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