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   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