Home | History | Annotate | Download | only in FvSimpleFileSystemDxe
      1 /** @file
      2   This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware
      3   volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL.
      4 
      5   It will expose a single directory, containing one file for each file in the firmware
      6   volume. If a file has a UI section, its contents will be used as a filename.
      7   Otherwise, a string representation of the GUID will be used.
      8   Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION)
      9   will have ".efi" added to their filename.
     10 
     11   Its primary intended use is to be able to start EFI applications embedded in FVs
     12   from the UEFI shell. It is entirely read-only.
     13 
     14 Copyright (c) 2014, ARM Limited. All rights reserved.
     15 Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
     16 
     17 This program and the accompanying materials
     18 are licensed and made available under the terms and conditions of the BSD License
     19 which accompanies this distribution.  The full text of the license may be found at
     20 http://opensource.org/licenses/bsd-license.php
     21 
     22 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     23 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     24 
     25 **/
     26 
     27 #include "FvSimpleFileSystemInternal.h"
     28 
     29 //
     30 // Template for EFI_FILE_SYSTEM_INFO data structure.
     31 //
     32 EFI_FILE_SYSTEM_INFO mFsInfoTemplate = {
     33   0,    // Populate at runtime
     34   TRUE, // Read-only
     35   0,    // Don't know volume size
     36   0,    // No free space
     37   0,    // Don't know block size
     38   L""   // Populate at runtime
     39 };
     40 
     41 //
     42 // Template for EFI_FILE_PROTOCOL data structure.
     43 //
     44 EFI_FILE_PROTOCOL mFileSystemTemplate = {
     45   EFI_FILE_PROTOCOL_REVISION,
     46   FvSimpleFileSystemOpen,
     47   FvSimpleFileSystemClose,
     48   FvSimpleFileSystemDelete,
     49   FvSimpleFileSystemRead,
     50   FvSimpleFileSystemWrite,
     51   FvSimpleFileSystemGetPosition,
     52   FvSimpleFileSystemSetPosition,
     53   FvSimpleFileSystemGetInfo,
     54   FvSimpleFileSystemSetInfo,
     55   FvSimpleFileSystemFlush
     56 };
     57 
     58 /**
     59   Find and call ReadSection on the first section found of an executable type.
     60 
     61   @param  FvProtocol                  A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
     62   @param  FvFileInfo                  A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
     63                                       representing a file's info.
     64   @param  BufferSize                  Pointer to a caller-allocated UINTN. It indicates the size of
     65                                       the memory represented by *Buffer.
     66   @param  Buffer                      Pointer to a pointer to a data buffer to contain file content.
     67 
     68   @retval EFI_SUCCESS                 The call completed successfully.
     69   @retval EFI_WARN_BUFFER_TOO_SMALL   The buffer is too small to contain the requested output.
     70   @retval EFI_ACCESS_DENIED           The firmware volume is configured to disallow reads.
     71   @retval EFI_NOT_FOUND               The requested file was not found in the firmware volume.
     72   @retval EFI_DEVICE_ERROR            A hardware error occurred when attempting toaccess the firmware volume.
     73 
     74 **/
     75 EFI_STATUS
     76 FvFsFindExecutableSection (
     77   IN     EFI_FIRMWARE_VOLUME2_PROTOCOL     *FvProtocol,
     78   IN     FV_FILESYSTEM_FILE_INFO           *FvFileInfo,
     79   IN OUT UINTN                             *BufferSize,
     80   IN OUT VOID                              **Buffer
     81   )
     82 {
     83   EFI_SECTION_TYPE                    SectionType;
     84   UINT32                              AuthenticationStatus;
     85   EFI_STATUS                          Status;
     86 
     87   for (SectionType = EFI_SECTION_PE32; SectionType <= EFI_SECTION_TE; SectionType++) {
     88     Status = FvProtocol->ReadSection (
     89                            FvProtocol,
     90                            &FvFileInfo->NameGuid,
     91                            SectionType,
     92                            0,
     93                            Buffer,
     94                            BufferSize,
     95                            &AuthenticationStatus
     96                            );
     97     if (Status != EFI_NOT_FOUND) {
     98       return Status;
     99     }
    100   }
    101 
    102   return EFI_NOT_FOUND;
    103 }
    104 
    105 /**
    106   Get the size of the buffer that will be returned by FvFsReadFile.
    107 
    108   @param  FvProtocol                  A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
    109   @param  FvFileInfo                  A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
    110                                       representing a file's info.
    111 
    112   @retval EFI_SUCCESS                 The file size was gotten correctly.
    113   @retval Others                      The file size wasn't gotten correctly.
    114 
    115 **/
    116 EFI_STATUS
    117 FvFsGetFileSize (
    118   IN     EFI_FIRMWARE_VOLUME2_PROTOCOL     *FvProtocol,
    119   IN OUT FV_FILESYSTEM_FILE_INFO           *FvFileInfo
    120   )
    121 {
    122   UINT32                         AuthenticationStatus;
    123   EFI_FV_FILETYPE                FoundType;
    124   EFI_FV_FILE_ATTRIBUTES         Attributes;
    125   EFI_STATUS                     Status;
    126   UINT8                          IgnoredByte;
    127   VOID                           *IgnoredPtr;
    128 
    129   //
    130   // To get the size of a section, we pass 0 for BufferSize. But we can't pass
    131   // NULL for Buffer, as that will cause a return of INVALID_PARAMETER, and we
    132   // can't pass NULL for *Buffer, as that will cause the callee to allocate
    133   // a buffer of the sections size.
    134   //
    135   IgnoredPtr = &IgnoredByte;
    136   FvFileInfo->FileInfo.FileSize = 0;
    137 
    138   if (FV_FILETYPE_IS_EXECUTABLE (FvFileInfo->Type)) {
    139     //
    140     // Get the size of the first executable section out of the file.
    141     //
    142     Status = FvFsFindExecutableSection (FvProtocol, FvFileInfo, (UINTN*)&FvFileInfo->FileInfo.FileSize, &IgnoredPtr);
    143     if (Status == EFI_WARN_BUFFER_TOO_SMALL) {
    144       return EFI_SUCCESS;
    145     }
    146   } else if (FvFileInfo->Type == EFI_FV_FILETYPE_FREEFORM) {
    147     //
    148     // Try to get the size of a raw section out of the file
    149     //
    150     Status = FvProtocol->ReadSection (
    151                            FvProtocol,
    152                            &FvFileInfo->NameGuid,
    153                            EFI_SECTION_RAW,
    154                            0,
    155                            &IgnoredPtr,
    156                            (UINTN*)&FvFileInfo->FileInfo.FileSize,
    157                            &AuthenticationStatus
    158                            );
    159     if (Status == EFI_WARN_BUFFER_TOO_SMALL) {
    160       return EFI_SUCCESS;
    161     }
    162     if (EFI_ERROR (Status)) {
    163       //
    164       // Didn't find a raw section, just return the whole file's size.
    165       //
    166       return FvProtocol->ReadFile (
    167                            FvProtocol,
    168                            &FvFileInfo->NameGuid,
    169                            NULL,
    170                            (UINTN*)&FvFileInfo->FileInfo.FileSize,
    171                            &FoundType,
    172                            &Attributes,
    173                            &AuthenticationStatus
    174                            );
    175     }
    176   } else {
    177     //
    178     // Get the size of the entire file
    179     //
    180     return FvProtocol->ReadFile (
    181                          FvProtocol,
    182                          &FvFileInfo->NameGuid,
    183                          NULL,
    184                          (UINTN*)&FvFileInfo->FileInfo.FileSize,
    185                          &FoundType,
    186                          &Attributes,
    187                          &AuthenticationStatus
    188                          );
    189   }
    190 
    191   return Status;
    192 }
    193 
    194 /**
    195   Helper function to read a file.
    196 
    197   The data returned depends on the type of the underlying FV file:
    198   - For executable types, the first section found that contains executable code is returned.
    199   - For files of type FREEFORM, the driver attempts to return the first section of type RAW.
    200     If none is found, the entire contents of the FV file are returned.
    201   - On all other files the entire contents of the FV file is returned, as by
    202     EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadFile.
    203 
    204   @param  FvProtocol                  A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance.
    205   @param  FvFileInfo                  A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
    206                                       representing a file's info.
    207   @param  BufferSize                  Pointer to a caller-allocated UINTN. It indicates the size of
    208                                       the memory represented by *Buffer.
    209   @param  Buffer                      Pointer to a pointer to a data buffer to contain file content.
    210 
    211   @retval EFI_SUCCESS                 The call completed successfully.
    212   @retval EFI_WARN_BUFFER_TOO_SMALL   The buffer is too small to contain the requested output.
    213   @retval EFI_ACCESS_DENIED           The firmware volume is configured to disallow reads.
    214   @retval EFI_NOT_FOUND               The requested file was not found in the firmware volume.
    215   @retval EFI_DEVICE_ERROR            A hardware error occurred when attempting toaccess the firmware volume.
    216 
    217 **/
    218 EFI_STATUS
    219 FvFsReadFile (
    220   IN     EFI_FIRMWARE_VOLUME2_PROTOCOL     *FvProtocol,
    221   IN     FV_FILESYSTEM_FILE_INFO           *FvFileInfo,
    222   IN OUT UINTN                             *BufferSize,
    223   IN OUT VOID                              **Buffer
    224   )
    225 {
    226   UINT32                         AuthenticationStatus;
    227   EFI_FV_FILETYPE                FoundType;
    228   EFI_FV_FILE_ATTRIBUTES         Attributes;
    229   EFI_STATUS                     Status;
    230 
    231   if (FV_FILETYPE_IS_EXECUTABLE (FvFileInfo->Type)) {
    232     //
    233     // Read the first executable section out of the file.
    234     //
    235     Status = FvFsFindExecutableSection (FvProtocol, FvFileInfo, BufferSize, Buffer);
    236   } else if (FvFileInfo->Type == EFI_FV_FILETYPE_FREEFORM) {
    237     //
    238     // Try to read a raw section out of the file
    239     //
    240     Status = FvProtocol->ReadSection (
    241                            FvProtocol,
    242                            &FvFileInfo->NameGuid,
    243                            EFI_SECTION_RAW,
    244                            0,
    245                            Buffer,
    246                            BufferSize,
    247                            &AuthenticationStatus
    248                            );
    249     if (EFI_ERROR (Status)) {
    250       //
    251       // Didn't find a raw section, just return the whole file.
    252       //
    253       Status = FvProtocol->ReadFile (
    254                              FvProtocol,
    255                              &FvFileInfo->NameGuid,
    256                              Buffer,
    257                              BufferSize,
    258                              &FoundType,
    259                              &Attributes,
    260                              &AuthenticationStatus
    261                              );
    262     }
    263   } else {
    264     //
    265     // Read the entire file
    266     //
    267     Status = FvProtocol->ReadFile (
    268                            FvProtocol,
    269                            &FvFileInfo->NameGuid,
    270                            Buffer,
    271                            BufferSize,
    272                            &FoundType,
    273                            &Attributes,
    274                            &AuthenticationStatus
    275                            );
    276   }
    277 
    278   return Status;
    279 }
    280 
    281 /**
    282   Helper function for populating an EFI_FILE_INFO for a file.
    283 
    284   Note the CreateTime, LastAccessTime and ModificationTime fields in EFI_FILE_INFO
    285   are full zero as FV2 protocol has no corresponding info to fill.
    286 
    287   @param  FvFileInfo                  A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct
    288                                       representing a file's info.
    289   @param  BufferSize                  Pointer to a caller-allocated UINTN. It indicates the size of
    290                                       the memory represented by FileInfo.
    291   @param  FileInfo                    A pointer to EFI_FILE_INFO to contain the returned file info.
    292 
    293   @retval EFI_SUCCESS                 The call completed successfully.
    294   @retval EFI_BUFFER_TOO_SMALL        The buffer is too small to contain the requested output.
    295 
    296 **/
    297 EFI_STATUS
    298 FvFsGetFileInfo (
    299   IN     FV_FILESYSTEM_FILE_INFO           *FvFileInfo,
    300   IN OUT UINTN                             *BufferSize,
    301      OUT EFI_FILE_INFO                     *FileInfo
    302   )
    303 {
    304   UINTN                      InfoSize;
    305 
    306   InfoSize = (UINTN)FvFileInfo->FileInfo.Size;
    307   if (*BufferSize < InfoSize) {
    308     *BufferSize = InfoSize;
    309     return EFI_BUFFER_TOO_SMALL;
    310   }
    311 
    312   //
    313   // Initialize FileInfo
    314   //
    315   CopyMem (FileInfo, &FvFileInfo->FileInfo, InfoSize);
    316 
    317   *BufferSize = InfoSize;
    318   return EFI_SUCCESS;
    319 }
    320 
    321 /**
    322   Removes the last directory or file entry in a path by changing the last
    323   L'\' to a CHAR_NULL.
    324 
    325   @param  Path      The pointer to the path to modify.
    326 
    327   @retval FALSE     Nothing was found to remove.
    328   @retval TRUE      A directory or file was removed.
    329 
    330 **/
    331 BOOLEAN
    332 EFIAPI
    333 RemoveLastItemFromPath (
    334   IN OUT CHAR16 *Path
    335   )
    336 {
    337   CHAR16        *Walker;
    338   CHAR16        *LastSlash;
    339   //
    340   // get directory name from path... ('chop' off extra)
    341   //
    342   for ( Walker = Path, LastSlash = NULL
    343       ; Walker != NULL && *Walker != CHAR_NULL
    344       ; Walker++
    345      ){
    346     if (*Walker == L'\\' && *(Walker + 1) != CHAR_NULL) {
    347       LastSlash = Walker + 1;
    348     }
    349   }
    350 
    351   if (LastSlash != NULL) {
    352     *LastSlash = CHAR_NULL;
    353     return (TRUE);
    354   }
    355 
    356   return (FALSE);
    357 }
    358 
    359 /**
    360   Function to clean up paths.
    361 
    362   - Single periods in the path are removed.
    363   - Double periods in the path are removed along with a single parent directory.
    364   - Forward slashes L'/' are converted to backward slashes L'\'.
    365 
    366   This will be done inline and the existing buffer may be larger than required
    367   upon completion.
    368 
    369   @param  Path          The pointer to the string containing the path.
    370 
    371   @retval NULL          An error occured.
    372   @return Path in all other instances.
    373 
    374 **/
    375 CHAR16*
    376 EFIAPI
    377 TrimFilePathToAbsolutePath (
    378   IN CHAR16 *Path
    379   )
    380 {
    381   CHAR16  *TempString;
    382   UINTN   TempSize;
    383 
    384   if (Path == NULL) {
    385     return NULL;
    386   }
    387 
    388   //
    389   // Fix up the '/' vs '\'
    390   //
    391   for (TempString = Path ; (TempString != NULL) && (*TempString != CHAR_NULL); TempString++) {
    392     if (*TempString == L'/') {
    393       *TempString = L'\\';
    394     }
    395   }
    396 
    397   //
    398   // Fix up the ..
    399   //
    400   while ((TempString = StrStr (Path, L"\\..\\")) != NULL) {
    401     *TempString  = CHAR_NULL;
    402     TempString  += 4;
    403     RemoveLastItemFromPath (Path);
    404     TempSize     = StrSize (TempString);
    405     CopyMem (Path + StrLen (Path), TempString, TempSize);
    406   }
    407 
    408   if (((TempString = StrStr (Path, L"\\..")) != NULL) && (*(TempString + 3) == CHAR_NULL)) {
    409     *TempString  = CHAR_NULL;
    410     RemoveLastItemFromPath (Path);
    411   }
    412 
    413   //
    414   // Fix up the .
    415   //
    416   while ((TempString = StrStr (Path, L"\\.\\")) != NULL) {
    417     *TempString  = CHAR_NULL;
    418     TempString  += 2;
    419     TempSize     = StrSize (TempString);
    420     CopyMem(Path + StrLen (Path), TempString, TempSize);
    421   }
    422 
    423   if (((TempString = StrStr (Path, L"\\.")) != NULL) && (*(TempString + 2) == CHAR_NULL)) {
    424     *(TempString + 1) = CHAR_NULL;
    425   }
    426 
    427   while ((TempString = StrStr (Path, L"\\\\")) != NULL) {
    428     *TempString  = CHAR_NULL;
    429     TempString  += 1;
    430     TempSize     = StrSize(TempString);
    431     CopyMem(Path + StrLen(Path), TempString, TempSize);
    432   }
    433 
    434   if (((TempString = StrStr(Path, L"\\\\")) != NULL) && (*(TempString + 1) == CHAR_NULL)) {
    435     *(TempString) = CHAR_NULL;
    436   }
    437 
    438   return Path;
    439 }
    440 
    441 /**
    442   Opens a new file relative to the source file's location.
    443 
    444   @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
    445                      handle to the source location. This would typically be an open
    446                      handle to a directory.
    447   @param  NewHandle  A pointer to the location to return the opened handle for the new
    448                      file.
    449   @param  FileName   The Null-terminated string of the name of the file to be opened.
    450                      The file name may contain the following path modifiers: "\", ".",
    451                      and "..".
    452   @param  OpenMode   The mode to open the file. The only valid combinations that the
    453                      file may be opened with are: Read, Read/Write, or Create/Read/Write.
    454   @param  Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the
    455                      attribute bits for the newly created file.
    456 
    457   @retval EFI_SUCCESS          The file was opened.
    458   @retval EFI_NOT_FOUND        The specified file could not be found on the device.
    459   @retval EFI_NO_MEDIA         The device has no medium.
    460   @retval EFI_MEDIA_CHANGED    The device has a different medium in it or the medium is no
    461                                longer supported.
    462   @retval EFI_DEVICE_ERROR     The device reported an error.
    463   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    464   @retval EFI_WRITE_PROTECTED  An attempt was made to create a file, or open a file for write
    465                                when the media is write-protected.
    466   @retval EFI_ACCESS_DENIED    The service denied access to the file.
    467   @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
    468   @retval EFI_VOLUME_FULL      The volume is full.
    469 
    470 **/
    471 EFI_STATUS
    472 EFIAPI
    473 FvSimpleFileSystemOpen (
    474   IN     EFI_FILE_PROTOCOL    *This,
    475      OUT EFI_FILE_PROTOCOL    **NewHandle,
    476   IN     CHAR16               *FileName,
    477   IN     UINT64               OpenMode,
    478   IN     UINT64               Attributes
    479   )
    480 {
    481   FV_FILESYSTEM_INSTANCE      *Instance;
    482   FV_FILESYSTEM_FILE          *File;
    483   FV_FILESYSTEM_FILE          *NewFile;
    484   FV_FILESYSTEM_FILE_INFO     *FvFileInfo;
    485   LIST_ENTRY                  *FvFileInfoLink;
    486   EFI_STATUS                  Status;
    487   UINTN                       FileNameLength;
    488   UINTN                       NewFileNameLength;
    489   CHAR16                      *FileNameWithExtension;
    490 
    491   //
    492   // Check for a valid mode
    493   //
    494   switch (OpenMode) {
    495   case EFI_FILE_MODE_READ:
    496     break;
    497 
    498   default:
    499     return EFI_WRITE_PROTECTED;
    500   }
    501 
    502   File = FVFS_FILE_FROM_FILE_THIS (This);
    503   Instance = File->Instance;
    504 
    505   FileName = TrimFilePathToAbsolutePath (FileName);
    506   if (FileName == NULL) {
    507     return EFI_INVALID_PARAMETER;
    508   }
    509 
    510   if (FileName[0] == L'\\') {
    511     FileName++;
    512   }
    513 
    514   //
    515   // Check for opening root
    516   //
    517   if (StrCmp (FileName, L".") == 0 || StrCmp (FileName, L"") == 0) {
    518     NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE));
    519     if (NewFile == NULL) {
    520       return EFI_OUT_OF_RESOURCES;
    521     }
    522     NewFile->Signature = FVFS_FILE_SIGNATURE;
    523     NewFile->Instance  = Instance;
    524     NewFile->FvFileInfo = File->FvFileInfo;
    525     CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate));
    526     InitializeListHead (&NewFile->Link);
    527     InsertHeadList (&Instance->FileHead, &NewFile->Link);
    528 
    529     NewFile->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
    530 
    531     *NewHandle = &NewFile->FileProtocol;
    532     return EFI_SUCCESS;
    533   }
    534 
    535   //
    536   // Do a linear search for a file in the FV with a matching filename
    537   //
    538   Status     = EFI_NOT_FOUND;
    539   FvFileInfo = NULL;
    540   for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead);
    541       !IsNull (&Instance->FileInfoHead, FvFileInfoLink);
    542        FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) {
    543     FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
    544     if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileName) == 0) {
    545       Status = EFI_SUCCESS;
    546       break;
    547     }
    548   }
    549 
    550   // If the file has not been found check if the filename exists with an extension
    551   // in case there was no extension present.
    552   // FvFileSystem adds a 'virtual' extension '.EFI' to EFI applications and drivers
    553   // present in the Firmware Volume
    554   if (Status == EFI_NOT_FOUND) {
    555     FileNameLength = StrLen (FileName);
    556 
    557     // Does the filename already contain the '.EFI' extension?
    558     if (mUnicodeCollation->StriColl (mUnicodeCollation, FileName + FileNameLength - 4, L".efi") != 0) {
    559       // No, there was no extension. So add one and search again for the file
    560       // NewFileNameLength = FileNameLength + 1 + 4 = (Number of non-null character) + (file extension) + (a null character)
    561       NewFileNameLength = FileNameLength + 1 + 4;
    562       FileNameWithExtension = AllocateCopyPool (NewFileNameLength * 2, FileName);
    563       StrCatS (FileNameWithExtension, NewFileNameLength, L".EFI");
    564 
    565       for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead);
    566           !IsNull (&Instance->FileInfoHead, FvFileInfoLink);
    567            FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) {
    568         FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
    569         if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileNameWithExtension) == 0) {
    570           Status = EFI_SUCCESS;
    571           break;
    572         }
    573       }
    574     }
    575   }
    576 
    577   if (!EFI_ERROR (Status)) {
    578     NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE));
    579     if (NewFile == NULL) {
    580       return EFI_OUT_OF_RESOURCES;
    581     }
    582 
    583     NewFile->Signature = FVFS_FILE_SIGNATURE;
    584     NewFile->Instance  = Instance;
    585     NewFile->FvFileInfo = FvFileInfo;
    586     CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate));
    587     InitializeListHead (&NewFile->Link);
    588     InsertHeadList (&Instance->FileHead, &NewFile->Link);
    589 
    590     *NewHandle = &NewFile->FileProtocol;
    591     return EFI_SUCCESS;
    592   }
    593 
    594   return EFI_NOT_FOUND;
    595 }
    596 
    597 /**
    598   Closes a specified file handle.
    599 
    600   @param  This          A pointer to the EFI_FILE_PROTOCOL instance that is the file
    601                         handle to close.
    602 
    603   @retval EFI_SUCCESS   The file was closed.
    604 
    605 **/
    606 EFI_STATUS
    607 EFIAPI
    608 FvSimpleFileSystemClose (
    609   IN EFI_FILE_PROTOCOL  *This
    610   )
    611 {
    612   FV_FILESYSTEM_INSTANCE      *Instance;
    613   FV_FILESYSTEM_FILE          *File;
    614 
    615   File = FVFS_FILE_FROM_FILE_THIS (This);
    616   Instance = File->Instance;
    617 
    618   if (File != Instance->Root) {
    619     RemoveEntryList (&File->Link);
    620     FreePool (File);
    621   }
    622   return EFI_SUCCESS;
    623 }
    624 
    625 /**
    626   Reads data from a file.
    627 
    628   @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
    629                      handle to read data from.
    630   @param  BufferSize On input, the size of the Buffer. On output, the amount of data
    631                      returned in Buffer. In both cases, the size is measured in bytes.
    632   @param  Buffer     The buffer into which the data is read.
    633 
    634   @retval EFI_SUCCESS          Data was read.
    635   @retval EFI_NO_MEDIA         The device has no medium.
    636   @retval EFI_DEVICE_ERROR     The device reported an error.
    637   @retval EFI_DEVICE_ERROR     An attempt was made to read from a deleted file.
    638   @retval EFI_DEVICE_ERROR     On entry, the current file position is beyond the end of the file.
    639   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    640   @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory
    641                                entry. BufferSize has been updated with the size
    642                                needed to complete the request.
    643 
    644 **/
    645 EFI_STATUS
    646 EFIAPI
    647 FvSimpleFileSystemRead (
    648   IN     EFI_FILE_PROTOCOL      *This,
    649   IN OUT UINTN                  *BufferSize,
    650      OUT VOID                   *Buffer
    651   )
    652 {
    653   FV_FILESYSTEM_INSTANCE        *Instance;
    654   FV_FILESYSTEM_FILE            *File;
    655   EFI_STATUS                    Status;
    656   LIST_ENTRY                    *FvFileInfoLink;
    657   VOID                          *FileBuffer;
    658   UINTN                         FileSize;
    659 
    660   File = FVFS_FILE_FROM_FILE_THIS (This);
    661   Instance = File->Instance;
    662 
    663   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
    664     if (File->DirReadNext) {
    665       //
    666       // Directory read: populate Buffer with an EFI_FILE_INFO
    667       //
    668       Status = FvFsGetFileInfo (File->DirReadNext, BufferSize, Buffer);
    669       if (!EFI_ERROR (Status)) {
    670         //
    671         // Successfully read a directory entry, now update the pointer to the
    672         // next file, which will be read on the next call to this function
    673         //
    674         FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, &File->DirReadNext->Link);
    675         if (IsNull (&Instance->FileInfoHead, FvFileInfoLink)) {
    676           //
    677           // No more files left
    678           //
    679           File->DirReadNext = NULL;
    680         } else {
    681           File->DirReadNext = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
    682         }
    683       }
    684       return Status;
    685     } else {
    686       //
    687       // Directory read. All entries have been read, so return a zero-size
    688       // buffer.
    689       //
    690       *BufferSize = 0;
    691       return EFI_SUCCESS;
    692     }
    693   } else {
    694     FileSize = (UINTN)File->FvFileInfo->FileInfo.FileSize;
    695 
    696     FileBuffer = AllocateZeroPool (FileSize);
    697     if (FileBuffer == NULL) {
    698       return EFI_DEVICE_ERROR;
    699     }
    700 
    701     Status = FvFsReadFile (File->Instance->FvProtocol, File->FvFileInfo, &FileSize, &FileBuffer);
    702     if (EFI_ERROR (Status)) {
    703       return EFI_DEVICE_ERROR;
    704     }
    705 
    706     if (*BufferSize + File->Position > FileSize) {
    707       *BufferSize = (UINTN)(FileSize - File->Position);
    708     }
    709 
    710     CopyMem (Buffer, (UINT8*)FileBuffer + File->Position, *BufferSize);
    711     File->Position += *BufferSize;
    712 
    713     return EFI_SUCCESS;
    714   }
    715 }
    716 
    717 /**
    718   Writes data to a file.
    719 
    720   @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
    721                      handle to write data to.
    722   @param  BufferSize On input, the size of the Buffer. On output, the amount of data
    723                      actually written. In both cases, the size is measured in bytes.
    724   @param  Buffer     The buffer of data to write.
    725 
    726   @retval EFI_SUCCESS          Data was written.
    727   @retval EFI_UNSUPPORTED      Writes to open directory files are not supported.
    728   @retval EFI_NO_MEDIA         The device has no medium.
    729   @retval EFI_DEVICE_ERROR     The device reported an error.
    730   @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.
    731   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    732   @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
    733   @retval EFI_ACCESS_DENIED    The file was opened read only.
    734   @retval EFI_VOLUME_FULL      The volume is full.
    735 
    736 **/
    737 EFI_STATUS
    738 EFIAPI
    739 FvSimpleFileSystemWrite (
    740   IN     EFI_FILE_PROTOCOL    *This,
    741   IN OUT UINTN                *BufferSize,
    742   IN     VOID                 *Buffer
    743   )
    744 {
    745   FV_FILESYSTEM_INSTANCE        *Instance;
    746   FV_FILESYSTEM_FILE            *File;
    747 
    748   File = FVFS_FILE_FROM_FILE_THIS (This);
    749   Instance = File->Instance;
    750 
    751   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
    752     return EFI_UNSUPPORTED;
    753   } else {
    754     return EFI_WRITE_PROTECTED;
    755   }
    756 }
    757 
    758 /**
    759   Returns a file's current position.
    760 
    761   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
    762                           handle to get the current position on.
    763   @param  Position        The address to return the file's current position value.
    764 
    765   @retval EFI_SUCCESS      The position was returned.
    766   @retval EFI_UNSUPPORTED  The request is not valid on open directories.
    767   @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file.
    768 
    769 **/
    770 EFI_STATUS
    771 EFIAPI
    772 FvSimpleFileSystemGetPosition (
    773   IN     EFI_FILE_PROTOCOL    *This,
    774      OUT UINT64               *Position
    775   )
    776 {
    777   FV_FILESYSTEM_INSTANCE        *Instance;
    778   FV_FILESYSTEM_FILE            *File;
    779 
    780   File = FVFS_FILE_FROM_FILE_THIS (This);
    781   Instance = File->Instance;
    782 
    783   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
    784     return EFI_UNSUPPORTED;
    785   } else {
    786     *Position = File->Position;
    787     return EFI_SUCCESS;
    788   }
    789 }
    790 
    791 /**
    792   Sets a file's current position.
    793 
    794   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the
    795                           file handle to set the requested position on.
    796   @param  Position        The byte position from the start of the file to set.
    797 
    798   @retval EFI_SUCCESS      The position was set.
    799   @retval EFI_UNSUPPORTED  The seek request for nonzero is not valid on open
    800                            directories.
    801   @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file.
    802 
    803 **/
    804 EFI_STATUS
    805 EFIAPI
    806 FvSimpleFileSystemSetPosition (
    807   IN EFI_FILE_PROTOCOL        *This,
    808   IN UINT64                   Position
    809   )
    810 {
    811   FV_FILESYSTEM_INSTANCE      *Instance;
    812   FV_FILESYSTEM_FILE          *File;
    813 
    814   File = FVFS_FILE_FROM_FILE_THIS (This);
    815   Instance = File->Instance;
    816 
    817   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
    818     if (Position != 0) {
    819       return EFI_UNSUPPORTED;
    820     }
    821     //
    822     // Reset directory position to first entry
    823     //
    824     File->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
    825   } else if (Position == 0xFFFFFFFFFFFFFFFFull) {
    826     File->Position = File->FvFileInfo->FileInfo.FileSize;
    827   } else {
    828     File->Position = Position;
    829   }
    830 
    831   return EFI_SUCCESS;
    832 }
    833 
    834 /**
    835   Flushes all modified data associated with a file to a device.
    836 
    837   @param  This A pointer to the EFI_FILE_PROTOCOL instance that is the file
    838                handle to flush.
    839 
    840   @retval EFI_SUCCESS          The data was flushed.
    841   @retval EFI_NO_MEDIA         The device has no medium.
    842   @retval EFI_DEVICE_ERROR     The device reported an error.
    843   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    844   @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
    845   @retval EFI_ACCESS_DENIED    The file was opened read-only.
    846   @retval EFI_VOLUME_FULL      The volume is full.
    847 
    848 **/
    849 EFI_STATUS
    850 EFIAPI
    851 FvSimpleFileSystemFlush (
    852   IN EFI_FILE_PROTOCOL  *This
    853   )
    854 {
    855   return EFI_WRITE_PROTECTED;
    856 }
    857 
    858 /**
    859   Close and delete the file handle.
    860 
    861   @param  This                     A pointer to the EFI_FILE_PROTOCOL instance that is the
    862                                    handle to the file to delete.
    863 
    864   @retval EFI_SUCCESS              The file was closed and deleted, and the handle was closed.
    865   @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not deleted.
    866 
    867 **/
    868 EFI_STATUS
    869 EFIAPI
    870 FvSimpleFileSystemDelete (
    871   IN EFI_FILE_PROTOCOL *This
    872   )
    873 {
    874   EFI_STATUS       Status;
    875 
    876   Status = FvSimpleFileSystemClose (This);
    877   ASSERT_EFI_ERROR (Status);
    878 
    879   return EFI_WARN_DELETE_FAILURE;
    880 }
    881 
    882 /**
    883   Returns information about a file.
    884 
    885   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
    886                           handle the requested information is for.
    887   @param  InformationType The type identifier for the information being requested.
    888   @param  BufferSize      On input, the size of Buffer. On output, the amount of data
    889                           returned in Buffer. In both cases, the size is measured in bytes.
    890   @param  Buffer          A pointer to the data buffer to return. The buffer's type is
    891                           indicated by InformationType.
    892 
    893   @retval EFI_SUCCESS          The information was returned.
    894   @retval EFI_UNSUPPORTED      The InformationType is not known.
    895   @retval EFI_NO_MEDIA         The device has no medium.
    896   @retval EFI_DEVICE_ERROR     The device reported an error.
    897   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    898   @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
    899                                BufferSize has been updated with the size needed to complete
    900                                the request.
    901 **/
    902 EFI_STATUS
    903 EFIAPI
    904 FvSimpleFileSystemGetInfo (
    905   IN     EFI_FILE_PROTOCOL    *This,
    906   IN     EFI_GUID             *InformationType,
    907   IN OUT UINTN                *BufferSize,
    908      OUT VOID                 *Buffer
    909   )
    910 {
    911   FV_FILESYSTEM_FILE           *File;
    912   EFI_FILE_SYSTEM_INFO         *FsInfoOut;
    913   EFI_FILE_SYSTEM_VOLUME_LABEL *FsVolumeLabel;
    914   FV_FILESYSTEM_INSTANCE       *Instance;
    915   UINTN                        Size;
    916   EFI_STATUS                   Status;
    917 
    918   File = FVFS_FILE_FROM_FILE_THIS (This);
    919 
    920   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
    921     //
    922     // Return filesystem info
    923     //
    924     Instance = File->Instance;
    925 
    926     Size = sizeof (EFI_FILE_SYSTEM_INFO) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);
    927 
    928     if (*BufferSize < Size) {
    929       *BufferSize = Size;
    930       return EFI_BUFFER_TOO_SMALL;
    931     }
    932 
    933     //
    934     // Cast output buffer for convenience
    935     //
    936     FsInfoOut = (EFI_FILE_SYSTEM_INFO *) Buffer;
    937 
    938     CopyMem (FsInfoOut, &mFsInfoTemplate, sizeof (EFI_FILE_SYSTEM_INFO));
    939     Status = StrnCpyS ( FsInfoOut->VolumeLabel,
    940                         (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)) / sizeof (CHAR16),
    941                         Instance->VolumeLabel,
    942                         StrLen (Instance->VolumeLabel)
    943                         );
    944     ASSERT_EFI_ERROR (Status);
    945     FsInfoOut->Size = Size;
    946     return Status;
    947   } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
    948     //
    949     // Return file info
    950     //
    951     return FvFsGetFileInfo (File->FvFileInfo, BufferSize, (EFI_FILE_INFO *) Buffer);
    952   } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
    953     //
    954     // Return Volume Label
    955     //
    956     Instance = File->Instance;
    957     Size     = sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);;
    958     if (*BufferSize < Size) {
    959       *BufferSize = Size;
    960       return EFI_BUFFER_TOO_SMALL;
    961     }
    962 
    963     FsVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL*) Buffer;
    964     Status        = StrnCpyS (FsVolumeLabel->VolumeLabel,
    965                               (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_VOLUME_LABEL, VolumeLabel)) / sizeof (CHAR16),
    966                               Instance->VolumeLabel,
    967                               StrLen (Instance->VolumeLabel)
    968                               );
    969     ASSERT_EFI_ERROR (Status);
    970     return Status;
    971   } else {
    972     return EFI_UNSUPPORTED;
    973   }
    974 }
    975 
    976 /**
    977   Sets information about a file.
    978 
    979   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
    980                           handle the information is for.
    981   @param  InformationType The type identifier for the information being set.
    982   @param  BufferSize      The size, in bytes, of Buffer.
    983   @param  Buffer          A pointer to the data buffer to write. The buffer's type is
    984                           indicated by InformationType.
    985 
    986   @retval EFI_SUCCESS          The information was set.
    987   @retval EFI_UNSUPPORTED      The InformationType is not known.
    988   @retval EFI_NO_MEDIA         The device has no medium.
    989   @retval EFI_DEVICE_ERROR     The device reported an error.
    990   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    991   @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_INFO_ID and the media is
    992                                read-only.
    993   @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_PROTOCOL_SYSTEM_INFO_ID
    994                                and the media is read only.
    995   @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_SYSTEM_VOLUME_LABEL_ID
    996                                and the media is read-only.
    997   @retval EFI_ACCESS_DENIED    An attempt is made to change the name of a file to a
    998                                file that is already present.
    999   @retval EFI_ACCESS_DENIED    An attempt is being made to change the EFI_FILE_DIRECTORY
   1000                                Attribute.
   1001   @retval EFI_ACCESS_DENIED    An attempt is being made to change the size of a directory.
   1002   @retval EFI_ACCESS_DENIED    InformationType is EFI_FILE_INFO_ID and the file was opened
   1003                                read-only and an attempt is being made to modify a field
   1004                                other than Attribute.
   1005   @retval EFI_VOLUME_FULL      The volume is full.
   1006   @retval EFI_BAD_BUFFER_SIZE  BufferSize is smaller than the size of the type indicated
   1007                                by InformationType.
   1008 
   1009 **/
   1010 EFI_STATUS
   1011 EFIAPI
   1012 FvSimpleFileSystemSetInfo (
   1013   IN EFI_FILE_PROTOCOL        *This,
   1014   IN EFI_GUID                 *InformationType,
   1015   IN UINTN                    BufferSize,
   1016   IN VOID                     *Buffer
   1017   )
   1018 {
   1019   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) ||
   1020       CompareGuid (InformationType, &gEfiFileInfoGuid) ||
   1021       CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
   1022     return EFI_WRITE_PROTECTED;
   1023   }
   1024 
   1025   return EFI_UNSUPPORTED;
   1026 }
   1027 
   1028