blob: 888f954ae67e40c55bbe4496907a3bb28a43db63 [file] [log] [blame]
Greg Hartman76d05dc2016-11-23 15:51:27 -08001/*++
2
3Copyright (c) 1998 Intel Corporation
4
5Module Name:
6
7 sread.c
8
9Abstract:
10
11 Simple read file access
12
13
14
15Revision History
16
17--*/
18
19#include "lib.h"
20
21#define SIMPLE_READ_SIGNATURE EFI_SIGNATURE_32('s','r','d','r')
22typedef 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
32EFI_STATUS
33OpenSimpleReadFile (
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
43Routine 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
49Arguments:
50
51Returns:
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
261Done:
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
279EFI_STATUS
280ReadSimpleReadFile (
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
327VOID
328CloseSimpleReadFile (
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}