0,0 → 1,352 |
/*++ |
|
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; |
EFI_DEVICE_PATH *TempFilePath; |
EFI_DEVICE_PATH *TempFilePathPtr; |
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)) { |
|
TempFilePath = DuplicateDevicePath (*FilePath); |
|
TempFilePathPtr = TempFilePath; |
|
Status = BS->LocateDevicePath (&LoadFileProtocol, &TempFilePath, DeviceHandle); |
|
FreePool (TempFilePathPtr); |
|
// |
// 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) || Status == EFI_ALREADY_STARTED) { |
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) && (Status != EFI_ALREADY_STARTED)) { |
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); |
} |