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 CHAR8 AsciiFileName[MAX_NAME_LENGTH]; 308 BOOTMON_FS_FILE *SameFile; 309 310 // If the file path start with a \ strip it. The EFI Shell may 311 // insert a \ in front of the file name. 312 if (FileName[0] == L'\\') { 313 FileName++; 314 } 315 316 UnicodeStrToAsciiStrS (FileName, AsciiFileName, MAX_NAME_LENGTH); 317 318 if (BootMonGetFileFromAsciiFileName ( 319 File->Instance, 320 AsciiFileName, 321 &SameFile 322 ) != EFI_NOT_FOUND) { 323 // A file with that name already exists. 324 return EFI_ACCESS_DENIED; 325 } else { 326 // OK, change the filename. 327 AsciiStrToUnicodeStrS (AsciiFileName, File->Info->FileName, 328 (File->Info->Size - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16)); 329 return EFI_SUCCESS; 330 } 331 } 332 333 /** 334 Set the size of a file. 335 336 This is a helper function for SetFileInfo(). 337 338 @param[in] Instance A pointer to the description of the volume 339 the file belongs to. 340 @param[in] File A pointer to the description of the file. 341 @param[in] NewSize The requested new size for the file. 342 343 @retval EFI_SUCCESS The size was set. 344 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed. 345 346 **/ 347 STATIC 348 EFI_STATUS 349 SetFileSize ( 350 IN BOOTMON_FS_INSTANCE *Instance, 351 IN BOOTMON_FS_FILE *BootMonFsFile, 352 IN UINTN NewSize 353 ) 354 { 355 EFI_STATUS Status; 356 UINT32 OldSize; 357 LIST_ENTRY *RegionToFlushLink; 358 LIST_ENTRY *NextRegionToFlushLink; 359 BOOTMON_FS_FILE_REGION *Region; 360 EFI_FILE_PROTOCOL *File; 361 CHAR8 *Buffer; 362 UINTN BufferSize; 363 UINT64 StoredPosition; 364 365 OldSize = BootMonFsFile->Info->FileSize; 366 367 // 368 // In case of file truncation, force the regions waiting for writing to 369 // not overflow the new size of the file. 370 // 371 if (NewSize < OldSize) { 372 for (RegionToFlushLink = GetFirstNode (&BootMonFsFile->RegionToFlushLink); 373 !IsNull (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink); 374 ) 375 { 376 NextRegionToFlushLink = GetNextNode (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink); 377 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink; 378 if (Region->Offset > NewSize) { 379 RemoveEntryList (RegionToFlushLink); 380 FreePool (Region->Buffer); 381 FreePool (Region); 382 } else { 383 Region->Size = MIN (Region->Size, NewSize - Region->Offset); 384 } 385 RegionToFlushLink = NextRegionToFlushLink; 386 } 387 388 } else if (NewSize > OldSize) { 389 // Increasing a file's size is potentially complicated as it may require 390 // moving the image description on media. The simplest way to do it is to 391 // seek past the end of the file (which is valid in UEFI) and perform a 392 // Write. 393 File = &BootMonFsFile->File; 394 395 // Save position 396 Status = File->GetPosition (File, &StoredPosition); 397 if (EFI_ERROR (Status)) { 398 return Status; 399 } 400 // Set position at the end of the file 401 Status = File->SetPosition (File, OldSize); 402 if (EFI_ERROR (Status)) { 403 return Status; 404 } 405 406 BufferSize = NewSize - OldSize; 407 Buffer = AllocateZeroPool (BufferSize); 408 if (Buffer == NULL) { 409 return EFI_OUT_OF_RESOURCES; 410 } 411 412 Status = File->Write (File, &BufferSize, Buffer); 413 FreePool (Buffer); 414 if (EFI_ERROR (Status)) { 415 return Status; 416 } 417 418 // Restore saved position 419 Status = File->SetPosition (File, StoredPosition); 420 if (EFI_ERROR (Status)) { 421 return Status; 422 } 423 } 424 425 BootMonFsFile->Info->FileSize = NewSize; 426 427 return EFI_SUCCESS; 428 } 429 430 /** 431 Set information about a file. 432 433 @param[in] Instance A pointer to the description of the volume 434 the file belongs to. 435 @param[in] File A pointer to the description of the file. 436 @param[in] Info A pointer to the file information to write. 437 438 @retval EFI_SUCCESS The information was set. 439 @retval EFI_ACCESS_DENIED An attempt is being made to change the 440 EFI_FILE_DIRECTORY Attribute. 441 @retval EFI_ACCESS_DENIED The file was opened in read-only mode and an 442 attempt is being made to modify a field other 443 than Attribute. 444 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file 445 to a file that is already present. 446 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only 447 attribute. 448 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request 449 failed. 450 451 **/ 452 STATIC 453 EFI_STATUS 454 SetFileInfo ( 455 IN BOOTMON_FS_INSTANCE *Instance, 456 IN BOOTMON_FS_FILE *File, 457 IN EFI_FILE_INFO *Info 458 ) 459 { 460 EFI_STATUS Status; 461 BOOLEAN FileSizeIsDifferent; 462 BOOLEAN FileNameIsDifferent; 463 BOOLEAN TimeIsDifferent; 464 465 // 466 // A directory can not be changed to a file and a file can 467 // not be changed to a directory. 468 // 469 if ((Info->Attribute & EFI_FILE_DIRECTORY) != 470 (File->Info->Attribute & EFI_FILE_DIRECTORY) ) { 471 return EFI_ACCESS_DENIED; 472 } 473 474 FileSizeIsDifferent = (Info->FileSize != File->Info->FileSize); 475 FileNameIsDifferent = (StrnCmp ( 476 Info->FileName, 477 File->Info->FileName, 478 MAX_NAME_LENGTH - 1 479 ) != 0); 480 // 481 // Check if the CreateTime, LastAccess or ModificationTime 482 // have been changed. The file system does not support file 483 // timestamps thus the three times in "File->Info" are 484 // always equal to zero. The following comparison actually 485 // checks if all three times are still equal to 0 or not. 486 // 487 TimeIsDifferent = CompareMem ( 488 &Info->CreateTime, 489 &File->Info->CreateTime, 490 3 * sizeof (EFI_TIME) 491 ) != 0; 492 493 // 494 // For a file opened in read-only mode, only the Attribute field can be 495 // modified. The root directory open mode is forced to read-only at opening 496 // thus the following test protects the root directory to be somehow modified. 497 // 498 if (File->OpenMode == EFI_FILE_MODE_READ) { 499 if (FileSizeIsDifferent || FileNameIsDifferent || TimeIsDifferent) { 500 return EFI_ACCESS_DENIED; 501 } 502 } 503 504 if (TimeIsDifferent) { 505 return EFI_WRITE_PROTECTED; 506 } 507 508 if (FileSizeIsDifferent) { 509 Status = SetFileSize (Instance, File, Info->FileSize); 510 if (EFI_ERROR (Status)) { 511 return Status; 512 } 513 } 514 515 // 516 // Note down in RAM the Attribute field but we can not 517 // ask to store it in flash for the time being. 518 // 519 File->Info->Attribute = Info->Attribute; 520 521 if (FileNameIsDifferent) { 522 Status = SetFileName (Instance, File, Info->FileName); 523 if (EFI_ERROR (Status)) { 524 return Status; 525 } 526 } 527 528 return EFI_SUCCESS; 529 } 530 531 EFIAPI 532 EFI_STATUS 533 BootMonFsGetInfo ( 534 IN EFI_FILE_PROTOCOL *This, 535 IN EFI_GUID *InformationType, 536 IN OUT UINTN *BufferSize, 537 OUT VOID *Buffer 538 ) 539 { 540 EFI_STATUS Status; 541 BOOTMON_FS_FILE *File; 542 BOOTMON_FS_INSTANCE *Instance; 543 544 if ((This == NULL) || 545 (InformationType == NULL) || 546 (BufferSize == NULL) || 547 ((Buffer == NULL) && (*BufferSize > 0)) ) { 548 return EFI_INVALID_PARAMETER; 549 } 550 551 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 552 if (File->Info == NULL) { 553 return EFI_INVALID_PARAMETER; 554 } 555 Instance = File->Instance; 556 557 // If the instance has not been initialized yet then do it ... 558 if (!Instance->Initialized) { 559 Status = BootMonFsInitialize (Instance); 560 } else { 561 Status = EFI_SUCCESS; 562 } 563 564 if (!EFI_ERROR (Status)) { 565 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid) 566 != 0) { 567 Status = GetFileSystemVolumeLabelInfo (Instance, BufferSize, Buffer); 568 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) { 569 Status = GetFilesystemInfo (Instance, BufferSize, Buffer); 570 } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) { 571 Status = GetFileInfo (Instance, File, BufferSize, Buffer); 572 } else if (CompareGuid (InformationType, &gArmBootMonFsFileInfoGuid) != 0) { 573 Status = GetBootMonFsFileInfo (Instance, File, BufferSize, Buffer); 574 } else { 575 Status = EFI_UNSUPPORTED; 576 } 577 } 578 579 return Status; 580 } 581 582 /** 583 Set information about a file or a volume. 584 585 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that 586 is the file handle the information is for. 587 @param[in] InformationType The type identifier for the information being set : 588 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or 589 EFI_FILE_SYSTEM_VOLUME_LABEL_ID 590 @param[in] BufferSize The size, in bytes, of Buffer. 591 @param[in] Buffer A pointer to the data buffer to write. The type of the 592 data inside the buffer is indicated by InformationType. 593 594 @retval EFI_SUCCESS The information was set. 595 @retval EFI_UNSUPPORTED The InformationType is not known. 596 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed. 597 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file 598 to a file that is already present. 599 @retval EFI_ACCESS_DENIED An attempt is being made to change the 600 EFI_FILE_DIRECTORY Attribute. 601 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and 602 the file was opened in read-only mode and an 603 attempt is being made to modify a field other 604 than Attribute. 605 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only 606 attribute. 607 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by 608 the data inside the buffer. 609 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed. 610 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid. 611 612 **/ 613 EFIAPI 614 EFI_STATUS 615 BootMonFsSetInfo ( 616 IN EFI_FILE_PROTOCOL *This, 617 IN EFI_GUID *InformationType, 618 IN UINTN BufferSize, 619 IN VOID *Buffer 620 ) 621 { 622 BOOTMON_FS_FILE *File; 623 EFI_FILE_INFO *Info; 624 EFI_FILE_SYSTEM_INFO *SystemInfo; 625 626 if ((This == NULL) || 627 (InformationType == NULL) || 628 (Buffer == NULL) ) { 629 return EFI_INVALID_PARAMETER; 630 } 631 632 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 633 if (File->Info == NULL) { 634 return EFI_INVALID_PARAMETER; 635 } 636 637 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { 638 Info = Buffer; 639 if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) { 640 return EFI_INVALID_PARAMETER; 641 } 642 if (BufferSize < Info->Size) { 643 return EFI_BAD_BUFFER_SIZE; 644 } 645 return (SetFileInfo (File->Instance, File, Info)); 646 } 647 648 // 649 // The only writable field in the other two information types 650 // (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the 651 // filesystem volume label. This can be retrieved with GetInfo, but it is 652 // hard-coded into this driver, not stored on media. 653 // 654 655 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { 656 SystemInfo = Buffer; 657 if (SystemInfo->Size < 658 (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) { 659 return EFI_INVALID_PARAMETER; 660 } 661 if (BufferSize < SystemInfo->Size) { 662 return EFI_BAD_BUFFER_SIZE; 663 } 664 return EFI_WRITE_PROTECTED; 665 } 666 667 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { 668 return EFI_WRITE_PROTECTED; 669 } 670 671 return EFI_UNSUPPORTED; 672 } 673 674 EFIAPI 675 EFI_STATUS 676 BootMonFsReadDirectory ( 677 IN EFI_FILE_PROTOCOL *This, 678 IN OUT UINTN *BufferSize, 679 OUT VOID *Buffer 680 ) 681 { 682 BOOTMON_FS_INSTANCE *Instance; 683 BOOTMON_FS_FILE *RootFile; 684 BOOTMON_FS_FILE *File; 685 EFI_FILE_INFO *Info; 686 UINTN NameSize; 687 UINTN ResultSize; 688 EFI_STATUS Status; 689 UINTN Index; 690 691 RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 692 if (RootFile == NULL) { 693 return EFI_INVALID_PARAMETER; 694 } 695 696 Instance = RootFile->Instance; 697 Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File); 698 if (EFI_ERROR (Status)) { 699 // No more file 700 *BufferSize = 0; 701 return EFI_SUCCESS; 702 } 703 704 NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1; 705 ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16)); 706 if (*BufferSize < ResultSize) { 707 *BufferSize = ResultSize; 708 return EFI_BUFFER_TOO_SMALL; 709 } 710 711 // Zero out the structure 712 Info = Buffer; 713 ZeroMem (Info, ResultSize); 714 715 // Fill in the structure 716 Info->Size = ResultSize; 717 Info->FileSize = BootMonFsGetImageLength (File); 718 Info->PhysicalSize = BootMonFsGetPhysicalSize (File); 719 for (Index = 0; Index < NameSize; Index++) { 720 Info->FileName[Index] = File->HwDescription.Footer.Filename[Index]; 721 } 722 723 *BufferSize = ResultSize; 724 RootFile->Position++; 725 726 return EFI_SUCCESS; 727 } 728 729 EFIAPI 730 EFI_STATUS 731 BootMonFsFlushDirectory ( 732 IN EFI_FILE_PROTOCOL *This 733 ) 734 { 735 BOOTMON_FS_FILE *RootFile; 736 LIST_ENTRY *ListFiles; 737 LIST_ENTRY *Link; 738 BOOTMON_FS_FILE *File; 739 740 RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 741 if (RootFile == NULL) { 742 return EFI_INVALID_PARAMETER; 743 } 744 745 ListFiles = &RootFile->Link; 746 747 if (IsListEmpty (ListFiles)) { 748 return EFI_SUCCESS; 749 } 750 751 // 752 // Flush all the files that need to be flushed 753 // 754 755 // Go through all the list of files to flush them 756 for (Link = GetFirstNode (ListFiles); 757 !IsNull (ListFiles, Link); 758 Link = GetNextNode (ListFiles, Link) 759 ) 760 { 761 File = BOOTMON_FS_FILE_FROM_LINK_THIS (Link); 762 File->File.Flush (&File->File); 763 } 764 765 return EFI_SUCCESS; 766 } 767