Rework the setting of information about a file, in particular file resizing, file renaming and the returned error codes in case of error. This rework has implied a rework of the read, write, close and flush functions. To strickly separate what has been actually written to the media (flushed) from what has not been written when a file is open, an "Info" field has been added to the description of a file. The field is used to store the modifications done to the file by the means of SetInfo() like the change of the name or of the size. Such changes are written to the media only when a flush occurs. When a file is open, the information pointed to by the "Info" field is always up-to-date. This is not the case of the information stored in the "HwDescription" of the file description which from now is just a mirror of what is written on the media. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ronald Cron <Ronald.Cron@arm.com> Reviewed-by: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16511 6f19259b-4bc3-4df7-8a09-765794883524
769 lines
22 KiB
C
769 lines
22 KiB
C
/** @file
|
|
*
|
|
* Copyright (c) 2012-2014, ARM Limited. All rights reserved.
|
|
*
|
|
* 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 "BootMonFsInternal.h"
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
OpenBootMonFsOpenVolume (
|
|
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
|
|
OUT EFI_FILE_PROTOCOL **Root
|
|
)
|
|
{
|
|
BOOTMON_FS_INSTANCE *Instance;
|
|
|
|
Instance = BOOTMON_FS_FROM_FS_THIS (This);
|
|
if (Instance == NULL) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Instance->RootFile->Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
|
|
|
|
*Root = &Instance->RootFile->File;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
UINT32
|
|
BootMonFsGetImageLength (
|
|
IN BOOTMON_FS_FILE *File
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
UINT32 FileSize;
|
|
LIST_ENTRY *RegionToFlushLink;
|
|
BOOTMON_FS_FILE_REGION *Region;
|
|
|
|
FileSize = 0;
|
|
|
|
// Look at all Flash areas to determine file size
|
|
for (Index = 0; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {
|
|
FileSize += File->HwDescription.Region[Index].Size;
|
|
}
|
|
|
|
// Add the regions that have not been flushed yet
|
|
for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
|
|
!IsNull (&File->RegionToFlushLink, RegionToFlushLink);
|
|
RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)
|
|
)
|
|
{
|
|
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
|
|
if (Region->Offset + Region->Size > FileSize) {
|
|
FileSize += Region->Offset + Region->Size;
|
|
}
|
|
}
|
|
|
|
return FileSize;
|
|
}
|
|
|
|
UINTN
|
|
BootMonFsGetPhysicalSize (
|
|
IN BOOTMON_FS_FILE* File
|
|
)
|
|
{
|
|
// Return 0 for files that haven't yet been flushed to media
|
|
if (File->HwDescription.RegionCount == 0) {
|
|
return 0;
|
|
}
|
|
|
|
return ((File->HwDescription.BlockEnd - File->HwDescription.BlockStart) + 1 )
|
|
* File->Instance->Media->BlockSize;
|
|
}
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsSetDirPosition (
|
|
IN EFI_FILE_PROTOCOL *This,
|
|
IN UINT64 Position
|
|
)
|
|
{
|
|
BOOTMON_FS_FILE *File;
|
|
|
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (File == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// UEFI Spec section 12.5:
|
|
// "The seek request for nonzero is not valid on open directories."
|
|
if (Position != 0) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
File->Position = Position;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BootMonFsOpenDirectory (
|
|
OUT EFI_FILE_PROTOCOL **NewHandle,
|
|
IN CHAR16 *FileName,
|
|
IN BOOTMON_FS_INSTANCE *Volume
|
|
)
|
|
{
|
|
ASSERT(0);
|
|
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GetFileSystemVolumeLabelInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
UINTN Size;
|
|
EFI_FILE_SYSTEM_VOLUME_LABEL *Label;
|
|
EFI_STATUS Status;
|
|
|
|
Label = Buffer;
|
|
|
|
// Value returned by StrSize includes null terminator.
|
|
Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL
|
|
+ StrSize (Instance->FsInfo.VolumeLabel);
|
|
|
|
if (*BufferSize >= Size) {
|
|
CopyMem (&Label->VolumeLabel, &Instance->FsInfo.VolumeLabel, Size);
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
*BufferSize = Size;
|
|
return Status;
|
|
}
|
|
|
|
// Helper function that calculates a rough "free space" by:
|
|
// - Taking the media size
|
|
// - Subtracting the sum of all file sizes
|
|
// - Subtracting the block size times the number of files
|
|
// (To account for the blocks containing the HW_IMAGE_INFO
|
|
STATIC
|
|
UINT64
|
|
ComputeFreeSpace (
|
|
IN BOOTMON_FS_INSTANCE *Instance
|
|
)
|
|
{
|
|
LIST_ENTRY *FileLink;
|
|
UINT64 FileSizeSum;
|
|
UINT64 MediaSize;
|
|
UINTN NumFiles;
|
|
EFI_BLOCK_IO_MEDIA *Media;
|
|
BOOTMON_FS_FILE *File;
|
|
|
|
Media = Instance->BlockIo->Media;
|
|
MediaSize = Media->BlockSize * (Media->LastBlock + 1);
|
|
|
|
NumFiles = 0;
|
|
FileSizeSum = 0;
|
|
for (FileLink = GetFirstNode (&Instance->RootFile->Link);
|
|
!IsNull (&Instance->RootFile->Link, FileLink);
|
|
FileLink = GetNextNode (&Instance->RootFile->Link, FileLink)
|
|
)
|
|
{
|
|
File = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
|
|
FileSizeSum += BootMonFsGetImageLength (File);
|
|
|
|
NumFiles++;
|
|
}
|
|
|
|
return MediaSize - (FileSizeSum + (Media->BlockSize + NumFiles));
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GetFilesystemInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (*BufferSize >= Instance->FsInfo.Size) {
|
|
Instance->FsInfo.FreeSpace = ComputeFreeSpace (Instance);
|
|
CopyMem (Buffer, &Instance->FsInfo, Instance->FsInfo.Size);
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
*BufferSize = Instance->FsInfo.Size;
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GetFileInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN BOOTMON_FS_FILE *File,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_FILE_INFO *Info;
|
|
UINTN ResultSize;
|
|
|
|
ResultSize = SIZE_OF_EFI_FILE_INFO + StrSize (File->Info->FileName);
|
|
|
|
if (*BufferSize < ResultSize) {
|
|
*BufferSize = ResultSize;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
Info = Buffer;
|
|
|
|
CopyMem (Info, File->Info, ResultSize);
|
|
// Size of the information
|
|
Info->Size = ResultSize;
|
|
|
|
*BufferSize = ResultSize;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GetBootMonFsFileInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN BOOTMON_FS_FILE *File,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOTMON_FS_FILE_INFO *Info;
|
|
UINTN ResultSize;
|
|
UINTN Index;
|
|
|
|
if (File == Instance->RootFile) {
|
|
Status = EFI_UNSUPPORTED;
|
|
} else {
|
|
ResultSize = SIZE_OF_BOOTMON_FS_FILE_INFO;
|
|
|
|
if (*BufferSize < ResultSize) {
|
|
*BufferSize = ResultSize;
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
} else {
|
|
Info = Buffer;
|
|
|
|
// Zero out the structure
|
|
ZeroMem (Info, ResultSize);
|
|
|
|
// Fill in the structure
|
|
Info->Size = ResultSize;
|
|
|
|
Info->EntryPoint = File->HwDescription.EntryPoint;
|
|
Info->RegionCount = File->HwDescription.RegionCount;
|
|
for (Index = 0; Index < File->HwDescription.RegionCount; Index++) {
|
|
Info->Region[Index].LoadAddress = File->HwDescription.Region[Index].LoadAddress;
|
|
Info->Region[Index].Size = File->HwDescription.Region[Index].Size;
|
|
Info->Region[Index].Offset = File->HwDescription.Region[Index].Offset;
|
|
Info->Region[Index].Checksum = File->HwDescription.Region[Index].Checksum;
|
|
}
|
|
*BufferSize = ResultSize;
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Set the name of a file.
|
|
|
|
This is a helper function for SetFileInfo().
|
|
|
|
@param[in] Instance A pointer to the description of the volume
|
|
the file belongs to.
|
|
@param[in] File A pointer to the description of the file.
|
|
@param[in] FileName A pointer to the new name of the file.
|
|
|
|
@retval EFI_SUCCESS The name was set.
|
|
@retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
|
|
to a file that is already present.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
SetFileName (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN BOOTMON_FS_FILE *File,
|
|
IN CONST CHAR16 *FileName
|
|
)
|
|
{
|
|
CHAR16 TruncFileName[MAX_NAME_LENGTH];
|
|
CHAR8 AsciiFileName[MAX_NAME_LENGTH];
|
|
BOOTMON_FS_FILE *SameFile;
|
|
|
|
// If the file path start with a \ strip it. The EFI Shell may
|
|
// insert a \ in front of the file name.
|
|
if (FileName[0] == L'\\') {
|
|
FileName++;
|
|
}
|
|
|
|
StrnCpy (TruncFileName, FileName, MAX_NAME_LENGTH - 1);
|
|
TruncFileName[MAX_NAME_LENGTH - 1] = 0;
|
|
UnicodeStrToAsciiStr (TruncFileName, AsciiFileName);
|
|
|
|
if (BootMonGetFileFromAsciiFileName (
|
|
File->Instance,
|
|
AsciiFileName,
|
|
&SameFile
|
|
) != EFI_NOT_FOUND) {
|
|
// A file with that name already exists.
|
|
return EFI_ACCESS_DENIED;
|
|
} else {
|
|
// OK, change the filename.
|
|
AsciiStrToUnicodeStr (AsciiFileName, File->Info->FileName);
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Set the size of a file.
|
|
|
|
This is a helper function for SetFileInfo().
|
|
|
|
@param[in] Instance A pointer to the description of the volume
|
|
the file belongs to.
|
|
@param[in] File A pointer to the description of the file.
|
|
@param[in] NewSize The requested new size for the file.
|
|
|
|
@retval EFI_SUCCESS The size was set.
|
|
@retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
SetFileSize (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN BOOTMON_FS_FILE *BootMonFsFile,
|
|
IN UINTN NewSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 OldSize;
|
|
LIST_ENTRY *RegionToFlushLink;
|
|
LIST_ENTRY *NextRegionToFlushLink;
|
|
BOOTMON_FS_FILE_REGION *Region;
|
|
EFI_FILE_PROTOCOL *File;
|
|
CHAR8 *Buffer;
|
|
UINTN BufferSize;
|
|
UINT64 StoredPosition;
|
|
|
|
OldSize = BootMonFsFile->Info->FileSize;
|
|
|
|
//
|
|
// In case of file truncation, force the regions waiting for writing to
|
|
// not overflow the new size of the file.
|
|
//
|
|
if (NewSize < OldSize) {
|
|
for (RegionToFlushLink = GetFirstNode (&BootMonFsFile->RegionToFlushLink);
|
|
!IsNull (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink);
|
|
)
|
|
{
|
|
NextRegionToFlushLink = GetNextNode (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink);
|
|
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
|
|
if (Region->Offset > NewSize) {
|
|
RemoveEntryList (RegionToFlushLink);
|
|
FreePool (Region->Buffer);
|
|
FreePool (Region);
|
|
} else {
|
|
Region->Size = MIN (Region->Size, NewSize - Region->Offset);
|
|
}
|
|
RegionToFlushLink = NextRegionToFlushLink;
|
|
}
|
|
|
|
} else if (NewSize > OldSize) {
|
|
// Increasing a file's size is potentially complicated as it may require
|
|
// moving the image description on media. The simplest way to do it is to
|
|
// seek past the end of the file (which is valid in UEFI) and perform a
|
|
// Write.
|
|
File = &BootMonFsFile->File;
|
|
|
|
// Save position
|
|
Status = File->GetPosition (File, &StoredPosition);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
// Set position at the end of the file
|
|
Status = File->SetPosition (File, OldSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
BufferSize = NewSize - OldSize;
|
|
Buffer = AllocateZeroPool (BufferSize);
|
|
if (Buffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Status = File->Write (File, &BufferSize, Buffer);
|
|
FreePool (Buffer);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Restore saved position
|
|
Status = File->SetPosition (File, StoredPosition);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
BootMonFsFile->Info->FileSize = NewSize;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Set information about a file.
|
|
|
|
@param[in] Instance A pointer to the description of the volume
|
|
the file belongs to.
|
|
@param[in] File A pointer to the description of the file.
|
|
@param[in] Info A pointer to the file information to write.
|
|
|
|
@retval EFI_SUCCESS The information was set.
|
|
@retval EFI_ACCESS_DENIED An attempt is being made to change the
|
|
EFI_FILE_DIRECTORY Attribute.
|
|
@retval EFI_ACCESS_DENIED The file was opened in read-only mode and an
|
|
attempt is being made to modify a field other
|
|
than Attribute.
|
|
@retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
|
|
to a file that is already present.
|
|
@retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only
|
|
attribute.
|
|
@retval EFI_OUT_OF_RESOURCES An allocation needed to process the request
|
|
failed.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
SetFileInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN BOOTMON_FS_FILE *File,
|
|
IN EFI_FILE_INFO *Info
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN FileSizeIsDifferent;
|
|
BOOLEAN FileNameIsDifferent;
|
|
BOOLEAN TimeIsDifferent;
|
|
|
|
//
|
|
// A directory can not be changed to a file and a file can
|
|
// not be changed to a directory.
|
|
//
|
|
if ((Info->Attribute & EFI_FILE_DIRECTORY) !=
|
|
(File->Info->Attribute & EFI_FILE_DIRECTORY) ) {
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
|
|
FileSizeIsDifferent = (Info->FileSize != File->Info->FileSize);
|
|
FileNameIsDifferent = (StrnCmp (
|
|
Info->FileName,
|
|
File->Info->FileName,
|
|
MAX_NAME_LENGTH - 1
|
|
) != 0);
|
|
//
|
|
// Check if the CreateTime, LastAccess or ModificationTime
|
|
// have been changed. The file system does not support file
|
|
// timestamps thus the three times in "File->Info" are
|
|
// always equal to zero. The following comparison actually
|
|
// checks if all three times are still equal to 0 or not.
|
|
//
|
|
TimeIsDifferent = CompareMem (
|
|
&Info->CreateTime,
|
|
&File->Info->CreateTime,
|
|
3 * sizeof (EFI_TIME)
|
|
) != 0;
|
|
|
|
//
|
|
// For a file opened in read-only mode, only the Attribute field can be
|
|
// modified. The root directory open mode is forced to read-only at opening
|
|
// thus the following test protects the root directory to be somehow modified.
|
|
//
|
|
if (File->OpenMode == EFI_FILE_MODE_READ) {
|
|
if (FileSizeIsDifferent || FileNameIsDifferent || TimeIsDifferent) {
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
}
|
|
|
|
if (TimeIsDifferent) {
|
|
return EFI_WRITE_PROTECTED;
|
|
}
|
|
|
|
if (FileSizeIsDifferent) {
|
|
Status = SetFileSize (Instance, File, Info->FileSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Note down in RAM the Attribute field but we can not
|
|
// ask to store it in flash for the time being.
|
|
//
|
|
File->Info->Attribute = Info->Attribute;
|
|
|
|
if (FileNameIsDifferent) {
|
|
Status = SetFileName (Instance, File, Info->FileName);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsGetInfo (
|
|
IN EFI_FILE_PROTOCOL *This,
|
|
IN EFI_GUID *InformationType,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOTMON_FS_FILE *File;
|
|
BOOTMON_FS_INSTANCE *Instance;
|
|
|
|
if ((This == NULL) ||
|
|
(InformationType == NULL) ||
|
|
(BufferSize == NULL) ||
|
|
((Buffer == NULL) && (*BufferSize > 0)) ) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (File->Info == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
Instance = File->Instance;
|
|
|
|
// If the instance has not been initialized yet then do it ...
|
|
if (!Instance->Initialized) {
|
|
Status = BootMonFsInitialize (Instance);
|
|
} else {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)
|
|
!= 0) {
|
|
Status = GetFileSystemVolumeLabelInfo (Instance, BufferSize, Buffer);
|
|
} else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {
|
|
Status = GetFilesystemInfo (Instance, BufferSize, Buffer);
|
|
} else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
|
|
Status = GetFileInfo (Instance, File, BufferSize, Buffer);
|
|
} else if (CompareGuid (InformationType, &gArmBootMonFsFileInfoGuid) != 0) {
|
|
Status = GetBootMonFsFileInfo (Instance, File, BufferSize, Buffer);
|
|
} else {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Set information about a file or a volume.
|
|
|
|
@param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
|
|
is the file handle the information is for.
|
|
@param[in] InformationType The type identifier for the information being set :
|
|
EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
|
|
EFI_FILE_SYSTEM_VOLUME_LABEL_ID
|
|
@param[in] BufferSize The size, in bytes, of Buffer.
|
|
@param[in] Buffer A pointer to the data buffer to write. The type of the
|
|
data inside the buffer is indicated by InformationType.
|
|
|
|
@retval EFI_SUCCESS The information was set.
|
|
@retval EFI_UNSUPPORTED The InformationType is not known.
|
|
@retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
|
|
@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 InformationType is EFI_FILE_INFO_ID and
|
|
the file was opened in read-only mode and an
|
|
attempt is being made to modify a field other
|
|
than Attribute.
|
|
@retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only
|
|
attribute.
|
|
@retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
|
|
the data inside the buffer.
|
|
@retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.
|
|
@retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
|
|
|
|
**/
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsSetInfo (
|
|
IN EFI_FILE_PROTOCOL *This,
|
|
IN EFI_GUID *InformationType,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
BOOTMON_FS_FILE *File;
|
|
EFI_FILE_INFO *Info;
|
|
EFI_FILE_SYSTEM_INFO *SystemInfo;
|
|
|
|
if ((This == NULL) ||
|
|
(InformationType == NULL) ||
|
|
(Buffer == NULL) ) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (File->Info == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
|
|
Info = Buffer;
|
|
if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (BufferSize < Info->Size) {
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
return (SetFileInfo (File->Instance, File, Info));
|
|
}
|
|
|
|
//
|
|
// The only writable field in the other two information types
|
|
// (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the
|
|
// filesystem volume label. This can be retrieved with GetInfo, but it is
|
|
// hard-coded into this driver, not stored on media.
|
|
//
|
|
|
|
if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
|
|
SystemInfo = Buffer;
|
|
if (SystemInfo->Size <
|
|
(SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (BufferSize < SystemInfo->Size) {
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
}
|
|
return EFI_WRITE_PROTECTED;
|
|
}
|
|
|
|
if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
|
|
return EFI_WRITE_PROTECTED;
|
|
}
|
|
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsReadDirectory (
|
|
IN EFI_FILE_PROTOCOL *This,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
BOOTMON_FS_INSTANCE *Instance;
|
|
BOOTMON_FS_FILE *RootFile;
|
|
BOOTMON_FS_FILE *File;
|
|
EFI_FILE_INFO *Info;
|
|
UINTN NameSize;
|
|
UINTN ResultSize;
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
|
|
RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (RootFile == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Instance = RootFile->Instance;
|
|
Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File);
|
|
if (EFI_ERROR (Status)) {
|
|
// No more file
|
|
*BufferSize = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;
|
|
ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));
|
|
if (*BufferSize < ResultSize) {
|
|
*BufferSize = ResultSize;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
// Zero out the structure
|
|
Info = Buffer;
|
|
ZeroMem (Info, ResultSize);
|
|
|
|
// Fill in the structure
|
|
Info->Size = ResultSize;
|
|
Info->FileSize = BootMonFsGetImageLength (File);
|
|
Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
|
|
for (Index = 0; Index < NameSize; Index++) {
|
|
Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];
|
|
}
|
|
|
|
*BufferSize = ResultSize;
|
|
RootFile->Position++;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsFlushDirectory (
|
|
IN EFI_FILE_PROTOCOL *This
|
|
)
|
|
{
|
|
BOOTMON_FS_FILE *RootFile;
|
|
LIST_ENTRY *ListFiles;
|
|
LIST_ENTRY *Link;
|
|
BOOTMON_FS_FILE *File;
|
|
|
|
RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (RootFile == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ListFiles = &RootFile->Link;
|
|
|
|
if (IsListEmpty (ListFiles)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Flush all the files that need to be flushed
|
|
//
|
|
|
|
// Go through all the list of files to flush them
|
|
for (Link = GetFirstNode (ListFiles);
|
|
!IsNull (ListFiles, Link);
|
|
Link = GetNextNode (ListFiles, Link)
|
|
)
|
|
{
|
|
File = BOOTMON_FS_FILE_FROM_LINK_THIS (Link);
|
|
File->File.Flush (&File->File);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|