1 /** @file 2 * 3 * Copyright (c) 2012-2014, 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 EFIAPI 18 EFI_STATUS 19 OpenBootMonFsOpenVolume ( 20 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, 21 OUT EFI_FILE_PROTOCOL **Root 22 ) 23 { 24 BOOTMON_FS_INSTANCE *Instance; 25 26 Instance = BOOTMON_FS_FROM_FS_THIS (This); 27 if (Instance == NULL) { 28 return EFI_DEVICE_ERROR; 29 } 30 31 Instance->RootFile->Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY; 32 33 *Root = &Instance->RootFile->File; 34 35 return EFI_SUCCESS; 36 } 37 38 UINT32 39 BootMonFsGetImageLength ( 40 IN BOOTMON_FS_FILE *File 41 ) 42 { 43 UINT32 Index; 44 UINT32 FileSize; 45 LIST_ENTRY *RegionToFlushLink; 46 BOOTMON_FS_FILE_REGION *Region; 47 48 FileSize = 0; 49 50 // Look at all Flash areas to determine file size 51 for (Index = 0; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) { 52 FileSize += File->HwDescription.Region[Index].Size; 53 } 54 55 // Add the regions that have not been flushed yet 56 for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); 57 !IsNull (&File->RegionToFlushLink, RegionToFlushLink); 58 RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink) 59 ) 60 { 61 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink; 62 if (Region->Offset + Region->Size > FileSize) { 63 FileSize += Region->Offset + Region->Size; 64 } 65 } 66 67 return FileSize; 68 } 69 70 UINTN 71 BootMonFsGetPhysicalSize ( 72 IN BOOTMON_FS_FILE* File 73 ) 74 { 75 // Return 0 for files that haven't yet been flushed to media 76 if (File->HwDescription.RegionCount == 0) { 77 return 0; 78 } 79 80 return ((File->HwDescription.BlockEnd - File->HwDescription.BlockStart) + 1 ) 81 * File->Instance->Media->BlockSize; 82 } 83 84 EFIAPI 85 EFI_STATUS 86 BootMonFsSetDirPosition ( 87 IN EFI_FILE_PROTOCOL *This, 88 IN UINT64 Position 89 ) 90 { 91 BOOTMON_FS_FILE *File; 92 93 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 94 if (File == NULL) { 95 return EFI_INVALID_PARAMETER; 96 } 97 98 // UEFI Spec section 12.5: 99 // "The seek request for nonzero is not valid on open directories." 100 if (Position != 0) { 101 return EFI_UNSUPPORTED; 102 } 103 File->Position = Position; 104 105 return EFI_SUCCESS; 106 } 107 108 EFI_STATUS 109 BootMonFsOpenDirectory ( 110 OUT EFI_FILE_PROTOCOL **NewHandle, 111 IN CHAR16 *FileName, 112 IN BOOTMON_FS_INSTANCE *Volume 113 ) 114 { 115 ASSERT(0); 116 117 return EFI_UNSUPPORTED; 118 } 119 120 STATIC 121 EFI_STATUS 122 GetFileSystemVolumeLabelInfo ( 123 IN BOOTMON_FS_INSTANCE *Instance, 124 IN OUT UINTN *BufferSize, 125 OUT VOID *Buffer 126 ) 127 { 128 UINTN Size; 129 EFI_FILE_SYSTEM_VOLUME_LABEL *Label; 130 EFI_STATUS Status; 131 132 Label = Buffer; 133 134 // Value returned by StrSize includes null terminator. 135 Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL 136 + StrSize (Instance->FsInfo.VolumeLabel); 137 138 if (*BufferSize >= Size) { 139 CopyMem (&Label->VolumeLabel, &Instance->FsInfo.VolumeLabel, Size); 140 Status = EFI_SUCCESS; 141 } else { 142 Status = EFI_BUFFER_TOO_SMALL; 143 } 144 *BufferSize = Size; 145 return Status; 146 } 147 148 // Helper function that calculates a rough "free space" by: 149 // - Taking the media size 150 // - Subtracting the sum of all file sizes 151 // - Subtracting the block size times the number of files 152 // (To account for the blocks containing the HW_IMAGE_INFO 153 STATIC 154 UINT64 155 ComputeFreeSpace ( 156 IN BOOTMON_FS_INSTANCE *Instance 157 ) 158 { 159 LIST_ENTRY *FileLink; 160 UINT64 FileSizeSum; 161 UINT64 MediaSize; 162 UINTN NumFiles; 163 EFI_BLOCK_IO_MEDIA *Media; 164 BOOTMON_FS_FILE *File; 165 166 Media = Instance->BlockIo->Media; 167 MediaSize = Media->BlockSize * (Media->LastBlock + 1); 168 169 NumFiles = 0; 170 FileSizeSum = 0; 171 for (FileLink = GetFirstNode (&Instance->RootFile->Link); 172 !IsNull (&Instance->RootFile->Link, FileLink); 173 FileLink = GetNextNode (&Instance->RootFile->Link, FileLink) 174 ) 175 { 176 File = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink); 177 FileSizeSum += BootMonFsGetImageLength (File); 178 179 NumFiles++; 180 } 181 182 return MediaSize - (FileSizeSum + (Media->BlockSize + NumFiles)); 183 } 184 185 STATIC 186 EFI_STATUS 187 GetFilesystemInfo ( 188 IN BOOTMON_FS_INSTANCE *Instance, 189 IN OUT UINTN *BufferSize, 190 OUT VOID *Buffer 191 ) 192 { 193 EFI_STATUS Status; 194 195 if (*BufferSize >= Instance->FsInfo.Size) { 196 Instance->FsInfo.FreeSpace = ComputeFreeSpace (Instance); 197 CopyMem (Buffer, &Instance->FsInfo, Instance->FsInfo.Size); 198 Status = EFI_SUCCESS; 199 } else { 200 Status = EFI_BUFFER_TOO_SMALL; 201 } 202 203 *BufferSize = Instance->FsInfo.Size; 204 return Status; 205 } 206 207 STATIC 208 EFI_STATUS 209 GetFileInfo ( 210 IN BOOTMON_FS_INSTANCE *Instance, 211 IN BOOTMON_FS_FILE *File, 212 IN OUT UINTN *BufferSize, 213 OUT VOID *Buffer 214 ) 215 { 216 EFI_FILE_INFO *Info; 217 UINTN ResultSize; 218 219 ResultSize = SIZE_OF_EFI_FILE_INFO + StrSize (File->Info->FileName); 220 221 if (*BufferSize < ResultSize) { 222 *BufferSize = ResultSize; 223 return EFI_BUFFER_TOO_SMALL; 224 } 225 226 Info = Buffer; 227 228 CopyMem (Info, File->Info, ResultSize); 229 // Size of the information 230 Info->Size = ResultSize; 231 232 *BufferSize = ResultSize; 233 234 return EFI_SUCCESS; 235 } 236 237 STATIC 238 EFI_STATUS 239 GetBootMonFsFileInfo ( 240 IN BOOTMON_FS_INSTANCE *Instance, 241 IN BOOTMON_FS_FILE *File, 242 IN OUT UINTN *BufferSize, 243 OUT VOID *Buffer 244 ) 245 { 246 EFI_STATUS Status; 247 BOOTMON_FS_FILE_INFO *Info; 248 UINTN ResultSize; 249 UINTN Index; 250 251 if (File == Instance->RootFile) { 252 Status = EFI_UNSUPPORTED; 253 } else { 254 ResultSize = SIZE_OF_BOOTMON_FS_FILE_INFO; 255 256 if (*BufferSize < ResultSize) { 257 *BufferSize = ResultSize; 258 Status = EFI_BUFFER_TOO_SMALL; 259 } else { 260 Info = Buffer; 261 262 // Zero out the structure 263 ZeroMem (Info, ResultSize); 264 265 // Fill in the structure 266 Info->Size = ResultSize; 267 268 Info->EntryPoint = File->HwDescription.EntryPoint; 269 Info->RegionCount = File->HwDescription.RegionCount; 270 for (Index = 0; Index < File->HwDescription.RegionCount; Index++) { 271 Info->Region[Index].LoadAddress = File->HwDescription.Region[Index].LoadAddress; 272 Info->Region[Index].Size = File->HwDescription.Region[Index].Size; 273 Info->Region[Index].Offset = File->HwDescription.Region[Index].Offset; 274 Info->Region[Index].Checksum = File->HwDescription.Region[Index].Checksum; 275 } 276 *BufferSize = ResultSize; 277 Status = EFI_SUCCESS; 278 } 279 } 280 281 return Status; 282 } 283 284 /** 285 Set the name of a file. 286 287 This is a helper function for SetFileInfo(). 288 289 @param[in] Instance A pointer to the description of the volume 290 the file belongs to. 291 @param[in] File A pointer to the description of the file. 292 @param[in] FileName A pointer to the new name of the file. 293 294 @retval EFI_SUCCESS The name was set. 295 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file 296 to a file that is already present. 297 298 **/ 299 STATIC 300 EFI_STATUS 301 SetFileName ( 302 IN BOOTMON_FS_INSTANCE *Instance, 303 IN BOOTMON_FS_FILE *File, 304 IN CONST CHAR16 *FileName 305 ) 306 { 307 CHAR16 TruncFileName[MAX_NAME_LENGTH]; 308 CHAR8 AsciiFileName[MAX_NAME_LENGTH]; 309 BOOTMON_FS_FILE *SameFile; 310 311 // If the file path start with a \ strip it. The EFI Shell may 312 // insert a \ in front of the file name. 313 if (FileName[0] == L'\\') { 314 FileName++; 315 } 316 317 StrnCpy (TruncFileName, FileName, MAX_NAME_LENGTH - 1); 318 TruncFileName[MAX_NAME_LENGTH - 1] = 0; 319 UnicodeStrToAsciiStr (TruncFileName, AsciiFileName); 320 321 if (BootMonGetFileFromAsciiFileName ( 322 File->Instance, 323 AsciiFileName, 324 &SameFile 325 ) != EFI_NOT_FOUND) { 326 // A file with that name already exists. 327 return EFI_ACCESS_DENIED; 328 } else { 329 // OK, change the filename. 330 AsciiStrToUnicodeStr (AsciiFileName, File->Info->FileName); 331 return EFI_SUCCESS; 332 } 333 } 334 335 /** 336 Set the size of a file. 337 338 This is a helper function for SetFileInfo(). 339 340 @param[in] Instance A pointer to the description of the volume 341 the file belongs to. 342 @param[in] File A pointer to the description of the file. 343 @param[in] NewSize The requested new size for the file. 344 345 @retval EFI_SUCCESS The size was set. 346 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed. 347 348 **/ 349 STATIC 350 EFI_STATUS 351 SetFileSize ( 352 IN BOOTMON_FS_INSTANCE *Instance, 353 IN BOOTMON_FS_FILE *BootMonFsFile, 354 IN UINTN NewSize 355 ) 356 { 357 EFI_STATUS Status; 358 UINT32 OldSize; 359 LIST_ENTRY *RegionToFlushLink; 360 LIST_ENTRY *NextRegionToFlushLink; 361 BOOTMON_FS_FILE_REGION *Region; 362 EFI_FILE_PROTOCOL *File; 363 CHAR8 *Buffer; 364 UINTN BufferSize; 365 UINT64 StoredPosition; 366 367 OldSize = BootMonFsFile->Info->FileSize; 368 369 // 370 // In case of file truncation, force the regions waiting for writing to 371 // not overflow the new size of the file. 372 // 373 if (NewSize < OldSize) { 374 for (RegionToFlushLink = GetFirstNode (&BootMonFsFile->RegionToFlushLink); 375 !IsNull (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink); 376 ) 377 { 378 NextRegionToFlushLink = GetNextNode (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink); 379 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink; 380 if (Region->Offset > NewSize) { 381 RemoveEntryList (RegionToFlushLink); 382 FreePool (Region->Buffer); 383 FreePool (Region); 384 } else { 385 Region->Size = MIN (Region->Size, NewSize - Region->Offset); 386 } 387 RegionToFlushLink = NextRegionToFlushLink; 388 } 389 390 } else if (NewSize > OldSize) { 391 // Increasing a file's size is potentially complicated as it may require 392 // moving the image description on media. The simplest way to do it is to 393 // seek past the end of the file (which is valid in UEFI) and perform a 394 // Write. 395 File = &BootMonFsFile->File; 396 397 // Save position 398 Status = File->GetPosition (File, &StoredPosition); 399 if (EFI_ERROR (Status)) { 400 return Status; 401 } 402 // Set position at the end of the file 403 Status = File->SetPosition (File, OldSize); 404 if (EFI_ERROR (Status)) { 405 return Status; 406 } 407 408 BufferSize = NewSize - OldSize; 409 Buffer = AllocateZeroPool (BufferSize); 410 if (Buffer == NULL) { 411 return EFI_OUT_OF_RESOURCES; 412 } 413 414 Status = File->Write (File, &BufferSize, Buffer); 415 FreePool (Buffer); 416 if (EFI_ERROR (Status)) { 417 return Status; 418 } 419 420 // Restore saved position 421 Status = File->SetPosition (File, StoredPosition); 422 if (EFI_ERROR (Status)) { 423 return Status; 424 } 425 } 426 427 BootMonFsFile->Info->FileSize = NewSize; 428 429 return EFI_SUCCESS; 430 } 431 432 /** 433 Set information about a file. 434 435 @param[in] Instance A pointer to the description of the volume 436 the file belongs to. 437 @param[in] File A pointer to the description of the file. 438 @param[in] Info A pointer to the file information to write. 439 440 @retval EFI_SUCCESS The information was set. 441 @retval EFI_ACCESS_DENIED An attempt is being made to change the 442 EFI_FILE_DIRECTORY Attribute. 443 @retval EFI_ACCESS_DENIED The file was opened in read-only mode and an 444 attempt is being made to modify a field other 445 than Attribute. 446 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file 447 to a file that is already present. 448 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only 449 attribute. 450 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request 451 failed. 452 453 **/ 454 STATIC 455 EFI_STATUS 456 SetFileInfo ( 457 IN BOOTMON_FS_INSTANCE *Instance, 458 IN BOOTMON_FS_FILE *File, 459 IN EFI_FILE_INFO *Info 460 ) 461 { 462 EFI_STATUS Status; 463 BOOLEAN FileSizeIsDifferent; 464 BOOLEAN FileNameIsDifferent; 465 BOOLEAN TimeIsDifferent; 466 467 // 468 // A directory can not be changed to a file and a file can 469 // not be changed to a directory. 470 // 471 if ((Info->Attribute & EFI_FILE_DIRECTORY) != 472 (File->Info->Attribute & EFI_FILE_DIRECTORY) ) { 473 return EFI_ACCESS_DENIED; 474 } 475 476 FileSizeIsDifferent = (Info->FileSize != File->Info->FileSize); 477 FileNameIsDifferent = (StrnCmp ( 478 Info->FileName, 479 File->Info->FileName, 480 MAX_NAME_LENGTH - 1 481 ) != 0); 482 // 483 // Check if the CreateTime, LastAccess or ModificationTime 484 // have been changed. The file system does not support file 485 // timestamps thus the three times in "File->Info" are 486 // always equal to zero. The following comparison actually 487 // checks if all three times are still equal to 0 or not. 488 // 489 TimeIsDifferent = CompareMem ( 490 &Info->CreateTime, 491 &File->Info->CreateTime, 492 3 * sizeof (EFI_TIME) 493 ) != 0; 494 495 // 496 // For a file opened in read-only mode, only the Attribute field can be 497 // modified. The root directory open mode is forced to read-only at opening 498 // thus the following test protects the root directory to be somehow modified. 499 // 500 if (File->OpenMode == EFI_FILE_MODE_READ) { 501 if (FileSizeIsDifferent || FileNameIsDifferent || TimeIsDifferent) { 502 return EFI_ACCESS_DENIED; 503 } 504 } 505 506 if (TimeIsDifferent) { 507 return EFI_WRITE_PROTECTED; 508 } 509 510 if (FileSizeIsDifferent) { 511 Status = SetFileSize (Instance, File, Info->FileSize); 512 if (EFI_ERROR (Status)) { 513 return Status; 514 } 515 } 516 517 // 518 // Note down in RAM the Attribute field but we can not 519 // ask to store it in flash for the time being. 520 // 521 File->Info->Attribute = Info->Attribute; 522 523 if (FileNameIsDifferent) { 524 Status = SetFileName (Instance, File, Info->FileName); 525 if (EFI_ERROR (Status)) { 526 return Status; 527 } 528 } 529 530 return EFI_SUCCESS; 531 } 532 533 EFIAPI 534 EFI_STATUS 535 BootMonFsGetInfo ( 536 IN EFI_FILE_PROTOCOL *This, 537 IN EFI_GUID *InformationType, 538 IN OUT UINTN *BufferSize, 539 OUT VOID *Buffer 540 ) 541 { 542 EFI_STATUS Status; 543 BOOTMON_FS_FILE *File; 544 BOOTMON_FS_INSTANCE *Instance; 545 546 if ((This == NULL) || 547 (InformationType == NULL) || 548 (BufferSize == NULL) || 549 ((Buffer == NULL) && (*BufferSize > 0)) ) { 550 return EFI_INVALID_PARAMETER; 551 } 552 553 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 554 if (File->Info == NULL) { 555 return EFI_INVALID_PARAMETER; 556 } 557 Instance = File->Instance; 558 559 // If the instance has not been initialized yet then do it ... 560 if (!Instance->Initialized) { 561 Status = BootMonFsInitialize (Instance); 562 } else { 563 Status = EFI_SUCCESS; 564 } 565 566 if (!EFI_ERROR (Status)) { 567 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid) 568 != 0) { 569 Status = GetFileSystemVolumeLabelInfo (Instance, BufferSize, Buffer); 570 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) { 571 Status = GetFilesystemInfo (Instance, BufferSize, Buffer); 572 } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) { 573 Status = GetFileInfo (Instance, File, BufferSize, Buffer); 574 } else if (CompareGuid (InformationType, &gArmBootMonFsFileInfoGuid) != 0) { 575 Status = GetBootMonFsFileInfo (Instance, File, BufferSize, Buffer); 576 } else { 577 Status = EFI_UNSUPPORTED; 578 } 579 } 580 581 return Status; 582 } 583 584 /** 585 Set information about a file or a volume. 586 587 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that 588 is the file handle the information is for. 589 @param[in] InformationType The type identifier for the information being set : 590 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or 591 EFI_FILE_SYSTEM_VOLUME_LABEL_ID 592 @param[in] BufferSize The size, in bytes, of Buffer. 593 @param[in] Buffer A pointer to the data buffer to write. The type of the 594 data inside the buffer is indicated by InformationType. 595 596 @retval EFI_SUCCESS The information was set. 597 @retval EFI_UNSUPPORTED The InformationType is not known. 598 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed. 599 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file 600 to a file that is already present. 601 @retval EFI_ACCESS_DENIED An attempt is being made to change the 602 EFI_FILE_DIRECTORY Attribute. 603 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and 604 the file was opened in read-only mode and an 605 attempt is being made to modify a field other 606 than Attribute. 607 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only 608 attribute. 609 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by 610 the data inside the buffer. 611 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed. 612 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid. 613 614 **/ 615 EFIAPI 616 EFI_STATUS 617 BootMonFsSetInfo ( 618 IN EFI_FILE_PROTOCOL *This, 619 IN EFI_GUID *InformationType, 620 IN UINTN BufferSize, 621 IN VOID *Buffer 622 ) 623 { 624 BOOTMON_FS_FILE *File; 625 EFI_FILE_INFO *Info; 626 EFI_FILE_SYSTEM_INFO *SystemInfo; 627 628 if ((This == NULL) || 629 (InformationType == NULL) || 630 (Buffer == NULL) ) { 631 return EFI_INVALID_PARAMETER; 632 } 633 634 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 635 if (File->Info == NULL) { 636 return EFI_INVALID_PARAMETER; 637 } 638 639 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { 640 Info = Buffer; 641 if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) { 642 return EFI_INVALID_PARAMETER; 643 } 644 if (BufferSize < Info->Size) { 645 return EFI_BAD_BUFFER_SIZE; 646 } 647 return (SetFileInfo (File->Instance, File, Info)); 648 } 649 650 // 651 // The only writable field in the other two information types 652 // (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the 653 // filesystem volume label. This can be retrieved with GetInfo, but it is 654 // hard-coded into this driver, not stored on media. 655 // 656 657 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { 658 SystemInfo = Buffer; 659 if (SystemInfo->Size < 660 (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) { 661 return EFI_INVALID_PARAMETER; 662 } 663 if (BufferSize < SystemInfo->Size) { 664 return EFI_BAD_BUFFER_SIZE; 665 } 666 return EFI_WRITE_PROTECTED; 667 } 668 669 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { 670 return EFI_WRITE_PROTECTED; 671 } 672 673 return EFI_UNSUPPORTED; 674 } 675 676 EFIAPI 677 EFI_STATUS 678 BootMonFsReadDirectory ( 679 IN EFI_FILE_PROTOCOL *This, 680 IN OUT UINTN *BufferSize, 681 OUT VOID *Buffer 682 ) 683 { 684 BOOTMON_FS_INSTANCE *Instance; 685 BOOTMON_FS_FILE *RootFile; 686 BOOTMON_FS_FILE *File; 687 EFI_FILE_INFO *Info; 688 UINTN NameSize; 689 UINTN ResultSize; 690 EFI_STATUS Status; 691 UINTN Index; 692 693 RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 694 if (RootFile == NULL) { 695 return EFI_INVALID_PARAMETER; 696 } 697 698 Instance = RootFile->Instance; 699 Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File); 700 if (EFI_ERROR (Status)) { 701 // No more file 702 *BufferSize = 0; 703 return EFI_SUCCESS; 704 } 705 706 NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1; 707 ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16)); 708 if (*BufferSize < ResultSize) { 709 *BufferSize = ResultSize; 710 return EFI_BUFFER_TOO_SMALL; 711 } 712 713 // Zero out the structure 714 Info = Buffer; 715 ZeroMem (Info, ResultSize); 716 717 // Fill in the structure 718 Info->Size = ResultSize; 719 Info->FileSize = BootMonFsGetImageLength (File); 720 Info->PhysicalSize = BootMonFsGetPhysicalSize (File); 721 for (Index = 0; Index < NameSize; Index++) { 722 Info->FileName[Index] = File->HwDescription.Footer.Filename[Index]; 723 } 724 725 *BufferSize = ResultSize; 726 RootFile->Position++; 727 728 return EFI_SUCCESS; 729 } 730 731 EFIAPI 732 EFI_STATUS 733 BootMonFsFlushDirectory ( 734 IN EFI_FILE_PROTOCOL *This 735 ) 736 { 737 BOOTMON_FS_FILE *RootFile; 738 LIST_ENTRY *ListFiles; 739 LIST_ENTRY *Link; 740 BOOTMON_FS_FILE *File; 741 742 RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 743 if (RootFile == NULL) { 744 return EFI_INVALID_PARAMETER; 745 } 746 747 ListFiles = &RootFile->Link; 748 749 if (IsListEmpty (ListFiles)) { 750 return EFI_SUCCESS; 751 } 752 753 // 754 // Flush all the files that need to be flushed 755 // 756 757 // Go through all the list of files to flush them 758 for (Link = GetFirstNode (ListFiles); 759 !IsNull (ListFiles, Link); 760 Link = GetNextNode (ListFiles, Link) 761 ) 762 { 763 File = BOOTMON_FS_FILE_FROM_LINK_THIS (Link); 764 File->File.Flush (&File->File); 765 } 766 767 return EFI_SUCCESS; 768 } 769