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