Imported Upstream version 3.0
[platform/upstream/gnu-efi.git] / lib / sread.c
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 }