| /** @file | |
| This driver uses the EFI_FIRMWARE_VOLUME2_PROTOCOL to expose files in firmware | |
| volumes via the the EFI_SIMPLE_FILESYSTEM_PROTOCOL and EFI_FILE_PROTOCOL. | |
| It will expose a single directory, containing one file for each file in the firmware | |
| volume. If a file has a UI section, its contents will be used as a filename. | |
| Otherwise, a string representation of the GUID will be used. | |
| Files of an executable type (That is PEIM, DRIVER, COMBINED_PEIM_DRIVER and APPLICATION) | |
| will have ".efi" added to their filename. | |
| Its primary intended use is to be able to start EFI applications embedded in FVs | |
| from the UEFI shell. It is entirely read-only. | |
| Copyright (c) 2014, ARM Limited. All rights reserved. | |
| Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "FvSimpleFileSystemInternal.h" | |
| // | |
| // Template for EFI_FILE_SYSTEM_INFO data structure. | |
| // | |
| EFI_FILE_SYSTEM_INFO mFsInfoTemplate = { | |
| 0, // Populate at runtime | |
| TRUE, // Read-only | |
| 0, // Don't know volume size | |
| 0, // No free space | |
| 0, // Don't know block size | |
| L"" // Populate at runtime | |
| }; | |
| // | |
| // Template for EFI_FILE_PROTOCOL data structure. | |
| // | |
| EFI_FILE_PROTOCOL mFileSystemTemplate = { | |
| EFI_FILE_PROTOCOL_REVISION, | |
| FvSimpleFileSystemOpen, | |
| FvSimpleFileSystemClose, | |
| FvSimpleFileSystemDelete, | |
| FvSimpleFileSystemRead, | |
| FvSimpleFileSystemWrite, | |
| FvSimpleFileSystemGetPosition, | |
| FvSimpleFileSystemSetPosition, | |
| FvSimpleFileSystemGetInfo, | |
| FvSimpleFileSystemSetInfo, | |
| FvSimpleFileSystemFlush | |
| }; | |
| /** | |
| Find and call ReadSection on the first section found of an executable type. | |
| @param FvProtocol A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance. | |
| @param FvFileInfo A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct | |
| representing a file's info. | |
| @param BufferSize Pointer to a caller-allocated UINTN. It indicates the size of | |
| the memory represented by *Buffer. | |
| @param Buffer Pointer to a pointer to a data buffer to contain file content. | |
| @retval EFI_SUCCESS The call completed successfully. | |
| @retval EFI_WARN_BUFFER_TOO_SMALL The buffer is too small to contain the requested output. | |
| @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads. | |
| @retval EFI_NOT_FOUND The requested file was not found in the firmware volume. | |
| @retval EFI_DEVICE_ERROR A hardware error occurred when attempting toaccess the firmware volume. | |
| **/ | |
| EFI_STATUS | |
| FvFsFindExecutableSection ( | |
| IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol, | |
| IN FV_FILESYSTEM_FILE_INFO *FvFileInfo, | |
| IN OUT UINTN *BufferSize, | |
| IN OUT VOID **Buffer | |
| ) | |
| { | |
| EFI_SECTION_TYPE SectionType; | |
| UINT32 AuthenticationStatus; | |
| EFI_STATUS Status; | |
| for (SectionType = EFI_SECTION_PE32; SectionType <= EFI_SECTION_TE; SectionType++) { | |
| Status = FvProtocol->ReadSection ( | |
| FvProtocol, | |
| &FvFileInfo->NameGuid, | |
| SectionType, | |
| 0, | |
| Buffer, | |
| BufferSize, | |
| &AuthenticationStatus | |
| ); | |
| if (Status != EFI_NOT_FOUND) { | |
| return Status; | |
| } | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Get the size of the buffer that will be returned by FvFsReadFile. | |
| @param FvProtocol A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance. | |
| @param FvFileInfo A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct | |
| representing a file's info. | |
| @retval EFI_SUCCESS The file size was gotten correctly. | |
| @retval Others The file size wasn't gotten correctly. | |
| **/ | |
| EFI_STATUS | |
| FvFsGetFileSize ( | |
| IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol, | |
| IN OUT FV_FILESYSTEM_FILE_INFO *FvFileInfo | |
| ) | |
| { | |
| UINT32 AuthenticationStatus; | |
| EFI_FV_FILETYPE FoundType; | |
| EFI_FV_FILE_ATTRIBUTES Attributes; | |
| EFI_STATUS Status; | |
| UINT8 IgnoredByte; | |
| VOID *IgnoredPtr; | |
| // | |
| // To get the size of a section, we pass 0 for BufferSize. But we can't pass | |
| // NULL for Buffer, as that will cause a return of INVALID_PARAMETER, and we | |
| // can't pass NULL for *Buffer, as that will cause the callee to allocate | |
| // a buffer of the sections size. | |
| // | |
| IgnoredPtr = &IgnoredByte; | |
| FvFileInfo->FileInfo.FileSize = 0; | |
| if (FV_FILETYPE_IS_EXECUTABLE (FvFileInfo->Type)) { | |
| // | |
| // Get the size of the first executable section out of the file. | |
| // | |
| Status = FvFsFindExecutableSection (FvProtocol, FvFileInfo, (UINTN*)&FvFileInfo->FileInfo.FileSize, &IgnoredPtr); | |
| if (Status == EFI_WARN_BUFFER_TOO_SMALL) { | |
| return EFI_SUCCESS; | |
| } | |
| } else if (FvFileInfo->Type == EFI_FV_FILETYPE_FREEFORM) { | |
| // | |
| // Try to get the size of a raw section out of the file | |
| // | |
| Status = FvProtocol->ReadSection ( | |
| FvProtocol, | |
| &FvFileInfo->NameGuid, | |
| EFI_SECTION_RAW, | |
| 0, | |
| &IgnoredPtr, | |
| (UINTN*)&FvFileInfo->FileInfo.FileSize, | |
| &AuthenticationStatus | |
| ); | |
| if (Status == EFI_WARN_BUFFER_TOO_SMALL) { | |
| return EFI_SUCCESS; | |
| } | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Didn't find a raw section, just return the whole file's size. | |
| // | |
| return FvProtocol->ReadFile ( | |
| FvProtocol, | |
| &FvFileInfo->NameGuid, | |
| NULL, | |
| (UINTN*)&FvFileInfo->FileInfo.FileSize, | |
| &FoundType, | |
| &Attributes, | |
| &AuthenticationStatus | |
| ); | |
| } | |
| } else { | |
| // | |
| // Get the size of the entire file | |
| // | |
| return FvProtocol->ReadFile ( | |
| FvProtocol, | |
| &FvFileInfo->NameGuid, | |
| NULL, | |
| (UINTN*)&FvFileInfo->FileInfo.FileSize, | |
| &FoundType, | |
| &Attributes, | |
| &AuthenticationStatus | |
| ); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Helper function to read a file. | |
| The data returned depends on the type of the underlying FV file: | |
| - For executable types, the first section found that contains executable code is returned. | |
| - For files of type FREEFORM, the driver attempts to return the first section of type RAW. | |
| If none is found, the entire contents of the FV file are returned. | |
| - On all other files the entire contents of the FV file is returned, as by | |
| EFI_FIRMWARE_VOLUME2_PROTOCOL.ReadFile. | |
| @param FvProtocol A pointer to the EFI_FIRMWARE_VOLUME2_PROTOCOL instance. | |
| @param FvFileInfo A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct | |
| representing a file's info. | |
| @param BufferSize Pointer to a caller-allocated UINTN. It indicates the size of | |
| the memory represented by *Buffer. | |
| @param Buffer Pointer to a pointer to a data buffer to contain file content. | |
| @retval EFI_SUCCESS The call completed successfully. | |
| @retval EFI_WARN_BUFFER_TOO_SMALL The buffer is too small to contain the requested output. | |
| @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads. | |
| @retval EFI_NOT_FOUND The requested file was not found in the firmware volume. | |
| @retval EFI_DEVICE_ERROR A hardware error occurred when attempting toaccess the firmware volume. | |
| **/ | |
| EFI_STATUS | |
| FvFsReadFile ( | |
| IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol, | |
| IN FV_FILESYSTEM_FILE_INFO *FvFileInfo, | |
| IN OUT UINTN *BufferSize, | |
| IN OUT VOID **Buffer | |
| ) | |
| { | |
| UINT32 AuthenticationStatus; | |
| EFI_FV_FILETYPE FoundType; | |
| EFI_FV_FILE_ATTRIBUTES Attributes; | |
| EFI_STATUS Status; | |
| if (FV_FILETYPE_IS_EXECUTABLE (FvFileInfo->Type)) { | |
| // | |
| // Read the first executable section out of the file. | |
| // | |
| Status = FvFsFindExecutableSection (FvProtocol, FvFileInfo, BufferSize, Buffer); | |
| } else if (FvFileInfo->Type == EFI_FV_FILETYPE_FREEFORM) { | |
| // | |
| // Try to read a raw section out of the file | |
| // | |
| Status = FvProtocol->ReadSection ( | |
| FvProtocol, | |
| &FvFileInfo->NameGuid, | |
| EFI_SECTION_RAW, | |
| 0, | |
| Buffer, | |
| BufferSize, | |
| &AuthenticationStatus | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // Didn't find a raw section, just return the whole file. | |
| // | |
| Status = FvProtocol->ReadFile ( | |
| FvProtocol, | |
| &FvFileInfo->NameGuid, | |
| Buffer, | |
| BufferSize, | |
| &FoundType, | |
| &Attributes, | |
| &AuthenticationStatus | |
| ); | |
| } | |
| } else { | |
| // | |
| // Read the entire file | |
| // | |
| Status = FvProtocol->ReadFile ( | |
| FvProtocol, | |
| &FvFileInfo->NameGuid, | |
| Buffer, | |
| BufferSize, | |
| &FoundType, | |
| &Attributes, | |
| &AuthenticationStatus | |
| ); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Helper function for populating an EFI_FILE_INFO for a file. | |
| Note the CreateTime, LastAccessTime and ModificationTime fields in EFI_FILE_INFO | |
| are full zero as FV2 protocol has no corresponding info to fill. | |
| @param FvFileInfo A pointer to the FV_FILESYSTEM_FILE_INFO instance that is a struct | |
| representing a file's info. | |
| @param BufferSize Pointer to a caller-allocated UINTN. It indicates the size of | |
| the memory represented by FileInfo. | |
| @param FileInfo A pointer to EFI_FILE_INFO to contain the returned file info. | |
| @retval EFI_SUCCESS The call completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL The buffer is too small to contain the requested output. | |
| **/ | |
| EFI_STATUS | |
| FvFsGetFileInfo ( | |
| IN FV_FILESYSTEM_FILE_INFO *FvFileInfo, | |
| IN OUT UINTN *BufferSize, | |
| OUT EFI_FILE_INFO *FileInfo | |
| ) | |
| { | |
| UINTN InfoSize; | |
| InfoSize = (UINTN)FvFileInfo->FileInfo.Size; | |
| if (*BufferSize < InfoSize) { | |
| *BufferSize = InfoSize; | |
| return EFI_BUFFER_TOO_SMALL; | |
| } | |
| // | |
| // Initialize FileInfo | |
| // | |
| CopyMem (FileInfo, &FvFileInfo->FileInfo, InfoSize); | |
| *BufferSize = InfoSize; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Removes the last directory or file entry in a path by changing the last | |
| L'\' to a CHAR_NULL. | |
| @param Path The pointer to the path to modify. | |
| @retval FALSE Nothing was found to remove. | |
| @retval TRUE A directory or file was removed. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| RemoveLastItemFromPath ( | |
| IN OUT CHAR16 *Path | |
| ) | |
| { | |
| CHAR16 *Walker; | |
| CHAR16 *LastSlash; | |
| // | |
| // get directory name from path... ('chop' off extra) | |
| // | |
| for ( Walker = Path, LastSlash = NULL | |
| ; Walker != NULL && *Walker != CHAR_NULL | |
| ; Walker++ | |
| ){ | |
| if (*Walker == L'\\' && *(Walker + 1) != CHAR_NULL) { | |
| LastSlash = Walker + 1; | |
| } | |
| } | |
| if (LastSlash != NULL) { | |
| *LastSlash = CHAR_NULL; | |
| return (TRUE); | |
| } | |
| return (FALSE); | |
| } | |
| /** | |
| Function to clean up paths. | |
| - Single periods in the path are removed. | |
| - Double periods in the path are removed along with a single parent directory. | |
| - Forward slashes L'/' are converted to backward slashes L'\'. | |
| This will be done inline and the existing buffer may be larger than required | |
| upon completion. | |
| @param Path The pointer to the string containing the path. | |
| @retval NULL An error occured. | |
| @return Path in all other instances. | |
| **/ | |
| CHAR16* | |
| EFIAPI | |
| TrimFilePathToAbsolutePath ( | |
| IN CHAR16 *Path | |
| ) | |
| { | |
| CHAR16 *TempString; | |
| UINTN TempSize; | |
| if (Path == NULL) { | |
| return NULL; | |
| } | |
| // | |
| // Fix up the '/' vs '\' | |
| // | |
| for (TempString = Path ; (TempString != NULL) && (*TempString != CHAR_NULL); TempString++) { | |
| if (*TempString == L'/') { | |
| *TempString = L'\\'; | |
| } | |
| } | |
| // | |
| // Fix up the .. | |
| // | |
| while ((TempString = StrStr (Path, L"\\..\\")) != NULL) { | |
| *TempString = CHAR_NULL; | |
| TempString += 4; | |
| RemoveLastItemFromPath (Path); | |
| TempSize = StrSize (TempString); | |
| CopyMem (Path + StrLen (Path), TempString, TempSize); | |
| } | |
| if (((TempString = StrStr (Path, L"\\..")) != NULL) && (*(TempString + 3) == CHAR_NULL)) { | |
| *TempString = CHAR_NULL; | |
| RemoveLastItemFromPath (Path); | |
| } | |
| // | |
| // Fix up the . | |
| // | |
| while ((TempString = StrStr (Path, L"\\.\\")) != NULL) { | |
| *TempString = CHAR_NULL; | |
| TempString += 2; | |
| TempSize = StrSize (TempString); | |
| CopyMem(Path + StrLen (Path), TempString, TempSize); | |
| } | |
| if (((TempString = StrStr (Path, L"\\.")) != NULL) && (*(TempString + 2) == CHAR_NULL)) { | |
| *(TempString + 1) = CHAR_NULL; | |
| } | |
| while ((TempString = StrStr (Path, L"\\\\")) != NULL) { | |
| *TempString = CHAR_NULL; | |
| TempString += 1; | |
| TempSize = StrSize(TempString); | |
| CopyMem(Path + StrLen(Path), TempString, TempSize); | |
| } | |
| if (((TempString = StrStr(Path, L"\\\\")) != NULL) && (*(TempString + 1) == CHAR_NULL)) { | |
| *(TempString) = CHAR_NULL; | |
| } | |
| return Path; | |
| } | |
| /** | |
| Opens a new file relative to the source file's location. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file | |
| handle to the source location. This would typically be an open | |
| handle to a directory. | |
| @param NewHandle A pointer to the location to return the opened handle for the new | |
| file. | |
| @param FileName The Null-terminated string of the name of the file to be opened. | |
| The file name may contain the following path modifiers: "\", ".", | |
| and "..". | |
| @param OpenMode The mode to open the file. The only valid combinations that the | |
| file may be opened with are: Read, Read/Write, or Create/Read/Write. | |
| @param Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the | |
| attribute bits for the newly created file. | |
| @retval EFI_SUCCESS The file was opened. | |
| @retval EFI_NOT_FOUND The specified file could not be found on the device. | |
| @retval EFI_NO_MEDIA The device has no medium. | |
| @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no | |
| longer supported. | |
| @retval EFI_DEVICE_ERROR The device reported an error. | |
| @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
| @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write | |
| when the media is write-protected. | |
| @retval EFI_ACCESS_DENIED The service denied access to the file. | |
| @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. | |
| @retval EFI_VOLUME_FULL The volume is full. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemOpen ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| OUT EFI_FILE_PROTOCOL **NewHandle, | |
| IN CHAR16 *FileName, | |
| IN UINT64 OpenMode, | |
| IN UINT64 Attributes | |
| ) | |
| { | |
| FV_FILESYSTEM_INSTANCE *Instance; | |
| FV_FILESYSTEM_FILE *File; | |
| FV_FILESYSTEM_FILE *NewFile; | |
| FV_FILESYSTEM_FILE_INFO *FvFileInfo; | |
| LIST_ENTRY *FvFileInfoLink; | |
| EFI_STATUS Status; | |
| UINTN FileNameLength; | |
| UINTN NewFileNameLength; | |
| CHAR16 *FileNameWithExtension; | |
| // | |
| // Check for a valid mode | |
| // | |
| switch (OpenMode) { | |
| case EFI_FILE_MODE_READ: | |
| break; | |
| default: | |
| return EFI_WRITE_PROTECTED; | |
| } | |
| File = FVFS_FILE_FROM_FILE_THIS (This); | |
| Instance = File->Instance; | |
| FileName = TrimFilePathToAbsolutePath (FileName); | |
| if (FileName == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (FileName[0] == L'\\') { | |
| FileName++; | |
| } | |
| // | |
| // Check for opening root | |
| // | |
| if (StrCmp (FileName, L".") == 0 || StrCmp (FileName, L"") == 0) { | |
| NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE)); | |
| if (NewFile == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| NewFile->Signature = FVFS_FILE_SIGNATURE; | |
| NewFile->Instance = Instance; | |
| NewFile->FvFileInfo = File->FvFileInfo; | |
| CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate)); | |
| InitializeListHead (&NewFile->Link); | |
| InsertHeadList (&Instance->FileHead, &NewFile->Link); | |
| NewFile->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance); | |
| *NewHandle = &NewFile->FileProtocol; | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Do a linear search for a file in the FV with a matching filename | |
| // | |
| Status = EFI_NOT_FOUND; | |
| FvFileInfo = NULL; | |
| for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead); | |
| !IsNull (&Instance->FileInfoHead, FvFileInfoLink); | |
| FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) { | |
| FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink); | |
| if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileName) == 0) { | |
| Status = EFI_SUCCESS; | |
| break; | |
| } | |
| } | |
| // If the file has not been found check if the filename exists with an extension | |
| // in case there was no extension present. | |
| // FvFileSystem adds a 'virtual' extension '.EFI' to EFI applications and drivers | |
| // present in the Firmware Volume | |
| if (Status == EFI_NOT_FOUND) { | |
| FileNameLength = StrLen (FileName); | |
| // Does the filename already contain the '.EFI' extension? | |
| if (mUnicodeCollation->StriColl (mUnicodeCollation, FileName + FileNameLength - 4, L".efi") != 0) { | |
| // No, there was no extension. So add one and search again for the file | |
| // NewFileNameLength = FileNameLength + 1 + 4 = (Number of non-null character) + (file extension) + (a null character) | |
| NewFileNameLength = FileNameLength + 1 + 4; | |
| FileNameWithExtension = AllocateCopyPool (NewFileNameLength * 2, FileName); | |
| StrCatS (FileNameWithExtension, NewFileNameLength, L".EFI"); | |
| for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead); | |
| !IsNull (&Instance->FileInfoHead, FvFileInfoLink); | |
| FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) { | |
| FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink); | |
| if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileNameWithExtension) == 0) { | |
| Status = EFI_SUCCESS; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| if (!EFI_ERROR (Status)) { | |
| NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE)); | |
| if (NewFile == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| NewFile->Signature = FVFS_FILE_SIGNATURE; | |
| NewFile->Instance = Instance; | |
| NewFile->FvFileInfo = FvFileInfo; | |
| CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate)); | |
| InitializeListHead (&NewFile->Link); | |
| InsertHeadList (&Instance->FileHead, &NewFile->Link); | |
| *NewHandle = &NewFile->FileProtocol; | |
| return EFI_SUCCESS; | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| /** | |
| Closes a specified file handle. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file | |
| handle to close. | |
| @retval EFI_SUCCESS The file was closed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemClose ( | |
| IN EFI_FILE_PROTOCOL *This | |
| ) | |
| { | |
| FV_FILESYSTEM_INSTANCE *Instance; | |
| FV_FILESYSTEM_FILE *File; | |
| File = FVFS_FILE_FROM_FILE_THIS (This); | |
| Instance = File->Instance; | |
| if (File != Instance->Root) { | |
| RemoveEntryList (&File->Link); | |
| FreePool (File); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Reads data from a file. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file | |
| handle to read data from. | |
| @param BufferSize On input, the size of the Buffer. On output, the amount of data | |
| returned in Buffer. In both cases, the size is measured in bytes. | |
| @param Buffer The buffer into which the data is read. | |
| @retval EFI_SUCCESS Data was read. | |
| @retval EFI_NO_MEDIA The device has no medium. | |
| @retval EFI_DEVICE_ERROR The device reported an error. | |
| @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file. | |
| @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file. | |
| @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
| @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory | |
| entry. BufferSize has been updated with the size | |
| needed to complete the request. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemRead ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN OUT UINTN *BufferSize, | |
| OUT VOID *Buffer | |
| ) | |
| { | |
| FV_FILESYSTEM_INSTANCE *Instance; | |
| FV_FILESYSTEM_FILE *File; | |
| EFI_STATUS Status; | |
| LIST_ENTRY *FvFileInfoLink; | |
| VOID *FileBuffer; | |
| UINTN FileSize; | |
| File = FVFS_FILE_FROM_FILE_THIS (This); | |
| Instance = File->Instance; | |
| if (File->FvFileInfo == Instance->Root->FvFileInfo) { | |
| if (File->DirReadNext) { | |
| // | |
| // Directory read: populate Buffer with an EFI_FILE_INFO | |
| // | |
| Status = FvFsGetFileInfo (File->DirReadNext, BufferSize, Buffer); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Successfully read a directory entry, now update the pointer to the | |
| // next file, which will be read on the next call to this function | |
| // | |
| FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, &File->DirReadNext->Link); | |
| if (IsNull (&Instance->FileInfoHead, FvFileInfoLink)) { | |
| // | |
| // No more files left | |
| // | |
| File->DirReadNext = NULL; | |
| } else { | |
| File->DirReadNext = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink); | |
| } | |
| } | |
| return Status; | |
| } else { | |
| // | |
| // Directory read. All entries have been read, so return a zero-size | |
| // buffer. | |
| // | |
| *BufferSize = 0; | |
| return EFI_SUCCESS; | |
| } | |
| } else { | |
| FileSize = (UINTN)File->FvFileInfo->FileInfo.FileSize; | |
| FileBuffer = AllocateZeroPool (FileSize); | |
| if (FileBuffer == NULL) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| Status = FvFsReadFile (File->Instance->FvProtocol, File->FvFileInfo, &FileSize, &FileBuffer); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| if (*BufferSize + File->Position > FileSize) { | |
| *BufferSize = (UINTN)(FileSize - File->Position); | |
| } | |
| CopyMem (Buffer, (UINT8*)FileBuffer + File->Position, *BufferSize); | |
| File->Position += *BufferSize; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| /** | |
| Writes data to a file. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file | |
| handle to write data to. | |
| @param BufferSize On input, the size of the Buffer. On output, the amount of data | |
| actually written. In both cases, the size is measured in bytes. | |
| @param Buffer The buffer of data to write. | |
| @retval EFI_SUCCESS Data was written. | |
| @retval EFI_UNSUPPORTED Writes to open directory files are not supported. | |
| @retval EFI_NO_MEDIA The device has no medium. | |
| @retval EFI_DEVICE_ERROR The device reported an error. | |
| @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file. | |
| @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
| @retval EFI_WRITE_PROTECTED The file or medium is write-protected. | |
| @retval EFI_ACCESS_DENIED The file was opened read only. | |
| @retval EFI_VOLUME_FULL The volume is full. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemWrite ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN OUT UINTN *BufferSize, | |
| IN VOID *Buffer | |
| ) | |
| { | |
| FV_FILESYSTEM_INSTANCE *Instance; | |
| FV_FILESYSTEM_FILE *File; | |
| File = FVFS_FILE_FROM_FILE_THIS (This); | |
| Instance = File->Instance; | |
| if (File->FvFileInfo == Instance->Root->FvFileInfo) { | |
| return EFI_UNSUPPORTED; | |
| } else { | |
| return EFI_WRITE_PROTECTED; | |
| } | |
| } | |
| /** | |
| Returns a file's current position. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file | |
| handle to get the current position on. | |
| @param Position The address to return the file's current position value. | |
| @retval EFI_SUCCESS The position was returned. | |
| @retval EFI_UNSUPPORTED The request is not valid on open directories. | |
| @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemGetPosition ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| OUT UINT64 *Position | |
| ) | |
| { | |
| FV_FILESYSTEM_INSTANCE *Instance; | |
| FV_FILESYSTEM_FILE *File; | |
| File = FVFS_FILE_FROM_FILE_THIS (This); | |
| Instance = File->Instance; | |
| if (File->FvFileInfo == Instance->Root->FvFileInfo) { | |
| return EFI_UNSUPPORTED; | |
| } else { | |
| *Position = File->Position; | |
| return EFI_SUCCESS; | |
| } | |
| } | |
| /** | |
| Sets a file's current position. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the | |
| file handle to set the requested position on. | |
| @param Position The byte position from the start of the file to set. | |
| @retval EFI_SUCCESS The position was set. | |
| @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open | |
| directories. | |
| @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemSetPosition ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN UINT64 Position | |
| ) | |
| { | |
| FV_FILESYSTEM_INSTANCE *Instance; | |
| FV_FILESYSTEM_FILE *File; | |
| File = FVFS_FILE_FROM_FILE_THIS (This); | |
| Instance = File->Instance; | |
| if (File->FvFileInfo == Instance->Root->FvFileInfo) { | |
| if (Position != 0) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| // | |
| // Reset directory position to first entry | |
| // | |
| File->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance); | |
| } else if (Position == 0xFFFFFFFFFFFFFFFFull) { | |
| File->Position = File->FvFileInfo->FileInfo.FileSize; | |
| } else { | |
| File->Position = Position; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Flushes all modified data associated with a file to a device. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file | |
| handle to flush. | |
| @retval EFI_SUCCESS The data was flushed. | |
| @retval EFI_NO_MEDIA The device has no medium. | |
| @retval EFI_DEVICE_ERROR The device reported an error. | |
| @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
| @retval EFI_WRITE_PROTECTED The file or medium is write-protected. | |
| @retval EFI_ACCESS_DENIED The file was opened read-only. | |
| @retval EFI_VOLUME_FULL The volume is full. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemFlush ( | |
| IN EFI_FILE_PROTOCOL *This | |
| ) | |
| { | |
| return EFI_WRITE_PROTECTED; | |
| } | |
| /** | |
| Close and delete the file handle. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the | |
| handle to the file to delete. | |
| @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed. | |
| @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemDelete ( | |
| IN EFI_FILE_PROTOCOL *This | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = FvSimpleFileSystemClose (This); | |
| ASSERT_EFI_ERROR (Status); | |
| return EFI_WARN_DELETE_FAILURE; | |
| } | |
| /** | |
| Returns information about a file. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file | |
| handle the requested information is for. | |
| @param InformationType The type identifier for the information being requested. | |
| @param BufferSize On input, the size of Buffer. On output, the amount of data | |
| returned in Buffer. In both cases, the size is measured in bytes. | |
| @param Buffer A pointer to the data buffer to return. The buffer's type is | |
| indicated by InformationType. | |
| @retval EFI_SUCCESS The information was returned. | |
| @retval EFI_UNSUPPORTED The InformationType is not known. | |
| @retval EFI_NO_MEDIA The device has no medium. | |
| @retval EFI_DEVICE_ERROR The device reported an error. | |
| @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
| @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. | |
| BufferSize has been updated with the size needed to complete | |
| the request. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemGetInfo ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN EFI_GUID *InformationType, | |
| IN OUT UINTN *BufferSize, | |
| OUT VOID *Buffer | |
| ) | |
| { | |
| FV_FILESYSTEM_FILE *File; | |
| EFI_FILE_SYSTEM_INFO *FsInfoOut; | |
| EFI_FILE_SYSTEM_VOLUME_LABEL *FsVolumeLabel; | |
| FV_FILESYSTEM_INSTANCE *Instance; | |
| UINTN Size; | |
| EFI_STATUS Status; | |
| File = FVFS_FILE_FROM_FILE_THIS (This); | |
| if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { | |
| // | |
| // Return filesystem info | |
| // | |
| Instance = File->Instance; | |
| Size = sizeof (EFI_FILE_SYSTEM_INFO) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16); | |
| if (*BufferSize < Size) { | |
| *BufferSize = Size; | |
| return EFI_BUFFER_TOO_SMALL; | |
| } | |
| // | |
| // Cast output buffer for convenience | |
| // | |
| FsInfoOut = (EFI_FILE_SYSTEM_INFO *) Buffer; | |
| CopyMem (FsInfoOut, &mFsInfoTemplate, sizeof (EFI_FILE_SYSTEM_INFO)); | |
| Status = StrnCpyS ( FsInfoOut->VolumeLabel, | |
| (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)) / sizeof (CHAR16), | |
| Instance->VolumeLabel, | |
| StrLen (Instance->VolumeLabel) | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| FsInfoOut->Size = Size; | |
| return Status; | |
| } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { | |
| // | |
| // Return file info | |
| // | |
| return FvFsGetFileInfo (File->FvFileInfo, BufferSize, (EFI_FILE_INFO *) Buffer); | |
| } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { | |
| // | |
| // Return Volume Label | |
| // | |
| Instance = File->Instance; | |
| Size = sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);; | |
| if (*BufferSize < Size) { | |
| *BufferSize = Size; | |
| return EFI_BUFFER_TOO_SMALL; | |
| } | |
| FsVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL*) Buffer; | |
| Status = StrnCpyS (FsVolumeLabel->VolumeLabel, | |
| (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_VOLUME_LABEL, VolumeLabel)) / sizeof (CHAR16), | |
| Instance->VolumeLabel, | |
| StrLen (Instance->VolumeLabel) | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } else { | |
| return EFI_UNSUPPORTED; | |
| } | |
| } | |
| /** | |
| Sets information about a file. | |
| @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file | |
| handle the information is for. | |
| @param InformationType The type identifier for the information being set. | |
| @param BufferSize The size, in bytes, of Buffer. | |
| @param Buffer A pointer to the data buffer to write. The buffer's type is | |
| indicated by InformationType. | |
| @retval EFI_SUCCESS The information was set. | |
| @retval EFI_UNSUPPORTED The InformationType is not known. | |
| @retval EFI_NO_MEDIA The device has no medium. | |
| @retval EFI_DEVICE_ERROR The device reported an error. | |
| @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
| @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_INFO_ID and the media is | |
| read-only. | |
| @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_PROTOCOL_SYSTEM_INFO_ID | |
| and the media is read only. | |
| @retval EFI_WRITE_PROTECTED InformationType is EFI_FILE_SYSTEM_VOLUME_LABEL_ID | |
| and the media is read-only. | |
| @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file to a | |
| file that is already present. | |
| @retval EFI_ACCESS_DENIED An attempt is being made to change the EFI_FILE_DIRECTORY | |
| Attribute. | |
| @retval EFI_ACCESS_DENIED An attempt is being made to change the size of a directory. | |
| @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and the file was opened | |
| read-only and an attempt is being made to modify a field | |
| other than Attribute. | |
| @retval EFI_VOLUME_FULL The volume is full. | |
| @retval EFI_BAD_BUFFER_SIZE BufferSize is smaller than the size of the type indicated | |
| by InformationType. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| FvSimpleFileSystemSetInfo ( | |
| IN EFI_FILE_PROTOCOL *This, | |
| IN EFI_GUID *InformationType, | |
| IN UINTN BufferSize, | |
| IN VOID *Buffer | |
| ) | |
| { | |
| if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) || | |
| CompareGuid (InformationType, &gEfiFileInfoGuid) || | |
| CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { | |
| return EFI_WRITE_PROTECTED; | |
| } | |
| return EFI_UNSUPPORTED; | |
| } | |