windows-nt/Source/XPSP1/NT/base/efiutil/sdk/lib/sread.c

344 lines
7.5 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Intel Corporation
Module Name:
sread.c
Abstract:
Simple read file access
Revision History
--*/
#include "lib.h"
#define SIMPLE_READ_SIGNATURE EFI_SIGNATURE_32('s','r','d','r')
typedef struct _SIMPLE_READ_FILE {
UINTN Signature;
BOOLEAN FreeBuffer;
VOID *Source;
UINTN SourceSize;
EFI_FILE_HANDLE FileHandle;
} SIMPLE_READ_HANDLE;
EFI_STATUS
OpenSimpleReadFile (
IN BOOLEAN BootPolicy,
IN VOID *SourceBuffer OPTIONAL,
IN UINTN SourceSize,
IN OUT EFI_DEVICE_PATH **FilePath,
OUT EFI_HANDLE *DeviceHandle,
OUT SIMPLE_READ_FILE *SimpleReadHandle
)
/*++
Routine Description:
Opens a file for (simple) reading. The simple read abstraction
will access the file either from a memory copy, from a file
system interface, or from the load file interface.
Arguments:
Returns:
A handle to access the file
--*/
{
SIMPLE_READ_HANDLE *FHand;
EFI_DEVICE_PATH *UserFilePath;
FILEPATH_DEVICE_PATH *FilePathNode;
EFI_FILE_HANDLE FileHandle, LastHandle;
EFI_STATUS Status;
EFI_LOAD_FILE_INTERFACE *LoadFile;
FHand = NULL;
UserFilePath = *FilePath;
/*
* Allocate a new simple read handle structure
*/
FHand = AllocateZeroPool (sizeof(SIMPLE_READ_HANDLE));
if (!FHand) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
*SimpleReadHandle = (SIMPLE_READ_FILE) FHand;
FHand->Signature = SIMPLE_READ_SIGNATURE;
/*
* If the caller passed a copy of the file, then just use it
*/
if (SourceBuffer) {
FHand->Source = SourceBuffer;
FHand->SourceSize = SourceSize;
*DeviceHandle = NULL;
Status = EFI_SUCCESS;
goto Done;
}
/*
* Attempt to access the file via a file system interface
*/
FileHandle = NULL;
Status = BS->LocateDevicePath (&FileSystemProtocol, FilePath, DeviceHandle);
if (!EFI_ERROR(Status)) {
FileHandle = LibOpenRoot (*DeviceHandle);
}
Status = FileHandle ? EFI_SUCCESS : EFI_UNSUPPORTED;
/*
* To access as a filesystem, the filepath should only
* contain filepath components. Follow the filepath nodes
* and find the target file
*/
FilePathNode = (FILEPATH_DEVICE_PATH *) *FilePath;
while (!IsDevicePathEnd(&FilePathNode->Header)) {
/*
* For filesystem access each node should be a filepath component
*/
if (DevicePathType(&FilePathNode->Header) != MEDIA_DEVICE_PATH ||
DevicePathSubType(&FilePathNode->Header) != MEDIA_FILEPATH_DP) {
Status = EFI_UNSUPPORTED;
}
/*
* If there's been an error, stop
*/
if (EFI_ERROR(Status)) {
break;
}
/*
* Open this file path node
*/
LastHandle = FileHandle;
FileHandle = NULL;
Status = LastHandle->Open (
LastHandle,
&FileHandle,
FilePathNode->PathName,
EFI_FILE_MODE_READ,
0
);
/*
* Close the last node
*/
LastHandle->Close (LastHandle);
/*
* Get the next node
*/
FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode(&FilePathNode->Header);
}
/*
* If success, return the FHand
*/
if (!EFI_ERROR(Status)) {
ASSERT(FileHandle);
FHand->FileHandle = FileHandle;
goto Done;
}
/*
* Cleanup from filesystem access
*/
if (FileHandle) {
FileHandle->Close (FileHandle);
FileHandle = NULL;
*FilePath = UserFilePath;
}
/*
* If the error is something other then unsupported, return it
*/
if (Status != EFI_UNSUPPORTED) {
goto Done;
}
/*
* Attempt to access the file via the load file protocol
*/
Status = LibDevicePathToInterface (&LoadFileProtocol, *FilePath, (VOID*)&LoadFile);
if (!EFI_ERROR(Status)) {
/*
* Determine the size of buffer needed to hold the file
*/
SourceSize = 0;
Status = LoadFile->LoadFile (
LoadFile,
*FilePath,
BootPolicy,
&SourceSize,
NULL
);
/*
* We expect a buffer too small error to inform us
* of the buffer size needed
*/
if (Status == EFI_BUFFER_TOO_SMALL) {
SourceBuffer = AllocatePool (SourceSize);
if (SourceBuffer) {
FHand->FreeBuffer = TRUE;
FHand->Source = SourceBuffer;
FHand->SourceSize = SourceSize;
Status = LoadFile->LoadFile (
LoadFile,
*FilePath,
BootPolicy,
&SourceSize,
SourceBuffer
);
}
}
/*
* If success, return FHand
*/
if (!EFI_ERROR(Status)) {
goto Done;
}
}
/*
* Nothing else to try
*/
DEBUG ((D_LOAD|D_WARN, "OpenSimpleReadFile: Device did not support a known load protocol\n"));
Status = EFI_UNSUPPORTED;
Done:
/*
* If the file was not accessed, clean up
*/
if (EFI_ERROR(Status)) {
if (FHand) {
if (FHand->FreeBuffer) {
FreePool (FHand->Source);
}
FreePool (FHand);
}
}
return Status;
}
EFI_STATUS
ReadSimpleReadFile (
IN SIMPLE_READ_FILE UserHandle,
IN UINTN Offset,
IN OUT UINTN *ReadSize,
OUT VOID *Buffer
)
{
UINTN EndPos;
SIMPLE_READ_HANDLE *FHand;
EFI_STATUS Status;
FHand = UserHandle;
ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE);
if (FHand->Source) {
/*
* Move data from our local copy of the file
*/
EndPos = Offset + *ReadSize;
if (EndPos > FHand->SourceSize) {
*ReadSize = FHand->SourceSize - Offset;
if (Offset >= FHand->SourceSize) {
*ReadSize = 0;
}
}
CopyMem (Buffer, (CHAR8 *) FHand->Source + Offset, *ReadSize);
Status = EFI_SUCCESS;
} else {
/*
* Read data from the file
*/
Status = FHand->FileHandle->SetPosition (FHand->FileHandle, Offset);
if (!EFI_ERROR(Status)) {
Status = FHand->FileHandle->Read (FHand->FileHandle, ReadSize, Buffer);
}
}
return Status;
}
VOID
CloseSimpleReadFile (
IN SIMPLE_READ_FILE UserHandle
)
{
SIMPLE_READ_HANDLE *FHand;
FHand = UserHandle;
ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE);
/*
* Free any file handle we opened
*/
if (FHand->FileHandle) {
FHand->FileHandle->Close (FHand->FileHandle);
}
/*
* If we allocated the Source buffer, free it
*/
if (FHand->FreeBuffer) {
FreePool (FHand->Source);
}
/*
* Done with this simple read file handle
*/
FreePool (FHand);
}