/*++ 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); }