VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxFsDxe/fsw_efi.c@ 93115

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette