Home | History | Annotate | Download | only in lib
      1 /*++
      2 
      3 Copyright (c) 1998  Intel Corporation
      4 
      5 Module Name:
      6 
      7     sread.c
      8 
      9 Abstract:
     10 
     11     Simple read file access
     12 
     13 
     14 
     15 Revision History
     16 
     17 --*/
     18 
     19 #include "lib.h"
     20 
     21 #define SIMPLE_READ_SIGNATURE       EFI_SIGNATURE_32('s','r','d','r')
     22 typedef struct _SIMPLE_READ_FILE {
     23     UINTN               Signature;
     24     BOOLEAN             FreeBuffer;
     25     VOID                *Source;
     26     UINTN               SourceSize;
     27     EFI_FILE_HANDLE     FileHandle;
     28 } SIMPLE_READ_HANDLE;
     29 
     30 
     31 
     32 EFI_STATUS
     33 OpenSimpleReadFile (
     34     IN BOOLEAN                  BootPolicy,
     35     IN VOID                     *SourceBuffer   OPTIONAL,
     36     IN UINTN                    SourceSize,
     37     IN OUT EFI_DEVICE_PATH      **FilePath,
     38     OUT EFI_HANDLE              *DeviceHandle,
     39     OUT SIMPLE_READ_FILE        *SimpleReadHandle
     40     )
     41 /*++
     42 
     43 Routine Description:
     44 
     45     Opens a file for (simple) reading.  The simple read abstraction
     46     will access the file either from a memory copy, from a file
     47     system interface, or from the load file interface.
     48 
     49 Arguments:
     50 
     51 Returns:
     52 
     53     A handle to access the file
     54 
     55 --*/
     56 {
     57     SIMPLE_READ_HANDLE          *FHand;
     58     EFI_DEVICE_PATH             *UserFilePath;
     59     EFI_DEVICE_PATH             *TempFilePath;
     60     EFI_DEVICE_PATH             *TempFilePathPtr;
     61     FILEPATH_DEVICE_PATH        *FilePathNode;
     62     EFI_FILE_HANDLE             FileHandle, LastHandle;
     63     EFI_STATUS                  Status;
     64     EFI_LOAD_FILE_INTERFACE     *LoadFile;
     65 
     66     FHand = NULL;
     67     UserFilePath = *FilePath;
     68 
     69     //
     70     // Allocate a new simple read handle structure
     71     //
     72 
     73     FHand = AllocateZeroPool (sizeof(SIMPLE_READ_HANDLE));
     74     if (!FHand) {
     75         Status = EFI_OUT_OF_RESOURCES;
     76         goto Done;
     77     }
     78 
     79     *SimpleReadHandle = (SIMPLE_READ_FILE) FHand;
     80     FHand->Signature = SIMPLE_READ_SIGNATURE;
     81 
     82     //
     83     // If the caller passed a copy of the file, then just use it
     84     //
     85 
     86     if (SourceBuffer) {
     87         FHand->Source = SourceBuffer;
     88         FHand->SourceSize = SourceSize;
     89         *DeviceHandle = NULL;
     90         Status = EFI_SUCCESS;
     91         goto Done;
     92     }
     93 
     94     //
     95     // Attempt to access the file via a file system interface
     96     //
     97 
     98     FileHandle = NULL;
     99     Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &FileSystemProtocol, FilePath, DeviceHandle);
    100     if (!EFI_ERROR(Status)) {
    101         FileHandle = LibOpenRoot (*DeviceHandle);
    102     }
    103 
    104     Status = FileHandle ? EFI_SUCCESS : EFI_UNSUPPORTED;
    105 
    106     //
    107     // To access as a filesystem, the filepath should only
    108     // contain filepath components.  Follow the filepath nodes
    109     // and find the target file
    110     //
    111 
    112     FilePathNode = (FILEPATH_DEVICE_PATH *) *FilePath;
    113     while (!IsDevicePathEnd(&FilePathNode->Header)) {
    114 
    115         //
    116         // For filesystem access each node should be a filepath component
    117         //
    118 
    119         if (DevicePathType(&FilePathNode->Header) != MEDIA_DEVICE_PATH ||
    120             DevicePathSubType(&FilePathNode->Header) != MEDIA_FILEPATH_DP) {
    121             Status = EFI_UNSUPPORTED;
    122         }
    123 
    124         //
    125         // If there's been an error, stop
    126         //
    127 
    128         if (EFI_ERROR(Status)) {
    129             break;
    130         }
    131 
    132         //
    133         // Open this file path node
    134         //
    135 
    136         LastHandle = FileHandle;
    137         FileHandle = NULL;
    138 
    139         Status = uefi_call_wrapper(
    140 			LastHandle->Open,
    141 			5,
    142                         LastHandle,
    143                         &FileHandle,
    144                         FilePathNode->PathName,
    145                         EFI_FILE_MODE_READ,
    146                         0
    147                         );
    148 
    149         //
    150         // Close the last node
    151         //
    152 
    153         uefi_call_wrapper(LastHandle->Close, 1, LastHandle);
    154 
    155         //
    156         // Get the next node
    157         //
    158 
    159         FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode(&FilePathNode->Header);
    160     }
    161 
    162     //
    163     // If success, return the FHand
    164     //
    165 
    166     if (!EFI_ERROR(Status)) {
    167         ASSERT(FileHandle);
    168         FHand->FileHandle = FileHandle;
    169         goto Done;
    170     }
    171 
    172     //
    173     // Cleanup from filesystem access
    174     //
    175 
    176     if (FileHandle) {
    177         uefi_call_wrapper(FileHandle->Close, 1, FileHandle);
    178         FileHandle = NULL;
    179         *FilePath = UserFilePath;
    180     }
    181 
    182     //
    183     // If the error is something other then unsupported, return it
    184     //
    185 
    186     if (Status != EFI_UNSUPPORTED) {
    187         goto Done;
    188     }
    189 
    190     //
    191     // Attempt to access the file via the load file protocol
    192     //
    193 
    194     Status = LibDevicePathToInterface (&LoadFileProtocol, *FilePath, (VOID*)&LoadFile);
    195     if (!EFI_ERROR(Status)) {
    196 
    197         TempFilePath = DuplicateDevicePath (*FilePath);
    198 
    199         TempFilePathPtr = TempFilePath;
    200 
    201         Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &LoadFileProtocol, &TempFilePath, DeviceHandle);
    202 
    203         FreePool (TempFilePathPtr);
    204 
    205         //
    206         // Determine the size of buffer needed to hold the file
    207         //
    208 
    209         SourceSize = 0;
    210         Status = uefi_call_wrapper(
    211 		    LoadFile->LoadFile,
    212 			5,
    213                     LoadFile,
    214                     *FilePath,
    215                     BootPolicy,
    216                     &SourceSize,
    217                     NULL
    218                     );
    219 
    220         //
    221         // We expect a buffer too small error to inform us
    222         // of the buffer size needed
    223         //
    224 
    225         if (Status == EFI_BUFFER_TOO_SMALL) {
    226             SourceBuffer = AllocatePool (SourceSize);
    227 
    228             if (SourceBuffer) {
    229                 FHand->FreeBuffer = TRUE;
    230                 FHand->Source = SourceBuffer;
    231                 FHand->SourceSize = SourceSize;
    232 
    233                 Status = uefi_call_wrapper(
    234 			    LoadFile->LoadFile,
    235 				5,
    236                             LoadFile,
    237                             *FilePath,
    238                             BootPolicy,
    239                             &SourceSize,
    240                             SourceBuffer
    241                             );
    242             }
    243         }
    244 
    245         //
    246         // If success, return FHand
    247         //
    248 
    249         if (!EFI_ERROR(Status) || Status == EFI_ALREADY_STARTED) {
    250             goto Done;
    251         }
    252     }
    253 
    254     //
    255     // Nothing else to try
    256     //
    257 
    258     DEBUG ((D_LOAD|D_WARN, "OpenSimpleReadFile: Device did not support a known load protocol\n"));
    259     Status = EFI_UNSUPPORTED;
    260 
    261 Done:
    262 
    263     //
    264     // If the file was not accessed, clean up
    265     //
    266     if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) {
    267         if (FHand) {
    268             if (FHand->FreeBuffer) {
    269                 FreePool (FHand->Source);
    270             }
    271 
    272             FreePool (FHand);
    273         }
    274     }
    275 
    276     return Status;
    277 }
    278 
    279 EFI_STATUS
    280 ReadSimpleReadFile (
    281     IN SIMPLE_READ_FILE     UserHandle,
    282     IN UINTN                Offset,
    283     IN OUT UINTN            *ReadSize,
    284     OUT VOID                *Buffer
    285     )
    286 {
    287     UINTN                   EndPos;
    288     SIMPLE_READ_HANDLE      *FHand;
    289     EFI_STATUS              Status;
    290 
    291     FHand = UserHandle;
    292     ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE);
    293     if (FHand->Source) {
    294 
    295         //
    296         // Move data from our local copy of the file
    297         //
    298 
    299         EndPos = Offset + *ReadSize;
    300         if (EndPos > FHand->SourceSize) {
    301             *ReadSize = FHand->SourceSize - Offset;
    302             if (Offset >= FHand->SourceSize) {
    303                 *ReadSize = 0;
    304             }
    305         }
    306 
    307         CopyMem (Buffer, (CHAR8 *) FHand->Source + Offset, *ReadSize);
    308         Status = EFI_SUCCESS;
    309 
    310     } else {
    311 
    312         //
    313         // Read data from the file
    314         //
    315 
    316         Status = uefi_call_wrapper(FHand->FileHandle->SetPosition, 2, FHand->FileHandle, Offset);
    317 
    318         if (!EFI_ERROR(Status)) {
    319             Status = uefi_call_wrapper(FHand->FileHandle->Read, 3, FHand->FileHandle, ReadSize, Buffer);
    320         }
    321     }
    322 
    323     return Status;
    324 }
    325 
    326 
    327 VOID
    328 CloseSimpleReadFile (
    329     IN SIMPLE_READ_FILE     UserHandle
    330     )
    331 {
    332     SIMPLE_READ_HANDLE      *FHand;
    333 
    334     FHand = UserHandle;
    335     ASSERT (FHand->Signature == SIMPLE_READ_SIGNATURE);
    336 
    337     //
    338     // Free any file handle we opened
    339     //
    340 
    341     if (FHand->FileHandle) {
    342         uefi_call_wrapper(FHand->FileHandle->Close, 1, FHand->FileHandle);
    343     }
    344 
    345     //
    346     // If we allocated the Source buffer, free it
    347     //
    348 
    349     if (FHand->FreeBuffer) {
    350         FreePool (FHand->Source);
    351     }
    352 
    353     //
    354     // Done with this simple read file handle
    355     //
    356 
    357     FreePool (FHand);
    358 }
    359