MdeModulePkg/FvSimpleFileSystem: Add a new module to provide access to executable files in FVs.
This module implements Simple FileSystem protocol over Firmware Volume (FV). EFI Modules included into a FV can be listed and launched from the EFI Shell or any other EFI applications. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Brendan Jackman <brendan.jackman@arm.com> Signed-off-by: Feng Tian <feng.tian@intel.com> Reviewed-by: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16547 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
committed by
erictian
parent
32d258b5e7
commit
9da91aea69
@ -0,0 +1,978 @@
|
||||
/** @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, 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, &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,
|
||||
&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,
|
||||
&FvFileInfo->FileInfo.FileSize,
|
||||
&FoundType,
|
||||
&Attributes,
|
||||
&AuthenticationStatus
|
||||
);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Get the size of the entire file
|
||||
//
|
||||
return FvProtocol->ReadFile (
|
||||
FvProtocol,
|
||||
&FvFileInfo->NameGuid,
|
||||
NULL,
|
||||
&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 = 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;
|
||||
|
||||
//
|
||||
// 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[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
|
||||
//
|
||||
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) {
|
||||
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 = 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 = 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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user