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