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