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