| /*++ |
| |
| 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 = uefi_call_wrapper(BS->LocateDevicePath, 3, &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 = uefi_call_wrapper( |
| LastHandle->Open, |
| 5, |
| LastHandle, |
| &FileHandle, |
| FilePathNode->PathName, |
| EFI_FILE_MODE_READ, |
| 0 |
| ); |
| |
| // |
| // Close the last node |
| // |
| |
| uefi_call_wrapper(LastHandle->Close, 1, 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) { |
| uefi_call_wrapper(FileHandle->Close, 1, 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 = uefi_call_wrapper(BS->LocateDevicePath, 3, &LoadFileProtocol, &TempFilePath, DeviceHandle); |
| |
| FreePool (TempFilePathPtr); |
| |
| // |
| // Determine the size of buffer needed to hold the file |
| // |
| |
| SourceSize = 0; |
| Status = uefi_call_wrapper( |
| LoadFile->LoadFile, |
| 5, |
| 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 = uefi_call_wrapper( |
| LoadFile->LoadFile, |
| 5, |
| 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 = uefi_call_wrapper(FHand->FileHandle->SetPosition, 2, FHand->FileHandle, Offset); |
| |
| if (!EFI_ERROR(Status)) { |
| Status = uefi_call_wrapper(FHand->FileHandle->Read, 3, 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) { |
| uefi_call_wrapper(FHand->FileHandle->Close, 1, 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); |
| } |