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 = NULL;
    530     if (!IsListEmpty (&Instance->FileInfoHead)) {
    531       NewFile->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
    532     }
    533 
    534     *NewHandle = &NewFile->FileProtocol;
    535     return EFI_SUCCESS;
    536   }
    537 
    538   //
    539   // Do a linear search for a file in the FV with a matching filename
    540   //
    541   Status     = EFI_NOT_FOUND;
    542   FvFileInfo = NULL;
    543   for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead);
    544       !IsNull (&Instance->FileInfoHead, FvFileInfoLink);
    545        FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) {
    546     FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
    547     if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileName) == 0) {
    548       Status = EFI_SUCCESS;
    549       break;
    550     }
    551   }
    552 
    553   // If the file has not been found check if the filename exists with an extension
    554   // in case there was no extension present.
    555   // FvFileSystem adds a 'virtual' extension '.EFI' to EFI applications and drivers
    556   // present in the Firmware Volume
    557   if (Status == EFI_NOT_FOUND) {
    558     FileNameLength = StrLen (FileName);
    559 
    560     // Does the filename already contain the '.EFI' extension?
    561     if (mUnicodeCollation->StriColl (mUnicodeCollation, FileName + FileNameLength - 4, L".efi") != 0) {
    562       // No, there was no extension. So add one and search again for the file
    563       // NewFileNameLength = FileNameLength + 1 + 4 = (Number of non-null character) + (file extension) + (a null character)
    564       NewFileNameLength = FileNameLength + 1 + 4;
    565       FileNameWithExtension = AllocateCopyPool (NewFileNameLength * 2, FileName);
    566       StrCatS (FileNameWithExtension, NewFileNameLength, L".EFI");
    567 
    568       for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead);
    569           !IsNull (&Instance->FileInfoHead, FvFileInfoLink);
    570            FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) {
    571         FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
    572         if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileNameWithExtension) == 0) {
    573           Status = EFI_SUCCESS;
    574           break;
    575         }
    576       }
    577     }
    578   }
    579 
    580   if (!EFI_ERROR (Status)) {
    581     NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE));
    582     if (NewFile == NULL) {
    583       return EFI_OUT_OF_RESOURCES;
    584     }
    585 
    586     NewFile->Signature = FVFS_FILE_SIGNATURE;
    587     NewFile->Instance  = Instance;
    588     NewFile->FvFileInfo = FvFileInfo;
    589     CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate));
    590     InitializeListHead (&NewFile->Link);
    591     InsertHeadList (&Instance->FileHead, &NewFile->Link);
    592 
    593     *NewHandle = &NewFile->FileProtocol;
    594     return EFI_SUCCESS;
    595   }
    596 
    597   return EFI_NOT_FOUND;
    598 }
    599 
    600 /**
    601   Closes a specified file handle.
    602 
    603   @param  This          A pointer to the EFI_FILE_PROTOCOL instance that is the file
    604                         handle to close.
    605 
    606   @retval EFI_SUCCESS   The file was closed.
    607 
    608 **/
    609 EFI_STATUS
    610 EFIAPI
    611 FvSimpleFileSystemClose (
    612   IN EFI_FILE_PROTOCOL  *This
    613   )
    614 {
    615   FV_FILESYSTEM_INSTANCE      *Instance;
    616   FV_FILESYSTEM_FILE          *File;
    617 
    618   File = FVFS_FILE_FROM_FILE_THIS (This);
    619   Instance = File->Instance;
    620 
    621   if (File != Instance->Root) {
    622     RemoveEntryList (&File->Link);
    623     FreePool (File);
    624   }
    625   return EFI_SUCCESS;
    626 }
    627 
    628 /**
    629   Reads data from a file.
    630 
    631   @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
    632                      handle to read data from.
    633   @param  BufferSize On input, the size of the Buffer. On output, the amount of data
    634                      returned in Buffer. In both cases, the size is measured in bytes.
    635   @param  Buffer     The buffer into which the data is read.
    636 
    637   @retval EFI_SUCCESS          Data was read.
    638   @retval EFI_NO_MEDIA         The device has no medium.
    639   @retval EFI_DEVICE_ERROR     The device reported an error.
    640   @retval EFI_DEVICE_ERROR     An attempt was made to read from a deleted file.
    641   @retval EFI_DEVICE_ERROR     On entry, the current file position is beyond the end of the file.
    642   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    643   @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory
    644                                entry. BufferSize has been updated with the size
    645                                needed to complete the request.
    646 
    647 **/
    648 EFI_STATUS
    649 EFIAPI
    650 FvSimpleFileSystemRead (
    651   IN     EFI_FILE_PROTOCOL      *This,
    652   IN OUT UINTN                  *BufferSize,
    653      OUT VOID                   *Buffer
    654   )
    655 {
    656   FV_FILESYSTEM_INSTANCE        *Instance;
    657   FV_FILESYSTEM_FILE            *File;
    658   EFI_STATUS                    Status;
    659   LIST_ENTRY                    *FvFileInfoLink;
    660   VOID                          *FileBuffer;
    661   UINTN                         FileSize;
    662 
    663   File = FVFS_FILE_FROM_FILE_THIS (This);
    664   Instance = File->Instance;
    665 
    666   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
    667     if (File->DirReadNext) {
    668       //
    669       // Directory read: populate Buffer with an EFI_FILE_INFO
    670       //
    671       Status = FvFsGetFileInfo (File->DirReadNext, BufferSize, Buffer);
    672       if (!EFI_ERROR (Status)) {
    673         //
    674         // Successfully read a directory entry, now update the pointer to the
    675         // next file, which will be read on the next call to this function
    676         //
    677         FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, &File->DirReadNext->Link);
    678         if (IsNull (&Instance->FileInfoHead, FvFileInfoLink)) {
    679           //
    680           // No more files left
    681           //
    682           File->DirReadNext = NULL;
    683         } else {
    684           File->DirReadNext = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink);
    685         }
    686       }
    687       return Status;
    688     } else {
    689       //
    690       // Directory read. All entries have been read, so return a zero-size
    691       // buffer.
    692       //
    693       *BufferSize = 0;
    694       return EFI_SUCCESS;
    695     }
    696   } else {
    697     FileSize = (UINTN)File->FvFileInfo->FileInfo.FileSize;
    698 
    699     FileBuffer = AllocateZeroPool (FileSize);
    700     if (FileBuffer == NULL) {
    701       return EFI_DEVICE_ERROR;
    702     }
    703 
    704     Status = FvFsReadFile (File->Instance->FvProtocol, File->FvFileInfo, &FileSize, &FileBuffer);
    705     if (EFI_ERROR (Status)) {
    706       return EFI_DEVICE_ERROR;
    707     }
    708 
    709     if (*BufferSize + File->Position > FileSize) {
    710       *BufferSize = (UINTN)(FileSize - File->Position);
    711     }
    712 
    713     CopyMem (Buffer, (UINT8*)FileBuffer + File->Position, *BufferSize);
    714     File->Position += *BufferSize;
    715 
    716     return EFI_SUCCESS;
    717   }
    718 }
    719 
    720 /**
    721   Writes data to a file.
    722 
    723   @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
    724                      handle to write data to.
    725   @param  BufferSize On input, the size of the Buffer. On output, the amount of data
    726                      actually written. In both cases, the size is measured in bytes.
    727   @param  Buffer     The buffer of data to write.
    728 
    729   @retval EFI_SUCCESS          Data was written.
    730   @retval EFI_UNSUPPORTED      Writes to open directory files are not supported.
    731   @retval EFI_NO_MEDIA         The device has no medium.
    732   @retval EFI_DEVICE_ERROR     The device reported an error.
    733   @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.
    734   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    735   @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
    736   @retval EFI_ACCESS_DENIED    The file was opened read only.
    737   @retval EFI_VOLUME_FULL      The volume is full.
    738 
    739 **/
    740 EFI_STATUS
    741 EFIAPI
    742 FvSimpleFileSystemWrite (
    743   IN     EFI_FILE_PROTOCOL    *This,
    744   IN OUT UINTN                *BufferSize,
    745   IN     VOID                 *Buffer
    746   )
    747 {
    748   FV_FILESYSTEM_INSTANCE        *Instance;
    749   FV_FILESYSTEM_FILE            *File;
    750 
    751   File = FVFS_FILE_FROM_FILE_THIS (This);
    752   Instance = File->Instance;
    753 
    754   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
    755     return EFI_UNSUPPORTED;
    756   } else {
    757     return EFI_WRITE_PROTECTED;
    758   }
    759 }
    760 
    761 /**
    762   Returns a file's current position.
    763 
    764   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
    765                           handle to get the current position on.
    766   @param  Position        The address to return the file's current position value.
    767 
    768   @retval EFI_SUCCESS      The position was returned.
    769   @retval EFI_UNSUPPORTED  The request is not valid on open directories.
    770   @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file.
    771 
    772 **/
    773 EFI_STATUS
    774 EFIAPI
    775 FvSimpleFileSystemGetPosition (
    776   IN     EFI_FILE_PROTOCOL    *This,
    777      OUT UINT64               *Position
    778   )
    779 {
    780   FV_FILESYSTEM_INSTANCE        *Instance;
    781   FV_FILESYSTEM_FILE            *File;
    782 
    783   File = FVFS_FILE_FROM_FILE_THIS (This);
    784   Instance = File->Instance;
    785 
    786   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
    787     return EFI_UNSUPPORTED;
    788   } else {
    789     *Position = File->Position;
    790     return EFI_SUCCESS;
    791   }
    792 }
    793 
    794 /**
    795   Sets a file's current position.
    796 
    797   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the
    798                           file handle to set the requested position on.
    799   @param  Position        The byte position from the start of the file to set.
    800 
    801   @retval EFI_SUCCESS      The position was set.
    802   @retval EFI_UNSUPPORTED  The seek request for nonzero is not valid on open
    803                            directories.
    804   @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file.
    805 
    806 **/
    807 EFI_STATUS
    808 EFIAPI
    809 FvSimpleFileSystemSetPosition (
    810   IN EFI_FILE_PROTOCOL        *This,
    811   IN UINT64                   Position
    812   )
    813 {
    814   FV_FILESYSTEM_INSTANCE      *Instance;
    815   FV_FILESYSTEM_FILE          *File;
    816 
    817   File = FVFS_FILE_FROM_FILE_THIS (This);
    818   Instance = File->Instance;
    819 
    820   if (File->FvFileInfo == Instance->Root->FvFileInfo) {
    821     if (Position != 0) {
    822       return EFI_UNSUPPORTED;
    823     }
    824     //
    825     // Reset directory position to first entry
    826     //
    827     if (File->DirReadNext) {
    828       File->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance);
    829     }
    830   } else if (Position == 0xFFFFFFFFFFFFFFFFull) {
    831     File->Position = File->FvFileInfo->FileInfo.FileSize;
    832   } else {
    833     File->Position = Position;
    834   }
    835 
    836   return EFI_SUCCESS;
    837 }
    838 
    839 /**
    840   Flushes all modified data associated with a file to a device.
    841 
    842   @param  This A pointer to the EFI_FILE_PROTOCOL instance that is the file
    843                handle to flush.
    844 
    845   @retval EFI_SUCCESS          The data was flushed.
    846   @retval EFI_NO_MEDIA         The device has no medium.
    847   @retval EFI_DEVICE_ERROR     The device reported an error.
    848   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    849   @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
    850   @retval EFI_ACCESS_DENIED    The file was opened read-only.
    851   @retval EFI_VOLUME_FULL      The volume is full.
    852 
    853 **/
    854 EFI_STATUS
    855 EFIAPI
    856 FvSimpleFileSystemFlush (
    857   IN EFI_FILE_PROTOCOL  *This
    858   )
    859 {
    860   return EFI_WRITE_PROTECTED;
    861 }
    862 
    863 /**
    864   Close and delete the file handle.
    865 
    866   @param  This                     A pointer to the EFI_FILE_PROTOCOL instance that is the
    867                                    handle to the file to delete.
    868 
    869   @retval EFI_SUCCESS              The file was closed and deleted, and the handle was closed.
    870   @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not deleted.
    871 
    872 **/
    873 EFI_STATUS
    874 EFIAPI
    875 FvSimpleFileSystemDelete (
    876   IN EFI_FILE_PROTOCOL *This
    877   )
    878 {
    879   EFI_STATUS       Status;
    880 
    881   Status = FvSimpleFileSystemClose (This);
    882   ASSERT_EFI_ERROR (Status);
    883 
    884   return EFI_WARN_DELETE_FAILURE;
    885 }
    886 
    887 /**
    888   Returns information about a file.
    889 
    890   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
    891                           handle the requested information is for.
    892   @param  InformationType The type identifier for the information being requested.
    893   @param  BufferSize      On input, the size of Buffer. On output, the amount of data
    894                           returned in Buffer. In both cases, the size is measured in bytes.
    895   @param  Buffer          A pointer to the data buffer to return. The buffer's type is
    896                           indicated by InformationType.
    897 
    898   @retval EFI_SUCCESS          The information was returned.
    899   @retval EFI_UNSUPPORTED      The InformationType is not known.
    900   @retval EFI_NO_MEDIA         The device has no medium.
    901   @retval EFI_DEVICE_ERROR     The device reported an error.
    902   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    903   @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
    904                                BufferSize has been updated with the size needed to complete
    905                                the request.
    906 **/
    907 EFI_STATUS
    908 EFIAPI
    909 FvSimpleFileSystemGetInfo (
    910   IN     EFI_FILE_PROTOCOL    *This,
    911   IN     EFI_GUID             *InformationType,
    912   IN OUT UINTN                *BufferSize,
    913      OUT VOID                 *Buffer
    914   )
    915 {
    916   FV_FILESYSTEM_FILE           *File;
    917   EFI_FILE_SYSTEM_INFO         *FsInfoOut;
    918   EFI_FILE_SYSTEM_VOLUME_LABEL *FsVolumeLabel;
    919   FV_FILESYSTEM_INSTANCE       *Instance;
    920   UINTN                        Size;
    921   EFI_STATUS                   Status;
    922 
    923   File = FVFS_FILE_FROM_FILE_THIS (This);
    924 
    925   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
    926     //
    927     // Return filesystem info
    928     //
    929     Instance = File->Instance;
    930 
    931     Size = sizeof (EFI_FILE_SYSTEM_INFO) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);
    932 
    933     if (*BufferSize < Size) {
    934       *BufferSize = Size;
    935       return EFI_BUFFER_TOO_SMALL;
    936     }
    937 
    938     //
    939     // Cast output buffer for convenience
    940     //
    941     FsInfoOut = (EFI_FILE_SYSTEM_INFO *) Buffer;
    942 
    943     CopyMem (FsInfoOut, &mFsInfoTemplate, sizeof (EFI_FILE_SYSTEM_INFO));
    944     Status = StrnCpyS ( FsInfoOut->VolumeLabel,
    945                         (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)) / sizeof (CHAR16),
    946                         Instance->VolumeLabel,
    947                         StrLen (Instance->VolumeLabel)
    948                         );
    949     ASSERT_EFI_ERROR (Status);
    950     FsInfoOut->Size = Size;
    951     return Status;
    952   } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
    953     //
    954     // Return file info
    955     //
    956     return FvFsGetFileInfo (File->FvFileInfo, BufferSize, (EFI_FILE_INFO *) Buffer);
    957   } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
    958     //
    959     // Return Volume Label
    960     //
    961     Instance = File->Instance;
    962     Size     = sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);;
    963     if (*BufferSize < Size) {
    964       *BufferSize = Size;
    965       return EFI_BUFFER_TOO_SMALL;
    966     }
    967 
    968     FsVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL*) Buffer;
    969     Status        = StrnCpyS (FsVolumeLabel->VolumeLabel,
    970                               (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_VOLUME_LABEL, VolumeLabel)) / sizeof (CHAR16),
    971                               Instance->VolumeLabel,
    972                               StrLen (Instance->VolumeLabel)
    973                               );
    974     ASSERT_EFI_ERROR (Status);
    975     return Status;
    976   } else {
    977     return EFI_UNSUPPORTED;
    978   }
    979 }
    980 
    981 /**
    982   Sets information about a file.
    983 
    984   @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
    985                           handle the information is for.
    986   @param  InformationType The type identifier for the information being set.
    987   @param  BufferSize      The size, in bytes, of Buffer.
    988   @param  Buffer          A pointer to the data buffer to write. The buffer's type is
    989                           indicated by InformationType.
    990 
    991   @retval EFI_SUCCESS          The information was set.
    992   @retval EFI_UNSUPPORTED      The InformationType is not known.
    993   @retval EFI_NO_MEDIA         The device has no medium.
    994   @retval EFI_DEVICE_ERROR     The device reported an error.
    995   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
    996   @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_INFO_ID and the media is
    997                                read-only.
    998   @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_PROTOCOL_SYSTEM_INFO_ID
    999                                and the media is read only.
   1000   @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_SYSTEM_VOLUME_LABEL_ID
   1001                                and the media is read-only.
   1002   @retval EFI_ACCESS_DENIED    An attempt is made to change the name of a file to a
   1003                                file that is already present.
   1004   @retval EFI_ACCESS_DENIED    An attempt is being made to change the EFI_FILE_DIRECTORY
   1005                                Attribute.
   1006   @retval EFI_ACCESS_DENIED    An attempt is being made to change the size of a directory.
   1007   @retval EFI_ACCESS_DENIED    InformationType is EFI_FILE_INFO_ID and the file was opened
   1008                                read-only and an attempt is being made to modify a field
   1009                                other than Attribute.
   1010   @retval EFI_VOLUME_FULL      The volume is full.
   1011   @retval EFI_BAD_BUFFER_SIZE  BufferSize is smaller than the size of the type indicated
   1012                                by InformationType.
   1013 
   1014 **/
   1015 EFI_STATUS
   1016 EFIAPI
   1017 FvSimpleFileSystemSetInfo (
   1018   IN EFI_FILE_PROTOCOL        *This,
   1019   IN EFI_GUID                 *InformationType,
   1020   IN UINTN                    BufferSize,
   1021   IN VOID                     *Buffer
   1022   )
   1023 {
   1024   if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) ||
   1025       CompareGuid (InformationType, &gEfiFileInfoGuid) ||
   1026       CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
   1027     return EFI_WRITE_PROTECTED;
   1028   }
   1029 
   1030   return EFI_UNSUPPORTED;
   1031 }
   1032 
   1033