Home | History | Annotate | Download | only in BootMonFs
      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