xref: /DragonStub/lib/sread.c (revision e7db4418b1fe6ea0220974b77c3b10918ab9b7a0)
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