]> code.delx.au - refind/blob - filesystems/fsw_efi.c
Initial steps of purging GPLv2 code from core filesystem functions,
[refind] / filesystems / fsw_efi.c
1 /**
2 * \file fsw_efi.c
3 * EFI host environment code.
4 */
5
6 /*-
7 * Copyright (c) 2006 Christoph Pfisterer
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the
19 * distribution.
20 *
21 * * Neither the name of Christoph Pfisterer nor the names of the
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include "fsw_efi.h"
39 #include "fsw_core.h"
40 #ifdef __MAKEWITH_GNUEFI
41 #include "edk2/DriverBinding.h"
42 #include "edk2/ComponentName.h"
43 #endif
44 #include "../include/refit_call_wrapper.h"
45
46 #define DEBUG_LEVEL 0
47
48 #ifndef FSTYPE
49 /** The file system type name to use. */
50 #define FSTYPE ext2
51 #endif
52
53 #ifdef __MAKEWITH_GNUEFI
54
55 #define EFI_DISK_IO_PROTOCOL_GUID \
56 { \
57 0xce345171, 0xba0b, 0x11d2, {0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
58 }
59
60 #define EFI_BLOCK_IO_PROTOCOL_GUID \
61 { \
62 0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
63 }
64
65 EFI_GUID gEfiDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID;
66 EFI_GUID gEfiComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID;
67 extern EFI_GUID gEfiDiskIoProtocolGuid = EFI_DISK_IO_PROTOCOL_GUID;
68 extern EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID;
69 EFI_GUID gEfiFileInfoGuid = EFI_FILE_INFO_ID;
70 EFI_GUID gEfiFileSystemInfoGuid = EFI_FILE_SYSTEM_INFO_ID;
71 EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = EFI_FILE_SYSTEM_VOLUME_LABEL_INFO_ID;
72 #define gEfiSimpleFileSystemProtocolGuid FileSystemProtocol
73 #endif
74
75 /** Helper macro for stringification. */
76 #define FSW_EFI_STRINGIFY(x) #x
77 /** Expands to the EFI driver name given the file system type name. */
78 #define FSW_EFI_DRIVER_NAME(t) L"rEFInd 0.8.2 " FSW_EFI_STRINGIFY(t) L" File System Driver"
79
80 // function prototypes
81
82 EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This,
83 IN EFI_HANDLE ControllerHandle,
84 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath);
85 EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This,
86 IN EFI_HANDLE ControllerHandle,
87 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath);
88 EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This,
89 IN EFI_HANDLE ControllerHandle,
90 IN UINTN NumberOfChildren,
91 IN EFI_HANDLE *ChildHandleBuffer);
92
93 EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
94 IN CHAR8 *Language,
95 OUT CHAR16 **DriverName);
96 EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
97 IN EFI_HANDLE ControllerHandle,
98 IN EFI_HANDLE ChildHandle OPTIONAL,
99 IN CHAR8 *Language,
100 OUT CHAR16 **ControllerName);
101
102 void fsw_efi_change_blocksize(struct fsw_volume *vol,
103 fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
104 fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
105 fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer);
106
107 EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume);
108
109 EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
110 OUT EFI_FILE **Root);
111 EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
112 OUT EFI_FILE **NewFileHandle);
113
114 EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
115 IN OUT UINTN *BufferSize,
116 OUT VOID *Buffer);
117 EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
118 OUT UINT64 *Position);
119 EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
120 IN UINT64 Position);
121
122 EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
123 OUT EFI_FILE **NewHandle,
124 IN CHAR16 *FileName,
125 IN UINT64 OpenMode,
126 IN UINT64 Attributes);
127 EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
128 IN OUT UINTN *BufferSize,
129 OUT VOID *Buffer);
130 EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
131 IN UINT64 Position);
132
133 EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
134 IN EFI_GUID *InformationType,
135 IN OUT UINTN *BufferSize,
136 OUT VOID *Buffer);
137 EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
138 IN struct fsw_dnode *dno,
139 IN OUT UINTN *BufferSize,
140 OUT VOID *Buffer);
141
142 /**
143 * Structure for holding disk cache data.
144 */
145
146 #define CACHE_SIZE 131072 /* 128KiB */
147 struct cache_data {
148 fsw_u8 *Cache;
149 fsw_u64 CacheStart;
150 BOOLEAN CacheValid;
151 FSW_VOLUME_DATA *Volume; // NOTE: Do not deallocate; copied here to ID volume
152 };
153
154 #define NUM_CACHES 2 /* Don't increase without modifying fsw_efi_read_block() */
155 static struct cache_data Caches[NUM_CACHES];
156 static int LastRead = -1;
157
158 /**
159 * Interface structure for the EFI Driver Binding protocol.
160 */
161
162 EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = {
163 fsw_efi_DriverBinding_Supported,
164 fsw_efi_DriverBinding_Start,
165 fsw_efi_DriverBinding_Stop,
166 0x10,
167 NULL,
168 NULL
169 };
170
171 /**
172 * Interface structure for the EFI Component Name protocol.
173 */
174
175 EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = {
176 fsw_efi_ComponentName_GetDriverName,
177 fsw_efi_ComponentName_GetControllerName,
178 (CHAR8*) "eng"
179 };
180
181 /**
182 * Dispatch table for our FSW host driver.
183 */
184
185 struct fsw_host_table fsw_efi_host_table = {
186 FSW_STRING_TYPE_UTF16,
187
188 fsw_efi_change_blocksize,
189 fsw_efi_read_block
190 };
191
192 extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
193
194
195 static VOID EFIAPI fsw_efi_clear_cache(VOID) {
196 int i;
197
198 // clear the cache
199 for (i = 0; i < NUM_CACHES; i++) {
200 if (Caches[i].Cache != NULL) {
201 FreePool(Caches[i].Cache);
202 Caches[i].Cache = NULL;
203 } // if
204 Caches[i].CacheStart = 0;
205 Caches[i].CacheValid = FALSE;
206 Caches[i].Volume = NULL;
207 }
208 LastRead = -1;
209 } // VOID EFIAPI fsw_efi_clear_cache();
210
211 /**
212 * Image entry point. Installs the Driver Binding and Component Name protocols
213 * on the image's handle. Actually mounting a file system is initiated through
214 * the Driver Binding protocol at the firmware's request.
215 */
216 EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle,
217 IN EFI_SYSTEM_TABLE *SystemTable)
218 {
219 EFI_STATUS Status;
220
221 #ifndef HOST_EFI_EDK2
222 // Not available in EDK2 toolkit
223 InitializeLib(ImageHandle, SystemTable);
224 #endif
225
226 // complete Driver Binding protocol instance
227 fsw_efi_DriverBinding_table.ImageHandle = ImageHandle;
228 fsw_efi_DriverBinding_table.DriverBindingHandle = ImageHandle;
229 // install Driver Binding protocol
230 Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle,
231 &gEfiDriverBindingProtocolGuid,
232 EFI_NATIVE_INTERFACE,
233 &fsw_efi_DriverBinding_table);
234 if (EFI_ERROR (Status)) {
235 return Status;
236 }
237
238 // install Component Name protocol
239 Status = refit_call4_wrapper(BS->InstallProtocolInterface, &fsw_efi_DriverBinding_table.DriverBindingHandle,
240 &gEfiComponentNameProtocolGuid,
241 EFI_NATIVE_INTERFACE,
242 &fsw_efi_ComponentName_table);
243 if (EFI_ERROR (Status)) {
244 return Status;
245 }
246
247 // OverrideFunctions();
248 // Msg = NULL;
249 // msgCursor = NULL;
250 // Status = BS->LocateProtocol(&gMsgLogProtocolGuid, NULL, (VOID **) &Msg);
251 // if (!EFI_ERROR(Status) && (Msg != NULL)) {
252 // msgCursor = Msg->Cursor;
253 // BootLog("MsgLog installed into VBoxFs\n");
254 // }
255
256 return EFI_SUCCESS;
257 }
258
259 #ifdef __MAKEWITH_GNUEFI
260 EFI_DRIVER_ENTRY_POINT(fsw_efi_main)
261 #endif
262
263 /**
264 * Driver Binding EFI protocol, Supported function. This function is called by EFI
265 * to test if this driver can handle a certain device. Our implementation only checks
266 * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
267 * and implicitly checks if the disk is already in use by another driver.
268 */
269
270 EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This,
271 IN EFI_HANDLE ControllerHandle,
272 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
273 {
274 EFI_STATUS Status;
275 EFI_DISK_IO *DiskIo;
276
277 // we check for both DiskIO and BlockIO protocols
278
279 // first, open DiskIO
280 Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
281 &gEfiDiskIoProtocolGuid,
282 (VOID **) &DiskIo,
283 This->DriverBindingHandle,
284 ControllerHandle,
285 EFI_OPEN_PROTOCOL_BY_DRIVER);
286 if (EFI_ERROR(Status))
287 return Status;
288
289 // we were just checking, close it again
290 refit_call4_wrapper(BS->CloseProtocol, ControllerHandle,
291 &gEfiDiskIoProtocolGuid,
292 This->DriverBindingHandle,
293 ControllerHandle);
294
295 // next, check BlockIO without actually opening it
296 Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
297 &gEfiBlockIoProtocolGuid,
298 NULL,
299 This->DriverBindingHandle,
300 ControllerHandle,
301 EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
302 return Status;
303 }
304
305 /**
306 * Driver Binding EFI protocol, Start function. This function is called by EFI
307 * to start driving the given device. It is still possible at this point to
308 * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
309 * cannot find the superblock signature (or equivalent) that it expects.
310 *
311 * This function allocates memory for a per-volume structure, opens the
312 * required protocols (just Disk I/O in our case, Block I/O is only looked
313 * at to get the MediaId field), and lets the FSW core mount the file system.
314 * If successful, an EFI Simple File System protocol is exported on the
315 * device handle.
316 */
317
318 EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This,
319 IN EFI_HANDLE ControllerHandle,
320 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
321 {
322 EFI_STATUS Status;
323 EFI_BLOCK_IO *BlockIo;
324 EFI_DISK_IO *DiskIo;
325 FSW_VOLUME_DATA *Volume;
326
327 #if DEBUG_LEVEL
328 Print(L"fsw_efi_DriverBinding_Start\n");
329 #endif
330
331 // open consumed protocols
332 Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
333 &gEfiBlockIoProtocolGuid,
334 (VOID **) &BlockIo,
335 This->DriverBindingHandle,
336 ControllerHandle,
337 EFI_OPEN_PROTOCOL_GET_PROTOCOL); // NOTE: we only want to look at the MediaId
338 if (EFI_ERROR(Status)) {
339 // Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status);
340 return Status;
341 }
342
343 Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
344 &gEfiDiskIoProtocolGuid,
345 (VOID **) &DiskIo,
346 This->DriverBindingHandle,
347 ControllerHandle,
348 EFI_OPEN_PROTOCOL_BY_DRIVER);
349 if (EFI_ERROR(Status)) {
350 Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %x\n", Status);
351 return Status;
352 }
353
354 // allocate volume structure
355 Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA));
356 Volume->Signature = FSW_VOLUME_DATA_SIGNATURE;
357 Volume->Handle = ControllerHandle;
358 Volume->DiskIo = DiskIo;
359 Volume->MediaId = BlockIo->Media->MediaId;
360 Volume->LastIOStatus = EFI_SUCCESS;
361
362 // mount the filesystem
363 Status = fsw_efi_map_status(fsw_mount(Volume, &fsw_efi_host_table,
364 &FSW_FSTYPE_TABLE_NAME(FSTYPE), &Volume->vol),
365 Volume);
366
367 if (!EFI_ERROR(Status)) {
368 // register the SimpleFileSystem protocol
369 Volume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION;
370 Volume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume;
371 Status = refit_call4_wrapper(BS->InstallMultipleProtocolInterfaces, &ControllerHandle,
372 &gEfiSimpleFileSystemProtocolGuid,
373 &Volume->FileSystem,
374 NULL);
375 if (EFI_ERROR(Status)) {
376 // Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
377 }
378 }
379
380 // on errors, close the opened protocols
381 if (EFI_ERROR(Status)) {
382 if (Volume->vol != NULL)
383 fsw_unmount(Volume->vol);
384 FreePool(Volume);
385
386 refit_call4_wrapper(BS->CloseProtocol, ControllerHandle,
387 &gEfiDiskIoProtocolGuid,
388 This->DriverBindingHandle,
389 ControllerHandle);
390 }
391
392 return Status;
393 }
394
395 /**
396 * Driver Binding EFI protocol, Stop function. This function is called by EFI
397 * to stop the driver on the given device. This translates to an unmount
398 * call for the FSW core.
399 *
400 * We assume that all file handles on the volume have been closed before
401 * the driver is stopped. At least with the EFI shell, that is actually the
402 * case; it closes all file handles between commands.
403 */
404
405 EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This,
406 IN EFI_HANDLE ControllerHandle,
407 IN UINTN NumberOfChildren,
408 IN EFI_HANDLE *ChildHandleBuffer)
409 {
410 EFI_STATUS Status;
411 EFI_FILE_IO_INTERFACE *FileSystem;
412 FSW_VOLUME_DATA *Volume;
413
414 #if DEBUG_LEVEL
415 Print(L"fsw_efi_DriverBinding_Stop\n");
416 #endif
417
418 // get the installed SimpleFileSystem interface
419 Status = refit_call6_wrapper(BS->OpenProtocol, ControllerHandle,
420 &gEfiSimpleFileSystemProtocolGuid,
421 (VOID **) &FileSystem,
422 This->DriverBindingHandle,
423 ControllerHandle,
424 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
425 if (EFI_ERROR(Status))
426 return EFI_UNSUPPORTED;
427
428 // get private data structure
429 Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem);
430
431 // uninstall Simple File System protocol
432 Status = refit_call4_wrapper(BS->UninstallMultipleProtocolInterfaces, ControllerHandle,
433 &gEfiSimpleFileSystemProtocolGuid, &Volume->FileSystem,
434 NULL);
435 if (EFI_ERROR(Status)) {
436 // Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
437 return Status;
438 }
439 #if DEBUG_LEVEL
440 Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
441 #endif
442
443 // release private data structure
444 if (Volume->vol != NULL)
445 fsw_unmount(Volume->vol);
446 FreePool(Volume);
447
448 // close the consumed protocols
449 Status = refit_call4_wrapper(BS->CloseProtocol, ControllerHandle,
450 &gEfiDiskIoProtocolGuid,
451 This->DriverBindingHandle,
452 ControllerHandle);
453
454 // clear the cache
455 fsw_efi_clear_cache();
456
457 return Status;
458 }
459
460 /**
461 * Component Name EFI protocol, GetDriverName function. Used by the EFI
462 * environment to inquire the name of this driver. The name returned is
463 * based on the file system type actually used in compilation.
464 */
465
466 EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
467 IN CHAR8 *Language,
468 OUT CHAR16 **DriverName)
469 {
470 if (Language == NULL || DriverName == NULL)
471 return EFI_INVALID_PARAMETER;
472
473 if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) {
474 *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE);
475 return EFI_SUCCESS;
476 }
477 return EFI_UNSUPPORTED;
478 }
479
480 /**
481 * Component Name EFI protocol, GetControllerName function. Not implemented
482 * because this is not a "bus" driver in the sense of the EFI Driver Model.
483 */
484
485 EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
486 IN EFI_HANDLE ControllerHandle,
487 IN EFI_HANDLE ChildHandle OPTIONAL,
488 IN CHAR8 *Language,
489 OUT CHAR16 **ControllerName)
490 {
491 return EFI_UNSUPPORTED;
492 }
493
494 /**
495 * FSW interface function for block size changes. This function is called by the FSW core
496 * when the file system driver changes the block sizes for the volume.
497 */
498
499 void fsw_efi_change_blocksize(struct fsw_volume *vol,
500 fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
501 fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
502 {
503 // nothing to do
504 }
505
506 /**
507 * FSW interface function to read data blocks. This function is called by the FSW core
508 * to read a block of data from the device. The buffer is allocated by the core code.
509 * Two caches are maintained, so as to improve performance on some systems. (VirtualBox
510 * is particularly susceptible to performance problems with an uncached driver -- the
511 * ext2 driver can take 200 seconds to load a Linux kernel under VirtualBox, whereas
512 * the time is more like 3 seconds with a cache!) Two independent caches are maintained
513 * because the ext2fs driver tends to alternate between accessing two parts of the
514 * disk.
515 */
516
517 fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u64 phys_bno, void *buffer) {
518 int i, ReadCache = -1;
519 FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data;
520 EFI_STATUS Status = EFI_SUCCESS;
521 BOOLEAN ReadOneBlock = FALSE;
522 fsw_u64 StartRead = phys_bno * vol->phys_blocksize;
523
524 if (buffer == NULL)
525 return (fsw_status_t) EFI_BAD_BUFFER_SIZE;
526
527 // Initialize static data structures, if necessary....
528 if (LastRead < 0) {
529 fsw_efi_clear_cache();
530 } // if
531
532 // Look for a cache hit on the current query....
533 i = 0;
534 do {
535 if ((Caches[i].Volume == Volume) &&
536 (Caches[i].CacheValid == TRUE) &&
537 (StartRead >= Caches[i].CacheStart) &&
538 ((StartRead + vol->phys_blocksize) <= (Caches[i].CacheStart + CACHE_SIZE))) {
539 ReadCache = i;
540 }
541 i++;
542 } while ((i < NUM_CACHES) && (ReadCache < 0));
543
544 // No cache hit found; load new cache and pass it on....
545 if (ReadCache < 0) {
546 if (LastRead == -1)
547 LastRead = 1;
548 ReadCache = 1 - LastRead; // NOTE: If NUM_CACHES > 2, this must become more complex
549 Caches[ReadCache].CacheValid = FALSE;
550 if (Caches[ReadCache].Cache == NULL)
551 Caches[ReadCache].Cache = AllocatePool(CACHE_SIZE);
552 if (Caches[ReadCache].Cache != NULL) {
553 Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId,
554 StartRead, CACHE_SIZE, Caches[ReadCache].Cache);
555 if (!EFI_ERROR(Status)) {
556 Caches[ReadCache].CacheStart = StartRead;
557 Caches[ReadCache].CacheValid = TRUE;
558 Caches[ReadCache].Volume = Volume;
559 LastRead = ReadCache;
560 } else {
561 ReadOneBlock = TRUE;
562 }
563 } else {
564 ReadOneBlock = TRUE;
565 } // if cache memory allocated
566 } // if (ReadCache < 0)
567
568 if (Caches[ReadCache].Cache != NULL && Caches[ReadCache].CacheValid == TRUE) {
569 CopyMem(buffer, &Caches[ReadCache].Cache[StartRead - Caches[ReadCache].CacheStart], vol->phys_blocksize);
570 } else {
571 ReadOneBlock = TRUE;
572 }
573
574 if (ReadOneBlock) { // Something's failed, so try a simple disk read of one block....
575 Status = refit_call5_wrapper(Volume->DiskIo->ReadDisk, Volume->DiskIo, Volume->MediaId,
576 phys_bno * vol->phys_blocksize,
577 vol->phys_blocksize,
578 buffer);
579 }
580 Volume->LastIOStatus = Status;
581
582 return Status;
583 } // fsw_status_t *fsw_efi_read_block()
584
585 /**
586 * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
587 * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
588 * the last I/O operation.
589 */
590
591 EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume)
592 {
593 switch (fsw_status) {
594 case FSW_SUCCESS:
595 return EFI_SUCCESS;
596 case FSW_OUT_OF_MEMORY:
597 return EFI_VOLUME_CORRUPTED;
598 case FSW_IO_ERROR:
599 return Volume->LastIOStatus;
600 case FSW_UNSUPPORTED:
601 return EFI_UNSUPPORTED;
602 case FSW_NOT_FOUND:
603 return EFI_NOT_FOUND;
604 case FSW_VOLUME_CORRUPTED:
605 return EFI_VOLUME_CORRUPTED;
606 default:
607 return EFI_DEVICE_ERROR;
608 }
609 }
610
611 /**
612 * File System EFI protocol, OpenVolume function. Creates a file handle for
613 * the root directory and returns it. Note that this function may be called
614 * multiple times and returns a new file handle each time. Each returned
615 * handle is closed by the client using it.
616 */
617
618 EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
619 OUT EFI_FILE **Root)
620 {
621 EFI_STATUS Status;
622 FSW_VOLUME_DATA *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This);
623
624 #if DEBUG_LEVEL
625 Print(L"fsw_efi_FileSystem_OpenVolume\n");
626 #endif
627
628 fsw_efi_clear_cache();
629 Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root);
630
631 return Status;
632 }
633
634 /**
635 * File Handle EFI protocol, Open function. Dispatches the call
636 * based on the kind of file handle.
637 */
638
639 EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This,
640 OUT EFI_FILE **NewHandle,
641 IN CHAR16 *FileName,
642 IN UINT64 OpenMode,
643 IN UINT64 Attributes)
644 {
645 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
646
647 if (File->Type == FSW_EFI_FILE_TYPE_DIR)
648 return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attributes);
649 // not supported for regular files
650 return EFI_UNSUPPORTED;
651 }
652
653 /**
654 * File Handle EFI protocol, Close function. Closes the FSW shandle
655 * and frees the memory used for the structure.
656 */
657
658 EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This)
659 {
660 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
661
662 #if DEBUG_LEVEL
663 Print(L"fsw_efi_FileHandle_Close\n");
664 #endif
665
666 fsw_shandle_close(&File->shand);
667 FreePool(File);
668
669 return EFI_SUCCESS;
670 }
671
672 /**
673 * File Handle EFI protocol, Delete function. Calls through to Close
674 * and returns a warning because this driver is read-only.
675 */
676
677 EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This)
678 {
679 EFI_STATUS Status;
680
681 Status = refit_call1_wrapper(This->Close, This);
682 if (Status == EFI_SUCCESS) {
683 // this driver is read-only
684 Status = EFI_WARN_DELETE_FAILURE;
685 }
686
687 return Status;
688 }
689
690 /**
691 * File Handle EFI protocol, Read function. Dispatches the call
692 * based on the kind of file handle.
693 */
694
695 EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This,
696 IN OUT UINTN *BufferSize,
697 OUT VOID *Buffer)
698 {
699 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
700
701 if (File->Type == FSW_EFI_FILE_TYPE_FILE)
702 return fsw_efi_file_read(File, BufferSize, Buffer);
703 else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
704 return fsw_efi_dir_read(File, BufferSize, Buffer);
705 return EFI_UNSUPPORTED;
706 }
707
708 /**
709 * File Handle EFI protocol, Write function. Returns unsupported status
710 * because this driver is read-only.
711 */
712
713 EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This,
714 IN OUT UINTN *BufferSize,
715 IN VOID *Buffer)
716 {
717 // this driver is read-only
718 return EFI_WRITE_PROTECTED;
719 }
720
721 /**
722 * File Handle EFI protocol, GetPosition function. Dispatches the call
723 * based on the kind of file handle.
724 */
725
726 EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This,
727 OUT UINT64 *Position)
728 {
729 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
730
731 if (File->Type == FSW_EFI_FILE_TYPE_FILE)
732 return fsw_efi_file_getpos(File, Position);
733 // not defined for directories
734 return EFI_UNSUPPORTED;
735 }
736
737 /**
738 * File Handle EFI protocol, SetPosition function. Dispatches the call
739 * based on the kind of file handle.
740 */
741
742 EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This,
743 IN UINT64 Position)
744 {
745 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
746
747 if (File->Type == FSW_EFI_FILE_TYPE_FILE)
748 return fsw_efi_file_setpos(File, Position);
749 else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
750 return fsw_efi_dir_setpos(File, Position);
751 return EFI_UNSUPPORTED;
752 }
753
754 /**
755 * File Handle EFI protocol, GetInfo function. Dispatches to the common
756 * function implementing this.
757 */
758
759 EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This,
760 IN EFI_GUID *InformationType,
761 IN OUT UINTN *BufferSize,
762 OUT VOID *Buffer)
763 {
764 FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
765
766 return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer);
767 }
768
769 /**
770 * File Handle EFI protocol, SetInfo function. Returns unsupported status
771 * because this driver is read-only.
772 */
773
774 EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This,
775 IN EFI_GUID *InformationType,
776 IN UINTN BufferSize,
777 IN VOID *Buffer)
778 {
779 // this driver is read-only
780 return EFI_WRITE_PROTECTED;
781 }
782
783 /**
784 * File Handle EFI protocol, Flush function. Returns unsupported status
785 * because this driver is read-only.
786 */
787
788 EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This)
789 {
790 // this driver is read-only
791 return EFI_WRITE_PROTECTED;
792 }
793
794 /**
795 * Set up a file handle for a dnode. This function allocates a data structure
796 * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
797 * with the interface functions.
798 */
799
800 EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
801 OUT EFI_FILE **NewFileHandle)
802 {
803 EFI_STATUS Status;
804 FSW_FILE_DATA *File;
805
806 // make sure the dnode has complete info
807 Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data);
808 if (EFI_ERROR(Status))
809 return Status;
810
811 // check type
812 if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR)
813 return EFI_UNSUPPORTED;
814
815 // allocate file structure
816 File = AllocateZeroPool(sizeof(FSW_FILE_DATA));
817 File->Signature = FSW_FILE_DATA_SIGNATURE;
818 if (dno->type == FSW_DNODE_TYPE_FILE)
819 File->Type = FSW_EFI_FILE_TYPE_FILE;
820 else if (dno->type == FSW_DNODE_TYPE_DIR)
821 File->Type = FSW_EFI_FILE_TYPE_DIR;
822
823 // open shandle
824 Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand),
825 (FSW_VOLUME_DATA *)dno->vol->host_data);
826 if (EFI_ERROR(Status)) {
827 FreePool(File);
828 return Status;
829 }
830
831 // populate the file handle
832 File->FileHandle.Revision = EFI_FILE_HANDLE_REVISION;
833 File->FileHandle.Open = fsw_efi_FileHandle_Open;
834 File->FileHandle.Close = fsw_efi_FileHandle_Close;
835 File->FileHandle.Delete = fsw_efi_FileHandle_Delete;
836 File->FileHandle.Read = fsw_efi_FileHandle_Read;
837 File->FileHandle.Write = fsw_efi_FileHandle_Write;
838 File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition;
839 File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition;
840 File->FileHandle.GetInfo = fsw_efi_FileHandle_GetInfo;
841 File->FileHandle.SetInfo = fsw_efi_FileHandle_SetInfo;
842 File->FileHandle.Flush = fsw_efi_FileHandle_Flush;
843
844 *NewFileHandle = &File->FileHandle;
845 return EFI_SUCCESS;
846 }
847
848 /**
849 * Data read function for regular files. Calls through to fsw_shandle_read.
850 */
851
852 EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
853 IN OUT UINTN *BufferSize,
854 OUT VOID *Buffer)
855 {
856 EFI_STATUS Status;
857 fsw_u32 buffer_size;
858
859 #if DEBUG_LEVEL
860 Print(L"fsw_efi_file_read %d bytes\n", *BufferSize);
861 #endif
862
863 buffer_size = (fsw_u32)*BufferSize;
864 Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer),
865 (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data);
866 *BufferSize = buffer_size;
867
868 return Status;
869 }
870
871 /**
872 * Get file position for regular files.
873 */
874
875 EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
876 OUT UINT64 *Position)
877 {
878 *Position = File->shand.pos;
879 return EFI_SUCCESS;
880 }
881
882 /**
883 * Set file position for regular files. EFI specifies the all-ones value
884 * to be a special value for the end of the file.
885 */
886
887 EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position)
888 {
889 if (Position == 0xFFFFFFFFFFFFFFFFULL)
890 File->shand.pos = File->shand.dnode->size;
891 else
892 File->shand.pos = Position;
893 return EFI_SUCCESS;
894 }
895
896 /**
897 * Open function used to open new file handles relative to a directory.
898 * In EFI, the "open file" function is implemented by directory file handles
899 * and is passed a relative or volume-absolute path to the file or directory
900 * to open. We use fsw_dnode_lookup_path to find the node plus an additional
901 * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
902 */
903
904 EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
905 OUT EFI_FILE **NewHandle,
906 IN CHAR16 *FileName,
907 IN UINT64 OpenMode,
908 IN UINT64 Attributes)
909 {
910 EFI_STATUS Status;
911 FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
912 struct fsw_dnode *dno;
913 struct fsw_dnode *target_dno;
914 struct fsw_string lookup_path;
915
916 #if DEBUG_LEVEL
917 Print(L"fsw_efi_dir_open: '%s'\n", FileName);
918 #endif
919
920 if (OpenMode != EFI_FILE_MODE_READ)
921 return EFI_WRITE_PROTECTED;
922
923 lookup_path.type = FSW_STRING_TYPE_UTF16;
924 lookup_path.len = (int)StrLen(FileName);
925 lookup_path.size = lookup_path.len * sizeof(fsw_u16);
926 lookup_path.data = FileName;
927
928 // resolve the path (symlinks along the way are automatically resolved)
929 Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno), Volume);
930 if (EFI_ERROR(Status))
931 return Status;
932
933 // if the final node is a symlink, also resolve it
934 Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno), Volume);
935 fsw_dnode_release(dno);
936 if (EFI_ERROR(Status))
937 return Status;
938 dno = target_dno;
939
940 // make a new EFI handle for the target dnode
941 Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle);
942 fsw_dnode_release(dno);
943 return Status;
944 }
945
946 /**
947 * Read function for directories. A file handle read on a directory retrieves
948 * the next directory entry.
949 */
950
951 EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
952 IN OUT UINTN *BufferSize,
953 OUT VOID *Buffer)
954 {
955 EFI_STATUS Status;
956 FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
957 struct fsw_dnode *dno;
958
959 #if DEBUG_LEVEL
960 Print(L"fsw_efi_dir_read...\n");
961 #endif
962
963 // read the next entry
964 Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno), Volume);
965 if (Status == EFI_NOT_FOUND) {
966 // end of directory
967 *BufferSize = 0;
968 #if DEBUG_LEVEL
969 Print(L"...no more entries\n");
970 #endif
971 return EFI_SUCCESS;
972 }
973 if (EFI_ERROR(Status))
974 return Status;
975
976 // get info into buffer
977 Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer);
978 fsw_dnode_release(dno);
979 return Status;
980 }
981
982 /**
983 * Set file position for directories. The only allowed set position operation
984 * for directories is to rewind the directory completely by setting the
985 * position to zero.
986 */
987
988 EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File, IN UINT64 Position)
989 {
990 if (Position == 0) {
991 File->shand.pos = 0;
992 return EFI_SUCCESS;
993 } else {
994 // directories can only rewind to the start
995 return EFI_UNSUPPORTED;
996 }
997 }
998
999 /**
1000 * Get file or volume information. This function implements the GetInfo call
1001 * for all file handles. Control is dispatched according to the type of information
1002 * requested by the caller.
1003 */
1004
1005 EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
1006 IN EFI_GUID *InformationType,
1007 IN OUT UINTN *BufferSize,
1008 OUT VOID *Buffer)
1009 {
1010 EFI_STATUS Status;
1011 FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
1012 EFI_FILE_SYSTEM_INFO *FSInfo;
1013 UINTN RequiredSize;
1014 struct fsw_volume_stat vsb;
1015
1016
1017 if (CompareGuid(InformationType, &gEfiFileInfoGuid)) {
1018 #if DEBUG_LEVEL
1019 Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n");
1020 #endif
1021
1022 Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer);
1023
1024 } else if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid)) {
1025 #if DEBUG_LEVEL
1026 Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
1027 #endif
1028
1029 // check buffer size
1030 RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label);
1031 if (*BufferSize < RequiredSize) {
1032 *BufferSize = RequiredSize;
1033 return EFI_BUFFER_TOO_SMALL;
1034 }
1035
1036 // fill structure
1037 FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
1038 FSInfo->Size = RequiredSize;
1039 FSInfo->ReadOnly = TRUE;
1040 FSInfo->BlockSize = Volume->vol->log_blocksize;
1041 fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label);
1042
1043 // get the missing info from the fs driver
1044 ZeroMem(&vsb, sizeof(struct fsw_volume_stat));
1045 Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume);
1046 if (EFI_ERROR(Status))
1047 return Status;
1048 FSInfo->VolumeSize = vsb.total_bytes;
1049 FSInfo->FreeSpace = vsb.free_bytes;
1050
1051 // prepare for return
1052 *BufferSize = RequiredSize;
1053 Status = EFI_SUCCESS;
1054
1055 } else if (CompareGuid(InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
1056 #if DEBUG_LEVEL
1057 Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
1058 #endif
1059
1060 // check buffer size
1061 RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label);
1062 if (*BufferSize < RequiredSize) {
1063 *BufferSize = RequiredSize;
1064 return EFI_BUFFER_TOO_SMALL;
1065 }
1066
1067 // copy volume label
1068 fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label);
1069
1070 // prepare for return
1071 *BufferSize = RequiredSize;
1072 Status = EFI_SUCCESS;
1073
1074 } else {
1075 Status = EFI_UNSUPPORTED;
1076 }
1077
1078 return Status;
1079 }
1080
1081 /**
1082 * Time mapping callback for the fsw_dnode_stat call. This function converts
1083 * a Posix style timestamp into an EFI_TIME structure and writes it to the
1084 * appropriate member of the EFI_FILE_INFO structure that we're filling.
1085 */
1086
1087 static void fsw_efi_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
1088 {
1089 EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
1090
1091 if (which == FSW_DNODE_STAT_CTIME)
1092 fsw_efi_decode_time(&FileInfo->CreateTime, posix_time);
1093 else if (which == FSW_DNODE_STAT_MTIME)
1094 fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time);
1095 else if (which == FSW_DNODE_STAT_ATIME)
1096 fsw_efi_decode_time(&FileInfo->LastAccessTime, posix_time);
1097 }
1098
1099 /**
1100 * Mode mapping callback for the fsw_dnode_stat call. This function looks at
1101 * the Posix mode passed by the file system driver and makes appropriate
1102 * adjustments to the EFI_FILE_INFO structure that we're filling.
1103 */
1104
1105 static void fsw_efi_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
1106 {
1107 EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
1108
1109 if ((posix_mode & S_IWUSR) == 0)
1110 FileInfo->Attribute |= EFI_FILE_READ_ONLY;
1111 }
1112
1113 /**
1114 * Common function to fill an EFI_FILE_INFO with information about a dnode.
1115 */
1116
1117 EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
1118 IN struct fsw_dnode *dno,
1119 IN OUT UINTN *BufferSize,
1120 OUT VOID *Buffer)
1121 {
1122 EFI_STATUS Status;
1123 EFI_FILE_INFO *FileInfo;
1124 UINTN RequiredSize;
1125 struct fsw_dnode_stat sb;
1126
1127 // make sure the dnode has complete info
1128 Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
1129 if (EFI_ERROR(Status))
1130 return Status;
1131
1132 // TODO: check/assert that the dno's name is in UTF16
1133
1134 // check buffer size
1135 RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name);
1136 if (*BufferSize < RequiredSize) {
1137 // TODO: wind back the directory in this case
1138
1139 #if DEBUG_LEVEL
1140 Print(L"...BUFFER TOO SMALL\n");
1141 #endif
1142 *BufferSize = RequiredSize;
1143 return EFI_BUFFER_TOO_SMALL;
1144 }
1145
1146 // fill structure
1147 ZeroMem(Buffer, RequiredSize);
1148 FileInfo = (EFI_FILE_INFO *)Buffer;
1149 FileInfo->Size = RequiredSize;
1150 FileInfo->FileSize = dno->size;
1151 FileInfo->Attribute = 0;
1152 if (dno->type == FSW_DNODE_TYPE_DIR)
1153 FileInfo->Attribute |= EFI_FILE_DIRECTORY;
1154 fsw_efi_strcpy(FileInfo->FileName, &dno->name);
1155
1156 // get the missing info from the fs driver
1157 ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
1158 sb.store_time_posix = fsw_efi_store_time_posix;
1159 sb.store_attr_posix = fsw_efi_store_attr_posix;
1160 sb.host_data = FileInfo;
1161 Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume);
1162 if (EFI_ERROR(Status))
1163 return Status;
1164 FileInfo->PhysicalSize = sb.used_bytes;
1165
1166 // prepare for return
1167 *BufferSize = RequiredSize;
1168 #if DEBUG_LEVEL
1169 Print(L"...returning '%s'\n", FileInfo->FileName);
1170 #endif
1171 return EFI_SUCCESS;
1172 }
1173
1174 // EOF