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