2014-01-16 01:06:13 +01:00
|
|
|
/** @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;
|
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
Instance->RootFile->Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
|
|
|
|
|
2014-01-16 01:06:13 +01:00
|
|
|
*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;
|
|
|
|
}
|
2014-12-12 20:06:10 +01:00
|
|
|
|
|
|
|
STATIC
|
2014-01-16 01:06:13 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
STATIC
|
2014-01-16 01:06:13 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
STATIC
|
2014-01-16 01:06:13 +01:00
|
|
|
EFI_STATUS
|
|
|
|
GetFileInfo (
|
2014-12-12 20:06:10 +01:00
|
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
|
|
IN BOOTMON_FS_FILE *File,
|
|
|
|
IN OUT UINTN *BufferSize,
|
|
|
|
OUT VOID *Buffer
|
2014-01-16 01:06:13 +01:00
|
|
|
)
|
|
|
|
{
|
2014-12-12 20:06:10 +01:00
|
|
|
EFI_FILE_INFO *Info;
|
|
|
|
UINTN ResultSize;
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
ResultSize = SIZE_OF_EFI_FILE_INFO + StrSize (File->Info->FileName);
|
2014-01-16 01:06:13 +01:00
|
|
|
|
|
|
|
if (*BufferSize < ResultSize) {
|
|
|
|
*BufferSize = ResultSize;
|
|
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Info = Buffer;
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
CopyMem (Info, File->Info, ResultSize);
|
|
|
|
// Size of the information
|
2014-01-16 01:06:13 +01:00
|
|
|
Info->Size = ResultSize;
|
|
|
|
|
|
|
|
*BufferSize = ResultSize;
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2014-08-26 12:15:21 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
/**
|
|
|
|
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.
|
|
|
|
|
|
|
|
**/
|
2014-01-16 01:06:13 +01:00
|
|
|
STATIC
|
|
|
|
EFI_STATUS
|
|
|
|
SetFileName (
|
2014-12-12 20:06:10 +01:00
|
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
|
|
IN BOOTMON_FS_FILE *File,
|
|
|
|
IN CONST CHAR16 *FileName
|
2014-01-16 01:06:13 +01:00
|
|
|
)
|
|
|
|
{
|
2014-12-12 20:06:10 +01:00
|
|
|
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++;
|
2014-01-16 01:06:13 +01:00
|
|
|
}
|
|
|
|
|
2016-10-25 20:14:57 +02:00
|
|
|
UnicodeStrToAsciiStrS (FileName, AsciiFileName, MAX_NAME_LENGTH);
|
2014-12-12 20:06:10 +01:00
|
|
|
|
|
|
|
if (BootMonGetFileFromAsciiFileName (
|
|
|
|
File->Instance,
|
|
|
|
AsciiFileName,
|
|
|
|
&SameFile
|
|
|
|
) != EFI_NOT_FOUND) {
|
2014-05-08 17:03:05 +02:00
|
|
|
// A file with that name already exists.
|
2014-12-12 20:06:10 +01:00
|
|
|
return EFI_ACCESS_DENIED;
|
2014-01-16 01:06:13 +01:00
|
|
|
} else {
|
2014-05-08 17:03:05 +02:00
|
|
|
// OK, change the filename.
|
2016-10-25 20:14:57 +02:00
|
|
|
AsciiStrToUnicodeStrS (AsciiFileName, File->Info->FileName,
|
|
|
|
(File->Info->Size - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16));
|
2014-12-12 20:06:10 +01:00
|
|
|
return EFI_SUCCESS;
|
2014-01-16 01:06:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
/**
|
|
|
|
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.
|
|
|
|
|
|
|
|
**/
|
2014-01-16 01:06:13 +01:00
|
|
|
STATIC
|
|
|
|
EFI_STATUS
|
|
|
|
SetFileSize (
|
2014-12-12 20:06:10 +01:00
|
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
|
|
IN BOOTMON_FS_FILE *BootMonFsFile,
|
|
|
|
IN UINTN NewSize
|
2014-01-16 01:06:13 +01:00
|
|
|
)
|
|
|
|
{
|
2014-12-12 20:06:10 +01:00
|
|
|
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;
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
OldSize = BootMonFsFile->Info->FileSize;
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
//
|
|
|
|
// 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;
|
|
|
|
}
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
} else if (NewSize > OldSize) {
|
2014-01-16 01:06:13 +01:00
|
|
|
// 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.
|
2014-12-12 20:06:10 +01:00
|
|
|
File = &BootMonFsFile->File;
|
2014-01-16 01:06:13 +01:00
|
|
|
|
|
|
|
// Save position
|
|
|
|
Status = File->GetPosition (File, &StoredPosition);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
2014-12-12 20:06:10 +01:00
|
|
|
// Set position at the end of the file
|
|
|
|
Status = File->SetPosition (File, OldSize);
|
2014-01-16 01:06:13 +01:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
2014-12-12 20:06:10 +01:00
|
|
|
|
|
|
|
BufferSize = NewSize - OldSize;
|
|
|
|
Buffer = AllocateZeroPool (BufferSize);
|
|
|
|
if (Buffer == NULL) {
|
|
|
|
return EFI_OUT_OF_RESOURCES;
|
2014-01-16 01:06:13 +01:00
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
Status = File->Write (File, &BufferSize, Buffer);
|
|
|
|
FreePool (Buffer);
|
2014-01-16 01:06:13 +01:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
// Restore saved position
|
|
|
|
Status = File->SetPosition (File, StoredPosition);
|
2014-01-16 01:06:13 +01:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2014-12-12 20:06:10 +01:00
|
|
|
|
|
|
|
BootMonFsFile->Info->FileSize = NewSize;
|
|
|
|
|
2014-01-16 01:06:13 +01:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
/**
|
|
|
|
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
|
2014-01-16 01:06:13 +01:00
|
|
|
EFI_STATUS
|
|
|
|
SetFileInfo (
|
2014-12-12 20:06:10 +01:00
|
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
|
|
IN BOOTMON_FS_FILE *File,
|
|
|
|
IN EFI_FILE_INFO *Info
|
2014-01-16 01:06:13 +01:00
|
|
|
)
|
|
|
|
{
|
2014-12-12 20:06:10 +01:00
|
|
|
EFI_STATUS Status;
|
|
|
|
BOOLEAN FileSizeIsDifferent;
|
|
|
|
BOOLEAN FileNameIsDifferent;
|
|
|
|
BOOLEAN TimeIsDifferent;
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
//
|
|
|
|
// 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;
|
|
|
|
}
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
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;
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
//
|
|
|
|
// 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) {
|
2014-01-16 01:06:13 +01:00
|
|
|
return EFI_ACCESS_DENIED;
|
|
|
|
}
|
2014-12-12 20:06:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (TimeIsDifferent) {
|
|
|
|
return EFI_WRITE_PROTECTED;
|
|
|
|
}
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
if (FileSizeIsDifferent) {
|
|
|
|
Status = SetFileSize (Instance, File, Info->FileSize);
|
2014-01-16 01:06:13 +01:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
2014-12-12 20:06:10 +01:00
|
|
|
}
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
//
|
|
|
|
// 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);
|
2014-01-16 01:06:13 +01:00
|
|
|
if (EFI_ERROR (Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2014-12-12 20:06:10 +01:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
2014-01-16 01:06:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
if ((This == NULL) ||
|
|
|
|
(InformationType == NULL) ||
|
|
|
|
(BufferSize == NULL) ||
|
|
|
|
((Buffer == NULL) && (*BufferSize > 0)) ) {
|
|
|
|
return EFI_INVALID_PARAMETER;
|
2014-01-16 01:06:13 +01:00
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
|
|
if (File->Info == NULL) {
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
2014-01-16 01:06:13 +01:00
|
|
|
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);
|
2014-08-26 12:15:21 +02:00
|
|
|
} else if (CompareGuid (InformationType, &gArmBootMonFsFileInfoGuid) != 0) {
|
|
|
|
Status = GetBootMonFsFileInfo (Instance, File, BufferSize, Buffer);
|
2014-01-16 01:06:13 +01:00
|
|
|
} else {
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
/**
|
|
|
|
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.
|
|
|
|
|
|
|
|
**/
|
2014-01-16 01:06:13 +01:00
|
|
|
EFIAPI
|
|
|
|
EFI_STATUS
|
|
|
|
BootMonFsSetInfo (
|
|
|
|
IN EFI_FILE_PROTOCOL *This,
|
|
|
|
IN EFI_GUID *InformationType,
|
|
|
|
IN UINTN BufferSize,
|
|
|
|
IN VOID *Buffer
|
|
|
|
)
|
|
|
|
{
|
2014-12-12 20:06:10 +01:00
|
|
|
BOOTMON_FS_FILE *File;
|
|
|
|
EFI_FILE_INFO *Info;
|
|
|
|
EFI_FILE_SYSTEM_INFO *SystemInfo;
|
|
|
|
|
|
|
|
if ((This == NULL) ||
|
|
|
|
(InformationType == NULL) ||
|
|
|
|
(Buffer == NULL) ) {
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
2014-01-16 01:06:13 +01:00
|
|
|
|
|
|
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
2014-12-12 20:06:10 +01:00
|
|
|
if (File->Info == NULL) {
|
|
|
|
return EFI_INVALID_PARAMETER;
|
2014-01-16 01:06:13 +01:00
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
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));
|
|
|
|
}
|
2014-01-16 01:06:13 +01:00
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
//
|
|
|
|
// 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;
|
2014-01-16 01:06:13 +01:00
|
|
|
}
|
|
|
|
|
2014-12-12 20:06:10 +01:00
|
|
|
if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
|
|
|
|
return EFI_WRITE_PROTECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_UNSUPPORTED;
|
2014-01-16 01:06:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|