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