]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
af2fe514f0440221d1ff710d58fe08b904ae8e58
[mirror_edk2.git] / ArmPlatformPkg / FileSystem / BootMonFs / BootMonFsOpenClose.c
1 /** @file
2 *
3 * Copyright (c) 2012-2015, ARM Limited. All rights reserved.
4 *
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
9 *
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 *
13 **/
14
15 #include "BootMonFsInternal.h"
16
17 // Clear a file's image description on storage media:
18 // UEFI allows you to seek past the end of a file, a subsequent write will grow
19 // the file. It does not specify how space between the former end of the file
20 // and the beginning of the write should be filled. It's therefore possible that
21 // BootMonFs metadata, that comes after the end of a file, could be left there
22 // and wrongly detected by BootMonFsImageInBlock.
23 STATIC
24 EFI_STATUS
25 InvalidateImageDescription (
26 IN BOOTMON_FS_FILE *File
27 )
28 {
29 EFI_DISK_IO_PROTOCOL *DiskIo;
30 EFI_BLOCK_IO_PROTOCOL *BlockIo;
31 UINT32 MediaId;
32 VOID *Buffer;
33 EFI_STATUS Status;
34
35 DiskIo = File->Instance->DiskIo;
36 BlockIo = File->Instance->BlockIo;
37 MediaId = BlockIo->Media->MediaId;
38
39 Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));
40
41 if (Buffer == NULL) {
42 return EFI_OUT_OF_RESOURCES;
43 }
44
45 Status = DiskIo->WriteDisk (DiskIo,
46 MediaId,
47 File->HwDescAddress,
48 sizeof (HW_IMAGE_DESCRIPTION),
49 Buffer
50 );
51
52 FreePool(Buffer);
53
54 return Status;
55 }
56
57 /**
58 Write the description of a file to storage media.
59
60 This function uses DiskIo to write to the media, so call BlockIo->FlushBlocks()
61 after calling it to ensure the data are written on the media.
62
63 @param[in] File Description of the file whose description on the
64 storage media has to be updated.
65 @param[in] FileName Name of the file. Its length is assumed to be
66 lower than MAX_NAME_LENGTH.
67 @param[in] DataSize Number of data bytes of the file.
68 @param[in] FileStart File's starting position on media. FileStart must
69 be aligned to the media's block size.
70
71 @retval EFI_WRITE_PROTECTED The device cannot be written to.
72 @retval EFI_DEVICE_ERROR The device reported an error while performing
73 the write operation.
74
75 **/
76 STATIC
77 EFI_STATUS
78 WriteFileDescription (
79 IN BOOTMON_FS_FILE *File,
80 IN CHAR8 *FileName,
81 IN UINT32 DataSize,
82 IN UINT64 FileStart
83 )
84 {
85 EFI_STATUS Status;
86 EFI_DISK_IO_PROTOCOL *DiskIo;
87 UINTN BlockSize;
88 UINT32 FileSize;
89 HW_IMAGE_DESCRIPTION *Description;
90
91 DiskIo = File->Instance->DiskIo;
92 BlockSize = File->Instance->BlockIo->Media->BlockSize;
93 ASSERT (FileStart % BlockSize == 0);
94
95 //
96 // Construct the file description
97 //
98
99 FileSize = DataSize + sizeof (HW_IMAGE_DESCRIPTION);
100 Description = &File->HwDescription;
101 Description->Attributes = 1;
102 Description->BlockStart = FileStart / BlockSize;
103 Description->BlockEnd = Description->BlockStart + (FileSize / BlockSize);
104 AsciiStrCpy (Description->Footer.Filename, FileName);
105
106 #ifdef MDE_CPU_ARM
107 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;
108 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION;
109 #else
110 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2;
111 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION2;
112 #endif
113 Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;
114 Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;
115 Description->RegionCount = 1;
116 Description->Region[0].Checksum = 0;
117 Description->Region[0].Offset = Description->BlockStart * BlockSize;
118 Description->Region[0].Size = DataSize;
119
120 Status = BootMonFsComputeFooterChecksum (Description);
121 if (EFI_ERROR (Status)) {
122 return Status;
123 }
124
125 File->HwDescAddress = ((Description->BlockEnd + 1) * BlockSize) - sizeof (HW_IMAGE_DESCRIPTION);
126
127 // Update the file description on the media
128 Status = DiskIo->WriteDisk (
129 DiskIo,
130 File->Instance->Media->MediaId,
131 File->HwDescAddress,
132 sizeof (HW_IMAGE_DESCRIPTION),
133 Description
134 );
135 ASSERT_EFI_ERROR (Status);
136
137 return Status;
138 }
139
140 // Find a space on media for a file that has not yet been flushed to disk.
141 // Just returns the first space that's big enough.
142 // This function could easily be adapted to:
143 // - Find space for moving an existing file that has outgrown its space
144 // (We do not currently move files, just return EFI_VOLUME_FULL)
145 // - Find space for a fragment of a file that has outgrown its space
146 // (We do not currently fragment files - it's not clear whether fragmentation
147 // is actually part of BootMonFs as there is no spec)
148 // - Be more clever about finding space (choosing the largest or smallest
149 // suitable space)
150 // Parameters:
151 // File - the new (not yet flushed) file for which we need to find space.
152 // FileStart - the position on media of the file (in bytes).
153 STATIC
154 EFI_STATUS
155 BootMonFsFindSpaceForNewFile (
156 IN BOOTMON_FS_FILE *File,
157 IN UINT64 FileSize,
158 OUT UINT64 *FileStart
159 )
160 {
161 LIST_ENTRY *FileLink;
162 BOOTMON_FS_FILE *RootFile;
163 BOOTMON_FS_FILE *FileEntry;
164 UINTN BlockSize;
165 EFI_BLOCK_IO_MEDIA *Media;
166
167 Media = File->Instance->BlockIo->Media;
168 BlockSize = Media->BlockSize;
169 RootFile = File->Instance->RootFile;
170
171 // This function must only be called for file which has not been flushed into
172 // Flash yet
173 ASSERT (File->HwDescription.RegionCount == 0);
174
175 *FileStart = 0;
176 // Go through all the files in the list
177 for (FileLink = GetFirstNode (&RootFile->Link);
178 !IsNull (&RootFile->Link, FileLink);
179 FileLink = GetNextNode (&RootFile->Link, FileLink)
180 )
181 {
182 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
183 // Skip files that aren't on disk yet
184 if (FileEntry->HwDescription.RegionCount == 0) {
185 continue;
186 }
187
188 // If the free space preceding the file is big enough to contain the new
189 // file then use it!
190 if (((FileEntry->HwDescription.BlockStart * BlockSize) - *FileStart)
191 >= FileSize) {
192 // The file list must be in disk-order
193 RemoveEntryList (&File->Link);
194 File->Link.BackLink = FileLink->BackLink;
195 File->Link.ForwardLink = FileLink;
196 FileLink->BackLink->ForwardLink = &File->Link;
197 FileLink->BackLink = &File->Link;
198
199 return EFI_SUCCESS;
200 } else {
201 *FileStart = (FileEntry->HwDescription.BlockEnd + 1) * BlockSize;
202 }
203 }
204 // See if there's space after the last file
205 if ((((Media->LastBlock + 1) * BlockSize) - *FileStart) >= FileSize) {
206 return EFI_SUCCESS;
207 } else {
208 return EFI_VOLUME_FULL;
209 }
210 }
211
212 // Free the resources in the file's Region list.
213 STATIC
214 VOID
215 FreeFileRegions (
216 IN BOOTMON_FS_FILE *File
217 )
218 {
219 LIST_ENTRY *RegionToFlushLink;
220 BOOTMON_FS_FILE_REGION *Region;
221
222 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
223 while (!IsNull (&File->RegionToFlushLink, RegionToFlushLink)) {
224 // Repeatedly remove the first node from the list and free its resources.
225 Region = (BOOTMON_FS_FILE_REGION *) RegionToFlushLink;
226 RemoveEntryList (RegionToFlushLink);
227 FreePool (Region->Buffer);
228 FreePool (Region);
229
230 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
231 }
232 }
233
234 /**
235 Flush all modified data associated with a file to a device.
236
237 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
238 file handle to flush.
239
240 @retval EFI_SUCCESS The data was flushed.
241 @retval EFI_ACCESS_DENIED The file was opened read-only.
242 @retval EFI_DEVICE_ERROR The device reported an error.
243 @retval EFI_VOLUME_FULL The volume is full.
244 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to flush the data.
245 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
246
247 **/
248 EFIAPI
249 EFI_STATUS
250 BootMonFsFlushFile (
251 IN EFI_FILE_PROTOCOL *This
252 )
253 {
254 EFI_STATUS Status;
255 BOOTMON_FS_INSTANCE *Instance;
256 EFI_FILE_INFO *Info;
257 EFI_BLOCK_IO_PROTOCOL *BlockIo;
258 EFI_BLOCK_IO_MEDIA *Media;
259 EFI_DISK_IO_PROTOCOL *DiskIo;
260 UINTN BlockSize;
261 CHAR8 AsciiFileName[MAX_NAME_LENGTH];
262 LIST_ENTRY *RegionToFlushLink;
263 BOOTMON_FS_FILE *File;
264 BOOTMON_FS_FILE *NextFile;
265 BOOTMON_FS_FILE_REGION *Region;
266 LIST_ENTRY *FileLink;
267 UINTN CurrentPhysicalSize;
268 UINT64 FileStart;
269 UINT64 FileEnd;
270 UINT64 RegionStart;
271 UINT64 RegionEnd;
272 UINT64 NewDataSize;
273 UINT64 NewFileSize;
274 UINT64 EndOfAppendSpace;
275 BOOLEAN HasSpace;
276
277 if (This == NULL) {
278 return EFI_INVALID_PARAMETER;
279 }
280
281 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
282 if (File->Info == NULL) {
283 return EFI_INVALID_PARAMETER;
284 }
285
286 if (File->OpenMode == EFI_FILE_MODE_READ) {
287 return EFI_ACCESS_DENIED;
288 }
289
290 Instance = File->Instance;
291 Info = File->Info;
292 BlockIo = Instance->BlockIo;
293 Media = BlockIo->Media;
294 DiskIo = Instance->DiskIo;
295 BlockSize = Media->BlockSize;
296
297 UnicodeStrToAsciiStr (Info->FileName, AsciiFileName);
298
299 // If the file doesn't exist then find a space for it
300 if (File->HwDescription.RegionCount == 0) {
301 Status = BootMonFsFindSpaceForNewFile (
302 File,
303 Info->FileSize + sizeof (HW_IMAGE_DESCRIPTION),
304 &FileStart
305 );
306 if (EFI_ERROR (Status)) {
307 return Status;
308 }
309 } else {
310 FileStart = File->HwDescription.BlockStart * BlockSize;
311 }
312 // FileEnd is the current NOR address of the end of the file's data
313 FileEnd = FileStart + File->HwDescription.Region[0].Size;
314
315 for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
316 !IsNull (&File->RegionToFlushLink, RegionToFlushLink);
317 RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)
318 )
319 {
320 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
321 if (Region->Size == 0) {
322 continue;
323 }
324
325 // RegionStart and RegionEnd are the the intended NOR address of the
326 // start and end of the region
327 RegionStart = FileStart + Region->Offset;
328 RegionEnd = RegionStart + Region->Size;
329
330 if (RegionEnd < FileEnd) {
331 // Handle regions representing edits to existing portions of the file
332 // Write the region data straight into the file
333 Status = DiskIo->WriteDisk (DiskIo,
334 Media->MediaId,
335 RegionStart,
336 Region->Size,
337 Region->Buffer
338 );
339 if (EFI_ERROR (Status)) {
340 return Status;
341 }
342 } else {
343 // Handle regions representing appends to the file
344 //
345 // Note: Since seeking past the end of the file with SetPosition() is
346 // valid, it's possible there will be a gap between the current end of
347 // the file and the beginning of the new region. Since the UEFI spec
348 // says nothing about this case (except "a subsequent write would grow
349 // the file"), we just leave garbage in the gap.
350
351 // Check if there is space to append the new region
352 HasSpace = FALSE;
353 NewDataSize = RegionEnd - FileStart;
354 NewFileSize = NewDataSize + sizeof (HW_IMAGE_DESCRIPTION);
355 CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);
356 if (NewFileSize <= CurrentPhysicalSize) {
357 HasSpace = TRUE;
358 } else {
359 // Get the File Description for the next file
360 FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link);
361 if (!IsNull (&Instance->RootFile->Link, FileLink)) {
362 NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
363
364 // If there is space between the beginning of the current file and the
365 // beginning of the next file then use it
366 EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;
367 } else {
368 // We are flushing the last file.
369 EndOfAppendSpace = (Media->LastBlock + 1) * BlockSize;
370 }
371 if (EndOfAppendSpace - FileStart >= NewFileSize) {
372 HasSpace = TRUE;
373 }
374 }
375
376 if (HasSpace == TRUE) {
377 // Invalidate the current image description of the file if any.
378 if (File->HwDescAddress != 0) {
379 Status = InvalidateImageDescription (File);
380 if (EFI_ERROR (Status)) {
381 return Status;
382 }
383 }
384
385 // Write the new file data
386 Status = DiskIo->WriteDisk (
387 DiskIo,
388 Media->MediaId,
389 RegionStart,
390 Region->Size,
391 Region->Buffer
392 );
393 if (EFI_ERROR (Status)) {
394 return Status;
395 }
396
397 Status = WriteFileDescription (File, AsciiFileName, NewDataSize, FileStart);
398 if (EFI_ERROR (Status)) {
399 return Status;
400 }
401
402 } else {
403 // There isn't a space for the file.
404 // Options here are to move the file or fragment it. However as files
405 // may represent boot images at fixed positions, these options will
406 // break booting if the bootloader doesn't use BootMonFs to find the
407 // image.
408
409 return EFI_VOLUME_FULL;
410 }
411 }
412 }
413
414 FreeFileRegions (File);
415 Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
416
417 if ((AsciiStrCmp (AsciiFileName, File->HwDescription.Footer.Filename) != 0) ||
418 (Info->FileSize != File->HwDescription.Region[0].Size) ) {
419 Status = WriteFileDescription (File, AsciiFileName, Info->FileSize, FileStart);
420 if (EFI_ERROR (Status)) {
421 return Status;
422 }
423 }
424
425 // Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by
426 // calling FlushBlocks on the same device's BlockIo).
427 BlockIo->FlushBlocks (BlockIo);
428
429 return EFI_SUCCESS;
430 }
431
432 /**
433 Close a specified file handle.
434
435 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
436 handle to close.
437
438 @retval EFI_SUCCESS The file was closed.
439 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open
440 file handle.
441
442 **/
443 EFIAPI
444 EFI_STATUS
445 BootMonFsCloseFile (
446 IN EFI_FILE_PROTOCOL *This
447 )
448 {
449 BOOTMON_FS_FILE *File;
450
451 if (This == NULL) {
452 return EFI_INVALID_PARAMETER;
453 }
454
455 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
456 if (File->Info == NULL) {
457 return EFI_INVALID_PARAMETER;
458 }
459
460 // In the case of a file and not the root directory
461 if (This != &File->Instance->RootFile->File) {
462 This->Flush (This);
463 FreePool (File->Info);
464 File->Info = NULL;
465 }
466
467 return EFI_SUCCESS;
468 }
469
470 /**
471 Open a file on the boot monitor file system.
472
473 The boot monitor file system does not allow for sub-directories. There is only
474 one directory, the root one. On any attempt to create a directory, the function
475 returns in error with the EFI_WRITE_PROTECTED error code.
476
477 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
478 the file handle to source location.
479 @param[out] NewHandle A pointer to the location to return the opened
480 handle for the new file.
481 @param[in] FileName The Null-terminated string of the name of the file
482 to be opened.
483 @param[in] OpenMode The mode to open the file : Read or Read/Write or
484 Read/Write/Create
485 @param[in] Attributes Attributes of the file in case of a file creation
486
487 @retval EFI_SUCCESS The file was open.
488 @retval EFI_NOT_FOUND The specified file could not be found or the specified
489 directory in which to create a file could not be found.
490 @retval EFI_DEVICE_ERROR The device reported an error.
491 @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible
492 with the Boot Monitor file system.
493 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
494 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
495
496 **/
497 EFIAPI
498 EFI_STATUS
499 BootMonFsOpenFile (
500 IN EFI_FILE_PROTOCOL *This,
501 OUT EFI_FILE_PROTOCOL **NewHandle,
502 IN CHAR16 *FileName,
503 IN UINT64 OpenMode,
504 IN UINT64 Attributes
505 )
506 {
507 EFI_STATUS Status;
508 BOOTMON_FS_FILE *Directory;
509 BOOTMON_FS_FILE *File;
510 BOOTMON_FS_INSTANCE *Instance;
511 CHAR8 *Buf;
512 CHAR16 *Path;
513 CHAR16 *Separator;
514 CHAR8 *AsciiFileName;
515 EFI_FILE_INFO *Info;
516
517 if (This == NULL) {
518 return EFI_INVALID_PARAMETER;
519 }
520
521 Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
522 if (Directory->Info == NULL) {
523 return EFI_INVALID_PARAMETER;
524 }
525
526 if ((FileName == NULL) || (NewHandle == NULL)) {
527 return EFI_INVALID_PARAMETER;
528 }
529
530 //
531 // The only valid modes are read, read/write, and read/write/create
532 //
533 if ( (OpenMode != EFI_FILE_MODE_READ) &&
534 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) &&
535 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) {
536 return EFI_INVALID_PARAMETER;
537 }
538
539 Instance = Directory->Instance;
540
541 //
542 // If the instance has not been initialized yet then do it ...
543 //
544 if (!Instance->Initialized) {
545 Status = BootMonFsInitialize (Instance);
546 if (EFI_ERROR (Status)) {
547 return Status;
548 }
549 }
550
551 //
552 // Copy the file path to be able to work on it. We do not want to
553 // modify the input file name string "FileName".
554 //
555 Buf = AllocateCopyPool (StrSize (FileName), FileName);
556 if (Buf == NULL) {
557 return EFI_OUT_OF_RESOURCES;
558 }
559 Path = (CHAR16*)Buf;
560 AsciiFileName = NULL;
561 Info = NULL;
562
563 //
564 // Handle single periods, double periods and convert forward slashes '/'
565 // to backward '\' ones. Does not handle a '.' at the beginning of the
566 // path for the time being.
567 //
568 if (PathCleanUpDirectories (Path) == NULL) {
569 Status = EFI_INVALID_PARAMETER;
570 goto Error;
571 }
572
573 //
574 // Detect if the first component of the path refers to a directory.
575 // This is done to return the correct error code when trying to
576 // access or create a directory other than the root directory.
577 //
578
579 //
580 // Search for the '\\' sequence and if found return in error
581 // with the EFI_INVALID_PARAMETER error code. ere in the path.
582 //
583 if (StrStr (Path, L"\\\\") != NULL) {
584 Status = EFI_INVALID_PARAMETER;
585 goto Error;
586 }
587 //
588 // Get rid of the leading '\' if any.
589 //
590 Path += (Path[0] == L'\\');
591
592 //
593 // Look for a '\' in the file path. If one is found then
594 // the first component of the path refers to a directory
595 // that is not the root directory.
596 //
597 Separator = StrStr (Path, L"\\");
598 if (Separator != NULL) {
599 //
600 // In the case '<dir name>\' and a creation, return
601 // EFI_WRITE_PROTECTED if this is for a directory
602 // creation, EFI_INVALID_PARAMETER otherwise.
603 //
604 if ((*(Separator + 1) == '\0') && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {
605 if (Attributes & EFI_FILE_DIRECTORY) {
606 Status = EFI_WRITE_PROTECTED;
607 } else {
608 Status = EFI_INVALID_PARAMETER;
609 }
610 } else {
611 //
612 // Attempt to open a file or a directory that is not in the
613 // root directory or to open without creation a directory
614 // located in the root directory, returns EFI_NOT_FOUND.
615 //
616 Status = EFI_NOT_FOUND;
617 }
618 goto Error;
619 }
620
621 //
622 // BootMonFs interface requires ASCII filenames
623 //
624 AsciiFileName = AllocatePool (StrLen (Path) + 1);
625 if (AsciiFileName == NULL) {
626 Status = EFI_OUT_OF_RESOURCES;
627 goto Error;
628 }
629 UnicodeStrToAsciiStr (Path, AsciiFileName);
630 if (AsciiStrSize (AsciiFileName) > MAX_NAME_LENGTH) {
631 AsciiFileName[MAX_NAME_LENGTH - 1] = '\0';
632 }
633
634 if ((AsciiFileName[0] == '\0') ||
635 (AsciiFileName[0] == '.' ) ) {
636 //
637 // Opening the root directory
638 //
639
640 *NewHandle = &Instance->RootFile->File;
641 Instance->RootFile->Position = 0;
642 Status = EFI_SUCCESS;
643 } else {
644
645 if ((OpenMode & EFI_FILE_MODE_CREATE) &&
646 (Attributes & EFI_FILE_DIRECTORY) ) {
647 Status = EFI_WRITE_PROTECTED;
648 goto Error;
649 }
650
651 //
652 // Allocate a buffer to store the characteristics of the file while the
653 // file is open. We allocate the maximum size to not have to reallocate
654 // if the file name is changed.
655 //
656 Info = AllocateZeroPool (
657 SIZE_OF_EFI_FILE_INFO + (sizeof (CHAR16) * MAX_NAME_LENGTH));
658 if (Info == NULL) {
659 Status = EFI_OUT_OF_RESOURCES;
660 goto Error;
661 }
662
663 //
664 // Open or create a file in the root directory.
665 //
666
667 Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File);
668 if (Status == EFI_NOT_FOUND) {
669 if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) {
670 goto Error;
671 }
672
673 Status = BootMonFsCreateFile (Instance, &File);
674 if (EFI_ERROR (Status)) {
675 goto Error;
676 }
677 InsertHeadList (&Instance->RootFile->Link, &File->Link);
678 Info->Attribute = Attributes;
679 } else {
680 //
681 // File already open, not supported yet.
682 //
683 if (File->Info != NULL) {
684 Status = EFI_UNSUPPORTED;
685 goto Error;
686 }
687 }
688
689 Info->FileSize = BootMonFsGetImageLength (File);
690 Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
691 AsciiStrToUnicodeStr (AsciiFileName, Info->FileName);
692
693 File->Info = Info;
694 Info = NULL;
695 File->Position = 0;
696 File->OpenMode = OpenMode;
697
698 *NewHandle = &File->File;
699 }
700
701 Error:
702
703 FreePool (Buf);
704 if (AsciiFileName != NULL) {
705 FreePool (AsciiFileName);
706 }
707 if (Info != NULL) {
708 FreePool (Info);
709 }
710
711 return Status;
712 }
713
714 // Delete() for the root directory's EFI_FILE_PROTOCOL instance
715 EFIAPI
716 EFI_STATUS
717 BootMonFsDeleteFail (
718 IN EFI_FILE_PROTOCOL *This
719 )
720 {
721 This->Close(This);
722 // You can't delete the root directory
723 return EFI_WARN_DELETE_FAILURE;
724 }
725
726 /**
727 Close and delete a file from the boot monitor file system.
728
729 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
730 handle to delete.
731
732 @retval EFI_SUCCESS The file was closed and deleted.
733 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open
734 file handle.
735 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
736
737 **/
738 EFIAPI
739 EFI_STATUS
740 BootMonFsDelete (
741 IN EFI_FILE_PROTOCOL *This
742 )
743 {
744 EFI_STATUS Status;
745 BOOTMON_FS_FILE *File;
746 LIST_ENTRY *RegionToFlushLink;
747 BOOTMON_FS_FILE_REGION *Region;
748
749 if (This == NULL) {
750 return EFI_INVALID_PARAMETER;
751 }
752
753 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
754 if (File->Info == NULL) {
755 return EFI_INVALID_PARAMETER;
756 }
757
758 if (!IsListEmpty (&File->RegionToFlushLink)) {
759 // Free the entries from the Buffer List
760 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
761 do {
762 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
763
764 //
765 // Get next element of the list before deleting the region description
766 // that contain the LIST_ENTRY structure.
767 //
768 RegionToFlushLink = RemoveEntryList (RegionToFlushLink);
769
770 // Free the buffers
771 FreePool (Region->Buffer);
772 FreePool (Region);
773 } while (!IsListEmpty (&File->RegionToFlushLink));
774 }
775
776 // If (RegionCount is greater than 0) then the file already exists
777 if (File->HwDescription.RegionCount > 0) {
778 // Invalidate the last Block
779 Status = InvalidateImageDescription (File);
780 ASSERT_EFI_ERROR (Status);
781 if (EFI_ERROR (Status)) {
782 return EFI_WARN_DELETE_FAILURE;
783 }
784 }
785
786 // Remove the entry from the list
787 RemoveEntryList (&File->Link);
788 FreePool (File->Info);
789 FreePool (File);
790
791 return EFI_SUCCESS;
792 }