2 Handle on-disk format and volume structures in UDF/ECMA-167 file systems.
4 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
5 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 // Vendor-Defined Device Path GUID for UDF file system
21 EFI_GUID gUdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
24 Find the anchor volume descriptor pointer.
26 @param[in] BlockIo BlockIo interface.
27 @param[in] DiskIo DiskIo interface.
28 @param[out] AnchorPoint Anchor volume descriptor pointer.
30 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
31 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
32 @retval other Anchor volume descriptor pointer not found.
36 FindAnchorVolumeDescriptorPointer (
37 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
38 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
39 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
45 EFI_LBA DescriptorLBAs
[4];
47 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
49 BlockSize
= BlockIo
->Media
->BlockSize
;
50 EndLBA
= BlockIo
->Media
->LastBlock
;
51 DescriptorLBAs
[0] = 256;
52 DescriptorLBAs
[1] = EndLBA
- 256;
53 DescriptorLBAs
[2] = EndLBA
;
54 DescriptorLBAs
[3] = 512;
56 for (Index
= 0; Index
< ARRAY_SIZE (DescriptorLBAs
); Index
++) {
57 Status
= DiskIo
->ReadDisk (
59 BlockIo
->Media
->MediaId
,
60 MultU64x32 (DescriptorLBAs
[Index
], BlockSize
),
61 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
),
64 if (EFI_ERROR (Status
)) {
68 DescriptorTag
= &AnchorPoint
->DescriptorTag
;
71 // Check if read LBA has a valid AVDP descriptor.
73 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
80 return EFI_VOLUME_CORRUPTED
;
84 Save the content of Logical Volume Descriptors and Partitions Descriptors in
87 @param[in] BlockIo BlockIo interface.
88 @param[in] DiskIo DiskIo interface.
89 @param[in] AnchorPoint Anchor volume descriptor pointer.
90 @param[out] Volume UDF volume information structure.
92 @retval EFI_SUCCESS The descriptors were saved.
93 @retval EFI_OUT_OF_RESOURCES The descriptors were not saved due to lack of
95 @retval other The descriptors were not saved due to
100 StartMainVolumeDescriptorSequence (
101 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
102 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
103 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
104 OUT UDF_VOLUME_INFO
*Volume
109 UDF_EXTENT_AD
*ExtentAd
;
110 EFI_LBA SeqStartBlock
;
112 BOOLEAN StopSequence
;
114 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
115 UINT32 LogicalBlockSize
;
117 BlockSize
= BlockIo
->Media
->BlockSize
;
118 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
121 // Allocate buffer for reading disk blocks
123 Buffer
= AllocateZeroPool ((UINTN
)BlockSize
);
124 if (Buffer
== NULL
) {
125 return EFI_OUT_OF_RESOURCES
;
129 // The logical partition created by Partition driver is relative to the main
130 // VDS extent location, so we start the Main Volume Descriptor Sequence at
133 // We don't need to check again if we have valid Volume Descriptors here since
134 // Partition driver already did.
137 SeqEndBlock
= SeqStartBlock
+ DivU64x32 ((UINT64
)ExtentAd
->ExtentLength
,
139 StopSequence
= FALSE
;
140 for (; SeqStartBlock
< SeqEndBlock
&& !StopSequence
; SeqStartBlock
++) {
144 Status
= BlockIo
->ReadBlocks (
146 BlockIo
->Media
->MediaId
,
151 if (EFI_ERROR (Status
)) {
155 DescriptorTag
= Buffer
;
157 switch (DescriptorTag
->TagIdentifier
) {
158 case UdfPartitionDescriptor
:
160 // Save Partition Descriptor
162 CopyMem (&Volume
->PartitionDesc
, Buffer
, sizeof (Volume
->PartitionDesc
));
165 case UdfLogicalVolumeDescriptor
:
167 // Save Logical Volume Descriptor
169 CopyMem (&Volume
->LogicalVolDesc
, Buffer
, sizeof (Volume
->LogicalVolDesc
));
172 case UdfTerminatingDescriptor
:
182 // Determine FE (File Entry) size
184 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
185 if (LogicalBlockSize
>= UDF_LOGICAL_SECTOR_SIZE
) {
186 Volume
->FileEntrySize
= (UINTN
)LogicalBlockSize
;
188 Volume
->FileEntrySize
= UDF_LOGICAL_SECTOR_SIZE
;
191 Status
= EFI_SUCCESS
;
195 // Free block read buffer
203 Return a Partition Descriptor given a Long Allocation Descriptor. This is
204 necessary to calculate the right extent (LongAd) offset which is added up
205 with partition's starting location.
207 @param[in] Volume Volume information pointer.
208 @param[in] LongAd Long Allocation Descriptor pointer.
210 @return A pointer to a Partition Descriptor.
213 UDF_PARTITION_DESCRIPTOR
*
215 IN UDF_VOLUME_INFO
*Volume
,
216 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
219 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
222 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
224 switch (LogicalVolDesc
->DomainIdentifier
.Suffix
.Domain
.UdfRevision
) {
232 // UDF 1.02 specification:
234 // There shall be exactly one prevailing Logical Volume Descriptor recorded
235 // per Volume Set. The Partition Maps field shall contain only Type 1
238 // UDF 1.50 through 2.60 specs say:
240 // For the purpose of interchange partition maps shall be limited to
241 // Partition Map type 1, except type 2 maps as described in the document.
243 // NOTE: Only one Type 1 (Physical) Partition is supported. It has been
244 // checked already in Partition driver for existence of a single Type 1
245 // Partition map, so we don't have to double check here.
247 // Partition reference number can also be retrieved from
248 // LongAd->ExtentLocation.PartitionReferenceNumber, however the spec says
249 // it may be 0, so let's not rely on it.
251 PartitionNum
= *(UINT16
*)((UINTN
)&LogicalVolDesc
->PartitionMaps
[4]);
256 // Unsupported UDF revision
262 // Check if partition number matches Partition Descriptor found in Main Volume
263 // Descriptor Sequence.
265 if (Volume
->PartitionDesc
.PartitionNumber
== PartitionNum
) {
266 return &Volume
->PartitionDesc
;
273 Return logical sector number of a given Long Allocation Descriptor.
275 @param[in] Volume Volume information pointer.
276 @param[in] LongAd Long Allocation Descriptor pointer.
277 @param[out] Lsn Logical sector number pointer.
279 @retval EFI_SUCCESS Logical sector number successfully returned.
280 @retval EFI_UNSUPPORTED Logical sector number is not returned due to
286 IN UDF_VOLUME_INFO
*Volume
,
287 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
,
291 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
293 PartitionDesc
= GetPdFromLongAd (Volume
, LongAd
);
294 if (PartitionDesc
== NULL
) {
297 "%a: Fail to get the Partition Descriptor from the given Long Allocation Descriptor.\n",
300 return EFI_UNSUPPORTED
;
303 *Lsn
= (UINT64
)PartitionDesc
->PartitionStartingLocation
-
304 Volume
->MainVdsStartLocation
+
305 LongAd
->ExtentLocation
.LogicalBlockNumber
;
311 Return logical sector number of a given Short Allocation Descriptor.
313 @param[in] Volume Volume pointer.
314 @param[in] PartitionDesc Partition Descriptor pointer.
315 @param[in] ShortAd Short Allocation Descriptor pointer.
317 @return The logical sector number of a given Short Allocation Descriptor.
322 IN UDF_VOLUME_INFO
*Volume
,
323 IN UDF_PARTITION_DESCRIPTOR
*PartitionDesc
,
324 IN UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
327 return (UINT64
)PartitionDesc
->PartitionStartingLocation
-
328 Volume
->MainVdsStartLocation
+ ShortAd
->ExtentPosition
;
332 Find File Set Descriptor of a given Logical Volume Descriptor.
334 The found FSD will contain the extent (LogicalVolumeContentsUse) where our
337 @param[in] BlockIo BlockIo interface.
338 @param[in] DiskIo DiskIo interface.
339 @param[in] Volume Volume information pointer.
341 @retval EFI_SUCCESS File Set Descriptor pointer found.
342 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
343 @retval other File Set Descriptor pointer not found.
347 FindFileSetDescriptor (
348 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
349 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
350 IN UDF_VOLUME_INFO
*Volume
355 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
356 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
358 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
359 Status
= GetLongAdLsn (Volume
, &LogicalVolDesc
->LogicalVolumeContentsUse
, &Lsn
);
360 if (EFI_ERROR (Status
)) {
365 // As per UDF 2.60 specification:
367 // There shall be exactly one File Set Descriptor recorded per Logical
372 Status
= DiskIo
->ReadDisk (
374 BlockIo
->Media
->MediaId
,
375 MultU64x32 (Lsn
, LogicalVolDesc
->LogicalBlockSize
),
376 sizeof (Volume
->FileSetDesc
),
379 if (EFI_ERROR (Status
)) {
383 DescriptorTag
= &Volume
->FileSetDesc
.DescriptorTag
;
386 // Check if read block is a File Set Descriptor
388 if (DescriptorTag
->TagIdentifier
!= UdfFileSetDescriptor
) {
389 return EFI_VOLUME_CORRUPTED
;
396 Read Volume and File Structure on an UDF file system.
398 @param[in] BlockIo BlockIo interface.
399 @param[in] DiskIo DiskIo interface.
400 @param[out] Volume Volume information pointer.
402 @retval EFI_SUCCESS Volume and File Structure were read.
403 @retval other Volume and File Structure were not read.
407 ReadVolumeFileStructure (
408 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
409 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
410 OUT UDF_VOLUME_INFO
*Volume
414 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
415 UDF_EXTENT_AD
*ExtentAd
;
418 // Find Anchor Volume Descriptor Pointer
420 Status
= FindAnchorVolumeDescriptorPointer (
425 if (EFI_ERROR (Status
)) {
430 // Save Main VDS start block number
432 ExtentAd
= &AnchorPoint
.MainVolumeDescriptorSequenceExtent
;
434 Volume
->MainVdsStartLocation
= (UINT64
)ExtentAd
->ExtentLocation
;
437 // Start Main Volume Descriptor Sequence.
439 Status
= StartMainVolumeDescriptorSequence (
445 if (EFI_ERROR (Status
)) {
453 Calculate length of a given File Identifier Descriptor.
455 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
457 @return The length of a given File Identifier Descriptor.
461 GetFidDescriptorLength (
462 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
466 (INTN
)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR
, Data
[0]) + 3 +
467 FileIdentifierDesc
->LengthOfFileIdentifier
+
468 FileIdentifierDesc
->LengthOfImplementationUse
) >> 2) << 2
473 Duplicate a given File Identifier Descriptor.
475 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
476 @param[out] NewFileIdentifierDesc The duplicated File Identifier Descriptor.
481 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
482 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**NewFileIdentifierDesc
485 *NewFileIdentifierDesc
=
486 (UDF_FILE_IDENTIFIER_DESCRIPTOR
*)AllocateCopyPool (
487 (UINTN
) GetFidDescriptorLength (FileIdentifierDesc
), FileIdentifierDesc
);
491 Duplicate either a given File Entry or a given Extended File Entry.
493 @param[in] BlockIo BlockIo interface.
494 @param[in] Volume Volume information pointer.
495 @param[in] FileEntry (Extended) File Entry pointer.
496 @param[out] NewFileEntry The duplicated (Extended) File Entry.
501 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
502 IN UDF_VOLUME_INFO
*Volume
,
504 OUT VOID
**NewFileEntry
507 *NewFileEntry
= AllocateCopyPool (Volume
->FileEntrySize
, FileEntry
);
511 Get raw data + length of a given File Entry or Extended File Entry.
513 The file's recorded data can contain either real file content (inline) or
514 a sequence of extents (or Allocation Descriptors) which tells where file's
515 content is stored in.
517 NOTE: The FE/EFE can be thought it was an inode.
519 @attention This is boundary function that may receive untrusted input.
520 @attention The input is from FileSystem.
522 The (Extended) File Entry is external input, so this routine will do basic
523 validation for (Extended) File Entry and report status.
525 @param[in] FileEntryData (Extended) File Entry pointer.
526 @param[in] FileEntrySize Size of the (Extended) File Entry specified
528 @param[out] Data Buffer contains the raw data of a given
529 (Extended) File Entry.
530 @param[out] Length Length of the data in Buffer.
532 @retval EFI_SUCCESS Raw data and size of the FE/EFE was read.
533 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
538 IN VOID
*FileEntryData
,
539 IN UINTN FileEntrySize
,
544 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
545 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
546 UDF_FILE_ENTRY
*FileEntry
;
548 DescriptorTag
= FileEntryData
;
550 if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
551 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
553 *Length
= ExtendedFileEntry
->InformationLength
;
554 *Data
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
555 ExtendedFileEntry
->LengthOfExtendedAttributes
);
556 } else if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
557 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
559 *Length
= FileEntry
->InformationLength
;
560 *Data
= (VOID
*)((UINT8
*)FileEntry
->Data
+
561 FileEntry
->LengthOfExtendedAttributes
);
564 if ((*Length
> FileEntrySize
) ||
565 ((UINTN
)FileEntryData
> (UINTN
)(*Data
)) ||
566 ((UINTN
)(*Data
) - (UINTN
)FileEntryData
> FileEntrySize
- *Length
)) {
567 return EFI_VOLUME_CORRUPTED
;
573 Get Allocation Descriptors' data information from a given FE/EFE.
575 @attention This is boundary function that may receive untrusted input.
576 @attention The input is from FileSystem.
578 The (Extended) File Entry is external input, so this routine will do basic
579 validation for (Extended) File Entry and report status.
581 @param[in] FileEntryData (Extended) File Entry pointer.
582 @param[in] FileEntrySize Size of the (Extended) File Entry specified
584 @param[out] AdsData Buffer contains the Allocation Descriptors'
585 data from a given FE/EFE.
586 @param[out] Length Length of the data in AdsData.
588 @retval EFI_SUCCESS The data and size of Allocation Descriptors
589 were read from the FE/EFE.
590 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
595 IN VOID
*FileEntryData
,
596 IN UINTN FileEntrySize
,
601 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
602 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
603 UDF_FILE_ENTRY
*FileEntry
;
605 DescriptorTag
= FileEntryData
;
607 if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
608 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
610 *Length
= ExtendedFileEntry
->LengthOfAllocationDescriptors
;
611 *AdsData
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
612 ExtendedFileEntry
->LengthOfExtendedAttributes
);
613 } else if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
614 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
616 *Length
= FileEntry
->LengthOfAllocationDescriptors
;
617 *AdsData
= (VOID
*)((UINT8
*)FileEntry
->Data
+
618 FileEntry
->LengthOfExtendedAttributes
);
621 if ((*Length
> FileEntrySize
) ||
622 ((UINTN
)FileEntryData
> (UINTN
)(*AdsData
)) ||
623 ((UINTN
)(*AdsData
) - (UINTN
)FileEntryData
> FileEntrySize
- *Length
)) {
624 return EFI_VOLUME_CORRUPTED
;
630 Read next Long Allocation Descriptor from a given file's data.
632 @param[in] Data File's data pointer.
633 @param[in,out] Offset Starting offset of the File's data to read.
634 @param[in] Length Length of the data to read.
635 @param[out] FoundLongAd Long Allocation Descriptor pointer.
637 @retval EFI_SUCCESS A Long Allocation Descriptor was found.
638 @retval EFI_DEVICE_ERROR No more Long Allocation Descriptors.
644 IN OUT UINT64
*Offset
,
646 OUT UDF_LONG_ALLOCATION_DESCRIPTOR
**FoundLongAd
649 UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
;
650 UDF_EXTENT_FLAGS ExtentFlags
;
653 if (*Offset
>= Length
) {
655 // No more Long Allocation Descriptors.
657 return EFI_DEVICE_ERROR
;
661 (UDF_LONG_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
664 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
665 // allocated AD, then return it.
667 ExtentFlags
= GET_EXTENT_FLAGS (LongAdsSequence
, LongAd
);
668 if (ExtentFlags
== ExtentIsNextExtent
||
669 ExtentFlags
== ExtentRecordedAndAllocated
) {
674 // This AD is either not recorded but allocated, or not recorded and not
675 // allocated. Skip it.
677 *Offset
+= AD_LENGTH (LongAdsSequence
);
680 *FoundLongAd
= LongAd
;
686 Read next Short Allocation Descriptor from a given file's data.
688 @param[in] Data File's data pointer.
689 @param[in,out] Offset Starting offset of the File's data to read.
690 @param[in] Length Length of the data to read.
691 @param[out] FoundShortAd Short Allocation Descriptor pointer.
693 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
694 @retval EFI_DEVICE_ERROR No more Short Allocation Descriptors.
700 IN OUT UINT64
*Offset
,
702 OUT UDF_SHORT_ALLOCATION_DESCRIPTOR
**FoundShortAd
705 UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
;
706 UDF_EXTENT_FLAGS ExtentFlags
;
709 if (*Offset
>= Length
) {
711 // No more Short Allocation Descriptors.
713 return EFI_DEVICE_ERROR
;
717 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
720 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
721 // allocated AD, then return it.
723 ExtentFlags
= GET_EXTENT_FLAGS (ShortAdsSequence
, ShortAd
);
724 if (ExtentFlags
== ExtentIsNextExtent
||
725 ExtentFlags
== ExtentRecordedAndAllocated
) {
730 // This AD is either not recorded but allocated, or not recorded and not
731 // allocated. Skip it.
733 *Offset
+= AD_LENGTH (ShortAdsSequence
);
736 *FoundShortAd
= ShortAd
;
742 Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
745 @param[in] RecordingFlags Flag to indicate the type of descriptor.
746 @param[in] Data File's data pointer.
747 @param[in,out] Offset Starting offset of the File's data to read.
748 @param[in] Length Length of the data to read.
749 @param[out] FoundAd Allocation Descriptor pointer.
751 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
752 @retval EFI_DEVICE_ERROR No more Allocation Descriptors.
753 Invalid type of descriptor was given.
757 GetAllocationDescriptor (
758 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
760 IN OUT UINT64
*Offset
,
765 if (RecordingFlags
== LongAdsSequence
) {
766 return GetLongAdFromAds (
770 (UDF_LONG_ALLOCATION_DESCRIPTOR
**)FoundAd
772 } else if (RecordingFlags
== ShortAdsSequence
) {
773 return GetShortAdFromAds (
777 (UDF_SHORT_ALLOCATION_DESCRIPTOR
**)FoundAd
782 // Code should never reach here.
785 return EFI_DEVICE_ERROR
;
789 Return logical sector number of either Short or Long Allocation Descriptor.
791 @param[in] RecordingFlags Flag to indicate the type of descriptor.
792 @param[in] Volume Volume information pointer.
793 @param[in] ParentIcb Long Allocation Descriptor pointer.
794 @param[in] Ad Allocation Descriptor pointer.
795 @param[out] Lsn Logical sector number pointer.
797 @retval EFI_SUCCESS Logical sector number of the given Allocation
798 Descriptor successfully returned.
799 @retval EFI_UNSUPPORTED Logical sector number of the given Allocation
800 Descriptor is not returned due to unrecognized
805 GetAllocationDescriptorLsn (
806 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
807 IN UDF_VOLUME_INFO
*Volume
,
808 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
813 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
815 if (RecordingFlags
== LongAdsSequence
) {
816 return GetLongAdLsn (Volume
, (UDF_LONG_ALLOCATION_DESCRIPTOR
*)Ad
, Lsn
);
817 } else if (RecordingFlags
== ShortAdsSequence
) {
818 PartitionDesc
= GetPdFromLongAd (Volume
, ParentIcb
);
819 if (PartitionDesc
== NULL
) {
820 return EFI_UNSUPPORTED
;
823 *Lsn
= GetShortAdLsn (
826 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)Ad
832 // Code should never reach here.
835 return EFI_UNSUPPORTED
;
839 Return offset + length of a given indirect Allocation Descriptor (AED).
841 @param[in] BlockIo BlockIo interface.
842 @param[in] DiskIo DiskIo interface.
843 @param[in] Volume Volume information pointer.
844 @param[in] ParentIcb Long Allocation Descriptor pointer.
845 @param[in] RecordingFlags Flag to indicate the type of descriptor.
846 @param[in] Ad Allocation Descriptor pointer.
847 @param[out] Offset Offset of a given indirect Allocation
849 @param[out] Length Length of a given indirect Allocation
852 @retval EFI_SUCCESS The offset and length were returned.
853 @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due
854 to lack of resources.
855 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
856 @retval other The offset and length were not returned.
861 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
862 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
863 IN UDF_VOLUME_INFO
*Volume
,
864 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
865 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
875 UINT32 LogicalBlockSize
;
876 UDF_ALLOCATION_EXTENT_DESCRIPTOR
*AllocExtDesc
;
877 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
879 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
880 Status
= GetAllocationDescriptorLsn (RecordingFlags
,
885 if (EFI_ERROR (Status
)) {
889 Data
= AllocatePool (ExtentLength
);
891 return EFI_OUT_OF_RESOURCES
;
894 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
899 Status
= DiskIo
->ReadDisk (
901 BlockIo
->Media
->MediaId
,
902 MultU64x32 (Lsn
, LogicalBlockSize
),
906 if (EFI_ERROR (Status
)) {
910 AllocExtDesc
= (UDF_ALLOCATION_EXTENT_DESCRIPTOR
*)Data
;
912 DescriptorTag
= &AllocExtDesc
->DescriptorTag
;
915 // Check if read extent contains a valid tag identifier for AED.
917 if (DescriptorTag
->TagIdentifier
!= UdfAllocationExtentDescriptor
) {
918 Status
= EFI_VOLUME_CORRUPTED
;
923 // Get AED's block offset and its length.
925 *Offset
= MultU64x32 (Lsn
, LogicalBlockSize
) +
926 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR
);
927 *Length
= AllocExtDesc
->LengthOfAllocationDescriptors
;
936 Read Allocation Extent Descriptor into memory.
938 @param[in] BlockIo BlockIo interface.
939 @param[in] DiskIo DiskIo interface.
940 @param[in] Volume Volume information pointer.
941 @param[in] ParentIcb Long Allocation Descriptor pointer.
942 @param[in] RecordingFlags Flag to indicate the type of descriptor.
943 @param[in] Ad Allocation Descriptor pointer.
944 @param[out] Data Buffer that contains the Allocation Extent
946 @param[out] Length Length of Data.
948 @retval EFI_SUCCESS The Allocation Extent Descriptor was read.
949 @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read
950 due to lack of resources.
951 @retval other Fail to read the disk.
956 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
957 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
958 IN UDF_VOLUME_INFO
*Volume
,
959 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
960 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
970 // Get AED's offset + length.
972 Status
= GetAedAdsOffset (
982 if (EFI_ERROR (Status
)) {
987 // Allocate buffer to read in AED's data.
989 *Data
= AllocatePool ((UINTN
) (*Length
));
991 return EFI_OUT_OF_RESOURCES
;
994 return DiskIo
->ReadDisk (
996 BlockIo
->Media
->MediaId
,
1004 Function used to serialise reads of Allocation Descriptors.
1006 @param[in] RecordingFlags Flag to indicate the type of descriptor.
1007 @param[in] Ad Allocation Descriptor pointer.
1008 @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.
1009 @param[in] Length Length of Buffer.
1011 @retval EFI_SUCCESS Buffer was grown to hold the next Allocation
1013 @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.
1017 GrowUpBufferToNextAd (
1018 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
1020 IN OUT VOID
**Buffer
,
1024 UINT32 ExtentLength
;
1026 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1028 if (*Buffer
== NULL
) {
1029 *Buffer
= AllocatePool (ExtentLength
);
1030 if (*Buffer
== NULL
) {
1031 return EFI_OUT_OF_RESOURCES
;
1034 *Buffer
= ReallocatePool ((UINTN
) Length
, (UINTN
) (Length
+ ExtentLength
), *Buffer
);
1035 if (*Buffer
== NULL
) {
1036 return EFI_OUT_OF_RESOURCES
;
1044 Read data or size of either a File Entry or an Extended File Entry.
1046 @param[in] BlockIo BlockIo interface.
1047 @param[in] DiskIo DiskIo interface.
1048 @param[in] Volume Volume information pointer.
1049 @param[in] ParentIcb Long Allocation Descriptor pointer.
1050 @param[in] FileEntryData FE/EFE structure pointer.
1051 @param[in, out] ReadFileInfo Read file information pointer.
1053 @retval EFI_SUCCESS Data or size of a FE/EFE was read.
1054 @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to
1056 @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is
1058 @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData
1060 @retval other Data or size of a FE/EFE was not read.
1065 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1066 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1067 IN UDF_VOLUME_INFO
*Volume
,
1068 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1069 IN VOID
*FileEntryData
,
1070 IN OUT UDF_READ_FILE_INFO
*ReadFileInfo
1074 UINT32 LogicalBlockSize
;
1081 UINT64 FilePosition
;
1086 BOOLEAN FinishedSeeking
;
1087 UINT32 ExtentLength
;
1088 UDF_FE_RECORDING_FLAGS RecordingFlags
;
1090 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
1094 // set BytesLeft to suppress incorrect compiler/analyzer warnings
1099 FinishedSeeking
= FALSE
;
1102 switch (ReadFileInfo
->Flags
) {
1103 case ReadFileGetFileSize
:
1104 case ReadFileAllocateAndRead
:
1106 // Initialise ReadFileInfo structure for either getting file size, or
1107 // reading file's recorded data.
1109 ReadFileInfo
->ReadLength
= 0;
1110 ReadFileInfo
->FileData
= NULL
;
1112 case ReadFileSeekAndRead
:
1114 // About to seek a file and/or read its data.
1116 Length
= ReadFileInfo
->FileSize
- ReadFileInfo
->FilePosition
;
1117 if (ReadFileInfo
->FileDataSize
> Length
) {
1119 // About to read beyond the EOF -- truncate it.
1121 ReadFileInfo
->FileDataSize
= Length
;
1125 // Initialise data to start seeking and/or reading a file.
1127 BytesLeft
= ReadFileInfo
->FileDataSize
;
1130 FinishedSeeking
= FALSE
;
1135 RecordingFlags
= GET_FE_RECORDING_FLAGS (FileEntryData
);
1136 switch (RecordingFlags
) {
1139 // There are no extents for this FE/EFE. All data is inline.
1141 Status
= GetFileEntryData (FileEntryData
, Volume
->FileEntrySize
, &Data
, &Length
);
1142 if (EFI_ERROR (Status
)) {
1146 if (ReadFileInfo
->Flags
== ReadFileGetFileSize
) {
1147 ReadFileInfo
->ReadLength
= Length
;
1148 } else if (ReadFileInfo
->Flags
== ReadFileAllocateAndRead
) {
1150 // Allocate buffer for starting read data.
1152 ReadFileInfo
->FileData
= AllocatePool ((UINTN
) Length
);
1153 if (ReadFileInfo
->FileData
== NULL
) {
1154 return EFI_OUT_OF_RESOURCES
;
1158 // Read all inline data into ReadFileInfo->FileData
1160 CopyMem (ReadFileInfo
->FileData
, Data
, (UINTN
) Length
);
1161 ReadFileInfo
->ReadLength
= Length
;
1162 } else if (ReadFileInfo
->Flags
== ReadFileSeekAndRead
) {
1164 // If FilePosition is non-zero, seek file to FilePosition, read
1165 // FileDataSize bytes and then updates FilePosition.
1168 ReadFileInfo
->FileData
,
1169 (VOID
*)((UINT8
*)Data
+ ReadFileInfo
->FilePosition
),
1170 (UINTN
) ReadFileInfo
->FileDataSize
1173 ReadFileInfo
->FilePosition
+= ReadFileInfo
->FileDataSize
;
1176 return EFI_INVALID_PARAMETER
;
1179 Status
= EFI_SUCCESS
;
1182 case LongAdsSequence
:
1183 case ShortAdsSequence
:
1185 // This FE/EFE contains a run of Allocation Descriptors. Get data + size
1186 // for start reading them out.
1188 Status
= GetAdsInformation (FileEntryData
, Volume
->FileEntrySize
, &Data
, &Length
);
1189 if (EFI_ERROR (Status
)) {
1199 Status
= GetAllocationDescriptor (
1206 if (Status
== EFI_DEVICE_ERROR
) {
1207 Status
= EFI_SUCCESS
;
1212 // Check if AD is an indirect AD. If so, read Allocation Extent
1213 // Descriptor and its extents (ADs).
1215 if (GET_EXTENT_FLAGS (RecordingFlags
, Ad
) == ExtentIsNextExtent
) {
1222 Status
= GetAedAdsData (
1232 if (EFI_ERROR (Status
)) {
1235 ASSERT (Data
!= NULL
);
1241 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1243 Status
= GetAllocationDescriptorLsn (RecordingFlags
,
1248 if (EFI_ERROR (Status
)) {
1252 switch (ReadFileInfo
->Flags
) {
1253 case ReadFileGetFileSize
:
1254 ReadFileInfo
->ReadLength
+= ExtentLength
;
1256 case ReadFileAllocateAndRead
:
1258 // Increase FileData (if necessary) to read next extent.
1260 Status
= GrowUpBufferToNextAd (
1263 &ReadFileInfo
->FileData
,
1264 ReadFileInfo
->ReadLength
1266 if (EFI_ERROR (Status
)) {
1267 goto Error_Alloc_Buffer_To_Next_Ad
;
1271 // Read extent's data into FileData.
1273 Status
= DiskIo
->ReadDisk (
1275 BlockIo
->Media
->MediaId
,
1276 MultU64x32 (Lsn
, LogicalBlockSize
),
1278 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1279 ReadFileInfo
->ReadLength
)
1281 if (EFI_ERROR (Status
)) {
1282 goto Error_Read_Disk_Blk
;
1285 ReadFileInfo
->ReadLength
+= ExtentLength
;
1287 case ReadFileSeekAndRead
:
1289 // Seek file first before reading in its data.
1291 if (FinishedSeeking
) {
1293 goto Skip_File_Seek
;
1296 if (FilePosition
+ ExtentLength
< ReadFileInfo
->FilePosition
) {
1297 FilePosition
+= ExtentLength
;
1301 if (FilePosition
+ ExtentLength
> ReadFileInfo
->FilePosition
) {
1302 Offset
= ReadFileInfo
->FilePosition
- FilePosition
;
1308 // Done with seeking file. Start reading its data.
1310 FinishedSeeking
= TRUE
;
1314 // Make sure we don't read more data than really wanted.
1316 if (ExtentLength
- Offset
> BytesLeft
) {
1317 DataLength
= BytesLeft
;
1319 DataLength
= ExtentLength
- Offset
;
1323 // Read extent's data into FileData.
1325 Status
= DiskIo
->ReadDisk (
1327 BlockIo
->Media
->MediaId
,
1328 Offset
+ MultU64x32 (Lsn
, LogicalBlockSize
),
1330 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1333 if (EFI_ERROR (Status
)) {
1334 goto Error_Read_Disk_Blk
;
1338 // Update current file's position.
1340 DataOffset
+= DataLength
;
1341 ReadFileInfo
->FilePosition
+= DataLength
;
1343 BytesLeft
-= DataLength
;
1344 if (BytesLeft
== 0) {
1346 // There is no more file data to read.
1348 Status
= EFI_SUCCESS
;
1357 // Point to the next AD (extent).
1359 AdOffset
+= AD_LENGTH (RecordingFlags
);
1363 case ExtendedAdsSequence
:
1364 // FIXME: Not supported. Got no volume with it, yet.
1366 Status
= EFI_UNSUPPORTED
;
1371 // A flag value reserved by the ECMA-167 standard (3rd Edition - June
1372 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
1374 Status
= EFI_UNSUPPORTED
;
1385 Error_Read_Disk_Blk
:
1386 Error_Alloc_Buffer_To_Next_Ad
:
1387 if (ReadFileInfo
->Flags
!= ReadFileSeekAndRead
) {
1388 FreePool (ReadFileInfo
->FileData
);
1400 Find a file by its filename from a given Parent file.
1402 @param[in] BlockIo BlockIo interface.
1403 @param[in] DiskIo DiskIo interface.
1404 @param[in] Volume Volume information pointer.
1405 @param[in] FileName File name string.
1406 @param[in] Parent Parent directory file.
1407 @param[in] Icb Long Allocation Descriptor pointer.
1408 @param[out] File Found file.
1410 @retval EFI_SUCCESS The file was found.
1411 @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.
1412 @retval EFI_NOT_FOUND The file was not found.
1417 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1418 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1419 IN UDF_VOLUME_INFO
*Volume
,
1420 IN CHAR16
*FileName
,
1421 IN UDF_FILE_INFO
*Parent
,
1422 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1423 OUT UDF_FILE_INFO
*File
1427 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1428 UDF_READ_DIRECTORY_INFO ReadDirInfo
;
1430 CHAR16 FoundFileName
[UDF_FILENAME_LENGTH
];
1431 VOID
*CompareFileEntry
;
1434 // Check if both Parent->FileIdentifierDesc and Icb are NULL.
1436 if ((Parent
->FileIdentifierDesc
== NULL
) && (Icb
== NULL
)) {
1437 return EFI_INVALID_PARAMETER
;
1441 // Check if parent file is really directory.
1443 if (FE_ICB_FILE_TYPE (Parent
->FileEntry
) != UdfFileEntryDirectory
) {
1444 return EFI_NOT_FOUND
;
1448 // If FileName is current file or working directory, just duplicate Parent's
1449 // FE/EFE and FID descriptors.
1451 if (StrCmp (FileName
, L
".") == 0) {
1452 if (Parent
->FileIdentifierDesc
== NULL
) {
1453 return EFI_INVALID_PARAMETER
;
1456 DuplicateFe (BlockIo
, Volume
, Parent
->FileEntry
, &File
->FileEntry
);
1457 if (File
->FileEntry
== NULL
) {
1458 return EFI_OUT_OF_RESOURCES
;
1461 DuplicateFid (Parent
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1462 if (File
->FileIdentifierDesc
== NULL
) {
1463 FreePool (File
->FileEntry
);
1464 return EFI_OUT_OF_RESOURCES
;
1471 // Start directory listing.
1473 ZeroMem ((VOID
*)&ReadDirInfo
, sizeof (UDF_READ_DIRECTORY_INFO
));
1477 Status
= ReadDirectoryEntry (
1481 (Parent
->FileIdentifierDesc
!= NULL
) ?
1482 &Parent
->FileIdentifierDesc
->Icb
:
1488 if (EFI_ERROR (Status
)) {
1489 if (Status
== EFI_DEVICE_ERROR
) {
1490 Status
= EFI_NOT_FOUND
;
1496 // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is
1497 // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code
1498 // reaches here, 'FileIdentifierDesc' must be not NULL.
1500 // The ASSERT here is for addressing a false positive NULL pointer
1501 // dereference issue raised from static analysis.
1503 ASSERT (FileIdentifierDesc
!= NULL
);
1505 if (FileIdentifierDesc
->FileCharacteristics
& PARENT_FILE
) {
1507 // This FID contains the location (FE/EFE) of the parent directory of this
1508 // directory (Parent), and if FileName is either ".." or "\\", then it's
1509 // the expected FID.
1511 if (StrCmp (FileName
, L
"..") == 0 || StrCmp (FileName
, L
"\\") == 0) {
1516 Status
= GetFileNameFromFid (FileIdentifierDesc
, ARRAY_SIZE (FoundFileName
), FoundFileName
);
1517 if (EFI_ERROR (Status
)) {
1521 if (StrCmp (FileName
, FoundFileName
) == 0) {
1523 // FID has been found. Prepare to find its respective FE/EFE.
1530 FreePool ((VOID
*)FileIdentifierDesc
);
1533 if (ReadDirInfo
.DirectoryData
!= NULL
) {
1535 // Free all allocated resources for the directory listing.
1537 FreePool (ReadDirInfo
.DirectoryData
);
1541 Status
= EFI_SUCCESS
;
1543 File
->FileIdentifierDesc
= FileIdentifierDesc
;
1546 // If the requested file is root directory, then the FE/EFE was already
1547 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1549 // Otherwise, find FE/EFE from the respective FID.
1551 if (StrCmp (FileName
, L
"\\") != 0) {
1552 Status
= FindFileEntry (
1556 &FileIdentifierDesc
->Icb
,
1559 if (EFI_ERROR (Status
)) {
1564 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1566 if (CompareMem ((VOID
*)Parent
->FileEntry
, (VOID
*)CompareFileEntry
,
1567 Volume
->FileEntrySize
) != 0) {
1568 File
->FileEntry
= CompareFileEntry
;
1570 FreePool ((VOID
*)FileIdentifierDesc
);
1571 FreePool ((VOID
*)CompareFileEntry
);
1572 Status
= EFI_NOT_FOUND
;
1580 FreePool ((VOID
*)FileIdentifierDesc
);
1586 Read volume information on a medium which contains a valid UDF file system.
1588 @param[in] BlockIo BlockIo interface.
1589 @param[in] DiskIo DiskIo interface.
1590 @param[out] Volume UDF volume information structure.
1592 @retval EFI_SUCCESS Volume information read.
1593 @retval EFI_NO_MEDIA The device has no media.
1594 @retval EFI_DEVICE_ERROR The device reported an error.
1595 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1596 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1600 ReadUdfVolumeInformation (
1601 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1602 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1603 OUT UDF_VOLUME_INFO
*Volume
1609 // Read all necessary UDF volume information and keep it private to the driver
1611 Status
= ReadVolumeFileStructure (
1616 if (EFI_ERROR (Status
)) {
1621 // Find File Set Descriptor
1623 Status
= FindFileSetDescriptor (BlockIo
, DiskIo
, Volume
);
1624 if (EFI_ERROR (Status
)) {
1632 Find the root directory on an UDF volume.
1634 @param[in] BlockIo BlockIo interface.
1635 @param[in] DiskIo DiskIo interface.
1636 @param[in] Volume UDF volume information structure.
1637 @param[out] File Root directory file.
1639 @retval EFI_SUCCESS Root directory found.
1640 @retval EFI_NO_MEDIA The device has no media.
1641 @retval EFI_DEVICE_ERROR The device reported an error.
1642 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1643 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1649 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1650 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1651 IN UDF_VOLUME_INFO
*Volume
,
1652 OUT UDF_FILE_INFO
*File
1656 UDF_FILE_INFO Parent
;
1658 Status
= FindFileEntry (
1662 &Volume
->FileSetDesc
.RootDirectoryIcb
,
1665 if (EFI_ERROR (Status
)) {
1669 Parent
.FileEntry
= File
->FileEntry
;
1670 Parent
.FileIdentifierDesc
= NULL
;
1679 &Volume
->FileSetDesc
.RootDirectoryIcb
,
1682 if (EFI_ERROR (Status
)) {
1683 FreePool (File
->FileEntry
);
1690 Find either a File Entry or a Extended File Entry from a given ICB.
1692 @param[in] BlockIo BlockIo interface.
1693 @param[in] DiskIo DiskIo interface.
1694 @param[in] Volume UDF volume information structure.
1695 @param[in] Icb ICB of the FID.
1696 @param[out] FileEntry File Entry or Extended File Entry.
1698 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1699 @retval EFI_NO_MEDIA The device has no media.
1700 @retval EFI_DEVICE_ERROR The device reported an error.
1701 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1702 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1708 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1709 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1710 IN UDF_VOLUME_INFO
*Volume
,
1711 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1712 OUT VOID
**FileEntry
1717 UINT32 LogicalBlockSize
;
1718 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
1721 Status
= GetLongAdLsn (Volume
, Icb
, &Lsn
);
1722 if (EFI_ERROR (Status
)) {
1726 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
1728 ReadBuffer
= AllocateZeroPool (Volume
->FileEntrySize
);
1729 if (ReadBuffer
== NULL
) {
1730 return EFI_OUT_OF_RESOURCES
;
1736 Status
= DiskIo
->ReadDisk (
1738 BlockIo
->Media
->MediaId
,
1739 MultU64x32 (Lsn
, LogicalBlockSize
),
1740 Volume
->FileEntrySize
,
1743 if (EFI_ERROR (Status
)) {
1744 goto Error_Read_Disk_Blk
;
1747 DescriptorTag
= ReadBuffer
;
1750 // Check if the read extent contains a valid Tag Identifier for the expected
1753 if (DescriptorTag
->TagIdentifier
!= UdfFileEntry
&&
1754 DescriptorTag
->TagIdentifier
!= UdfExtendedFileEntry
) {
1755 Status
= EFI_VOLUME_CORRUPTED
;
1756 goto Error_Invalid_Fe
;
1759 *FileEntry
= ReadBuffer
;
1763 Error_Read_Disk_Blk
:
1764 FreePool (ReadBuffer
);
1770 Find a file given its absolute path on an UDF volume.
1772 @param[in] BlockIo BlockIo interface.
1773 @param[in] DiskIo DiskIo interface.
1774 @param[in] Volume UDF volume information structure.
1775 @param[in] FilePath File's absolute path.
1776 @param[in] Root Root directory file.
1777 @param[in] Parent Parent directory file.
1778 @param[in] Icb ICB of Parent.
1779 @param[out] File Found file.
1781 @retval EFI_SUCCESS FilePath was found.
1782 @retval EFI_NO_MEDIA The device has no media.
1783 @retval EFI_DEVICE_ERROR The device reported an error.
1784 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1785 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
1791 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1792 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1793 IN UDF_VOLUME_INFO
*Volume
,
1794 IN CHAR16
*FilePath
,
1795 IN UDF_FILE_INFO
*Root
,
1796 IN UDF_FILE_INFO
*Parent
,
1797 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1798 OUT UDF_FILE_INFO
*File
1802 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1803 CHAR16
*FileNamePointer
;
1804 UDF_FILE_INFO PreviousFile
;
1807 Status
= EFI_NOT_FOUND
;
1809 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1810 while (*FilePath
!= L
'\0') {
1811 FileNamePointer
= FileName
;
1812 while (*FilePath
!= L
'\0' && *FilePath
!= L
'\\') {
1813 if ((((UINTN
)FileNamePointer
- (UINTN
)FileName
) / sizeof (CHAR16
)) >=
1814 (ARRAY_SIZE (FileName
) - 1)) {
1815 return EFI_NOT_FOUND
;
1818 *FileNamePointer
++ = *FilePath
++;
1821 *FileNamePointer
= L
'\0';
1822 if (FileName
[0] == L
'\0') {
1824 // Open root directory.
1828 // There is no file found for the root directory yet. So, find only its
1831 // See UdfOpenVolume() function.
1833 Status
= InternalFindFile (BlockIo
,
1842 // We've already a file pointer (Root) for the root directory. Duplicate
1843 // its FE/EFE and FID descriptors.
1845 Status
= EFI_SUCCESS
;
1846 DuplicateFe (BlockIo
, Volume
, Root
->FileEntry
, &File
->FileEntry
);
1847 if (File
->FileEntry
== NULL
) {
1848 Status
= EFI_OUT_OF_RESOURCES
;
1851 // File->FileEntry is not NULL.
1853 DuplicateFid (Root
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1854 if (File
->FileIdentifierDesc
== NULL
) {
1855 FreePool (File
->FileEntry
);
1856 Status
= EFI_OUT_OF_RESOURCES
;
1862 // No root directory. Find filename from the current directory.
1864 Status
= InternalFindFile (BlockIo
,
1873 if (EFI_ERROR (Status
)) {
1878 // If the found file is a symlink, then find its respective FE/EFE and
1881 if (FE_ICB_FILE_TYPE (File
->FileEntry
) == UdfFileEntrySymlink
) {
1882 FreePool ((VOID
*)File
->FileIdentifierDesc
);
1884 FileEntry
= File
->FileEntry
;
1886 Status
= ResolveSymlink (BlockIo
,
1893 FreePool (FileEntry
);
1895 if (EFI_ERROR (Status
)) {
1900 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1901 sizeof (UDF_FILE_INFO
)) != 0) {
1902 CleanupFileInformation (&PreviousFile
);
1905 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1906 if (*FilePath
!= L
'\0' && *FilePath
== L
'\\') {
1915 Read a directory entry at a time on an UDF volume.
1917 @param[in] BlockIo BlockIo interface.
1918 @param[in] DiskIo DiskIo interface.
1919 @param[in] Volume UDF volume information structure.
1920 @param[in] ParentIcb ICB of the parent file.
1921 @param[in] FileEntryData FE/EFE of the parent file.
1922 @param[in, out] ReadDirInfo Next read directory listing structure
1924 @param[out] FoundFid File Identifier Descriptor pointer.
1926 @retval EFI_SUCCESS Directory entry read.
1927 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1928 @retval EFI_NO_MEDIA The device has no media.
1929 @retval EFI_DEVICE_ERROR The device reported an error.
1930 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1931 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1936 ReadDirectoryEntry (
1937 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1938 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1939 IN UDF_VOLUME_INFO
*Volume
,
1940 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1941 IN VOID
*FileEntryData
,
1942 IN OUT UDF_READ_DIRECTORY_INFO
*ReadDirInfo
,
1943 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**FoundFid
1947 UDF_READ_FILE_INFO ReadFileInfo
;
1948 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1950 if (ReadDirInfo
->DirectoryData
== NULL
) {
1952 // The directory's recorded data has not been read yet. So let's cache it
1953 // into memory and the next calls won't need to read it again.
1955 ReadFileInfo
.Flags
= ReadFileAllocateAndRead
;
1965 if (EFI_ERROR (Status
)) {
1970 // Fill in ReadDirInfo structure with the read directory's data information.
1972 ReadDirInfo
->DirectoryData
= ReadFileInfo
.FileData
;
1973 ReadDirInfo
->DirectoryLength
= ReadFileInfo
.ReadLength
;
1977 if (ReadDirInfo
->FidOffset
>= ReadDirInfo
->DirectoryLength
) {
1979 // There are no longer FIDs for this directory. By returning
1980 // EFI_DEVICE_ERROR to the callee will indicate end of directory
1983 return EFI_DEVICE_ERROR
;
1987 // Get FID for this entry.
1989 FileIdentifierDesc
= GET_FID_FROM_ADS (ReadDirInfo
->DirectoryData
,
1990 ReadDirInfo
->FidOffset
);
1992 // Update FidOffset to point to next FID.
1994 ReadDirInfo
->FidOffset
+= GetFidDescriptorLength (FileIdentifierDesc
);
1995 } while (FileIdentifierDesc
->FileCharacteristics
& DELETED_FILE
);
1997 DuplicateFid (FileIdentifierDesc
, FoundFid
);
1998 if (*FoundFid
== NULL
) {
1999 return EFI_OUT_OF_RESOURCES
;
2006 Get a filename (encoded in OSTA-compressed format) from a File Identifier
2007 Descriptor on an UDF volume.
2009 @attention This is boundary function that may receive untrusted input.
2010 @attention The input is from FileSystem.
2012 The File Identifier Descriptor is external input, so this routine will do
2013 basic validation for File Identifier Descriptor and report status.
2015 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
2016 @param[in] CharMax The maximum number of FileName Unicode char,
2017 including terminating null char.
2018 @param[out] FileName Decoded filename.
2020 @retval EFI_SUCCESS Filename decoded and read.
2021 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2022 @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
2026 GetFileNameFromFid (
2027 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
2029 OUT CHAR16
*FileName
2032 UINT8
*OstaCompressed
;
2033 UINT8 CompressionId
;
2036 CHAR16
*FileNameBak
;
2039 return EFI_BUFFER_TOO_SMALL
;
2044 (UINT8
*)FileIdentifierDesc
->Data
+
2045 FileIdentifierDesc
->LengthOfImplementationUse
2048 CompressionId
= OstaCompressed
[0];
2049 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2050 return EFI_VOLUME_CORRUPTED
;
2053 FileNameBak
= FileName
;
2058 Length
= FileIdentifierDesc
->LengthOfFileIdentifier
;
2059 if (CompressionId
== 16) {
2060 if (((UINTN
)Length
>> 1) > CharMax
) {
2061 return EFI_BUFFER_TOO_SMALL
;
2064 if ((Length
!= 0) && ((UINTN
)Length
- 1 > CharMax
)) {
2065 return EFI_BUFFER_TOO_SMALL
;
2069 for (Index
= 1; Index
< Length
; Index
++) {
2070 if (CompressionId
== 16) {
2071 *FileName
= OstaCompressed
[Index
++] << 8;
2076 if (Index
< Length
) {
2077 *FileName
|= (CHAR16
)(OstaCompressed
[Index
]);
2083 Index
= ((UINTN
)FileName
- (UINTN
)FileNameBak
) / sizeof (CHAR16
);
2084 if (Index
> CharMax
- 1) {
2085 Index
= CharMax
- 1;
2087 FileNameBak
[Index
] = L
'\0';
2093 Resolve a symlink file on an UDF volume.
2095 @attention This is boundary function that may receive untrusted input.
2096 @attention The input is from FileSystem.
2098 The Path Component is external input, so this routine will do basic
2099 validation for Path Component and report status.
2101 @param[in] BlockIo BlockIo interface.
2102 @param[in] DiskIo DiskIo interface.
2103 @param[in] Volume UDF volume information structure.
2104 @param[in] Parent Parent file.
2105 @param[in] FileEntryData FE/EFE structure pointer.
2106 @param[out] File Resolved file.
2108 @retval EFI_SUCCESS Symlink file resolved.
2109 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2110 @retval EFI_NO_MEDIA The device has no media.
2111 @retval EFI_DEVICE_ERROR The device reported an error.
2112 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2113 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
2119 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2120 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2121 IN UDF_VOLUME_INFO
*Volume
,
2122 IN UDF_FILE_INFO
*Parent
,
2123 IN VOID
*FileEntryData
,
2124 OUT UDF_FILE_INFO
*File
2128 UDF_READ_FILE_INFO ReadFileInfo
;
2132 UDF_PATH_COMPONENT
*PathComp
;
2133 UINT8 PathCompLength
;
2134 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
2137 UINT8 CompressionId
;
2138 UDF_FILE_INFO PreviousFile
;
2141 // Symlink files on UDF volumes do not contain so much data other than
2142 // Path Components which resolves to real filenames, so it's OK to read in
2143 // all its data here -- usually the data will be inline with the FE/EFE for
2146 ReadFileInfo
.Flags
= ReadFileAllocateAndRead
;
2152 &Parent
->FileIdentifierDesc
->Icb
,
2156 if (EFI_ERROR (Status
)) {
2160 Length
= ReadFileInfo
.ReadLength
;
2162 Data
= (UINT8
*)ReadFileInfo
.FileData
;
2163 EndData
= Data
+ Length
;
2165 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
2168 PathComp
= (UDF_PATH_COMPONENT
*)Data
;
2170 PathCompLength
= PathComp
->LengthOfComponentIdentifier
;
2172 switch (PathComp
->ComponentType
) {
2175 // This Path Component specifies the root directory hierarchy subject to
2176 // agreement between the originator and recipient of the medium. Skip it.
2182 // "\\." of the current directory. Read next Path Component.
2184 goto Next_Path_Component
;
2187 // ".." (parent directory). Go to it.
2189 CopyMem ((VOID
*)FileName
, L
"..", 6);
2193 // "." (current file). Duplicate both FE/EFE and FID of this file.
2195 DuplicateFe (BlockIo
, Volume
, PreviousFile
.FileEntry
, &File
->FileEntry
);
2196 if (File
->FileEntry
== NULL
) {
2197 Status
= EFI_OUT_OF_RESOURCES
;
2198 goto Error_Find_File
;
2201 DuplicateFid (PreviousFile
.FileIdentifierDesc
,
2202 &File
->FileIdentifierDesc
);
2203 if (File
->FileIdentifierDesc
== NULL
) {
2204 FreePool (File
->FileEntry
);
2205 Status
= EFI_OUT_OF_RESOURCES
;
2206 goto Error_Find_File
;
2208 goto Next_Path_Component
;
2211 // This Path Component identifies an object, either a file or a
2212 // directory or an alias.
2214 // Decode it from the compressed data in ComponentIdentifier and find
2217 CompressionId
= PathComp
->ComponentIdentifier
[0];
2218 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2219 return EFI_VOLUME_CORRUPTED
;
2223 for (Index
= 1; Index
< PathCompLength
; Index
++) {
2224 if (CompressionId
== 16) {
2225 *Char
= *(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+
2229 if (Index
> ARRAY_SIZE (FileName
)) {
2230 return EFI_UNSUPPORTED
;
2235 if (Index
< Length
) {
2236 *Char
|= (CHAR16
)(*(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+ Index
));
2242 Index
= ((UINTN
)Char
- (UINTN
)FileName
) / sizeof (CHAR16
);
2243 if (Index
> ARRAY_SIZE (FileName
) - 1) {
2244 Index
= ARRAY_SIZE (FileName
) - 1;
2246 FileName
[Index
] = L
'\0';
2251 // Find file from the read filename in symlink's file data.
2253 Status
= InternalFindFile (
2262 if (EFI_ERROR (Status
)) {
2263 goto Error_Find_File
;
2266 Next_Path_Component
:
2267 Data
+= sizeof (UDF_PATH_COMPONENT
) + PathCompLength
;
2268 if (Data
>= EndData
) {
2272 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
2273 sizeof (UDF_FILE_INFO
)) != 0) {
2274 CleanupFileInformation (&PreviousFile
);
2277 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
2281 // Unmap the symlink file.
2283 FreePool (ReadFileInfo
.FileData
);
2288 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
2289 sizeof (UDF_FILE_INFO
)) != 0) {
2290 CleanupFileInformation (&PreviousFile
);
2293 FreePool (ReadFileInfo
.FileData
);
2299 Clean up in-memory UDF file information.
2301 @param[in] File File information pointer.
2305 CleanupFileInformation (
2306 IN UDF_FILE_INFO
*File
2309 if (File
->FileEntry
!= NULL
) {
2310 FreePool (File
->FileEntry
);
2312 if (File
->FileIdentifierDesc
!= NULL
) {
2313 FreePool ((VOID
*)File
->FileIdentifierDesc
);
2316 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
2320 Find a file from its absolute path on an UDF volume.
2322 @param[in] BlockIo BlockIo interface.
2323 @param[in] DiskIo DiskIo interface.
2324 @param[in] Volume UDF volume information structure.
2325 @param[in] File File information structure.
2326 @param[out] Size Size of the file.
2328 @retval EFI_SUCCESS File size calculated and set in Size.
2329 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2330 @retval EFI_NO_MEDIA The device has no media.
2331 @retval EFI_DEVICE_ERROR The device reported an error.
2332 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2333 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2339 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2340 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2341 IN UDF_VOLUME_INFO
*Volume
,
2342 IN UDF_FILE_INFO
*File
,
2347 UDF_READ_FILE_INFO ReadFileInfo
;
2349 ReadFileInfo
.Flags
= ReadFileGetFileSize
;
2355 &File
->FileIdentifierDesc
->Icb
,
2359 if (EFI_ERROR (Status
)) {
2363 *Size
= ReadFileInfo
.ReadLength
;
2369 Set information about a file on an UDF volume.
2371 @param[in] File File pointer.
2372 @param[in] FileSize Size of the file.
2373 @param[in] FileName Filename of the file.
2374 @param[in, out] BufferSize Size of the returned file infomation.
2375 @param[out] Buffer Data of the returned file information.
2377 @retval EFI_SUCCESS File information set.
2378 @retval EFI_NO_MEDIA The device has no media.
2379 @retval EFI_DEVICE_ERROR The device reported an error.
2380 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2381 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2387 IN UDF_FILE_INFO
*File
,
2389 IN CHAR16
*FileName
,
2390 IN OUT UINTN
*BufferSize
,
2394 UINTN FileInfoLength
;
2395 EFI_FILE_INFO
*FileInfo
;
2396 UDF_FILE_ENTRY
*FileEntry
;
2397 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
2398 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
2401 // Calculate the needed size for the EFI_FILE_INFO structure.
2403 FileInfoLength
= sizeof (EFI_FILE_INFO
) + ((FileName
!= NULL
) ?
2404 StrSize (FileName
) :
2406 if (*BufferSize
< FileInfoLength
) {
2408 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2410 *BufferSize
= FileInfoLength
;
2411 return EFI_BUFFER_TOO_SMALL
;
2415 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2416 // Now, fill it in with all necessary information about the file.
2418 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
2419 FileInfo
->Size
= FileInfoLength
;
2420 FileInfo
->Attribute
&= ~EFI_FILE_VALID_ATTR
;
2421 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
2423 if (IS_FID_DIRECTORY_FILE (File
->FileIdentifierDesc
)) {
2424 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
2425 } else if (IS_FID_NORMAL_FILE (File
->FileIdentifierDesc
)) {
2426 FileInfo
->Attribute
|= EFI_FILE_ARCHIVE
;
2429 if (IS_FID_HIDDEN_FILE (File
->FileIdentifierDesc
)) {
2430 FileInfo
->Attribute
|= EFI_FILE_HIDDEN
;
2433 DescriptorTag
= File
->FileEntry
;
2435 if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
2436 FileEntry
= (UDF_FILE_ENTRY
*)File
->FileEntry
;
2439 // Check if FE has the system attribute set.
2441 if (FileEntry
->IcbTag
.Flags
& (1 << 10)) {
2442 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2445 FileInfo
->FileSize
= FileSize
;
2446 FileInfo
->PhysicalSize
= FileSize
;
2448 FileInfo
->CreateTime
.Year
= FileEntry
->AccessTime
.Year
;
2449 FileInfo
->CreateTime
.Month
= FileEntry
->AccessTime
.Month
;
2450 FileInfo
->CreateTime
.Day
= FileEntry
->AccessTime
.Day
;
2451 FileInfo
->CreateTime
.Hour
= FileEntry
->AccessTime
.Hour
;
2452 FileInfo
->CreateTime
.Minute
= FileEntry
->AccessTime
.Second
;
2453 FileInfo
->CreateTime
.Second
= FileEntry
->AccessTime
.Second
;
2454 FileInfo
->CreateTime
.Nanosecond
=
2455 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2457 FileInfo
->LastAccessTime
.Year
=
2458 FileEntry
->AccessTime
.Year
;
2459 FileInfo
->LastAccessTime
.Month
=
2460 FileEntry
->AccessTime
.Month
;
2461 FileInfo
->LastAccessTime
.Day
=
2462 FileEntry
->AccessTime
.Day
;
2463 FileInfo
->LastAccessTime
.Hour
=
2464 FileEntry
->AccessTime
.Hour
;
2465 FileInfo
->LastAccessTime
.Minute
=
2466 FileEntry
->AccessTime
.Minute
;
2467 FileInfo
->LastAccessTime
.Second
=
2468 FileEntry
->AccessTime
.Second
;
2469 FileInfo
->LastAccessTime
.Nanosecond
=
2470 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2471 } else if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
2472 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)File
->FileEntry
;
2475 // Check if EFE has the system attribute set.
2477 if (ExtendedFileEntry
->IcbTag
.Flags
& (1 << 10)) {
2478 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2481 FileInfo
->FileSize
= FileSize
;
2482 FileInfo
->PhysicalSize
= FileSize
;
2484 FileInfo
->CreateTime
.Year
= ExtendedFileEntry
->CreationTime
.Year
;
2485 FileInfo
->CreateTime
.Month
= ExtendedFileEntry
->CreationTime
.Month
;
2486 FileInfo
->CreateTime
.Day
= ExtendedFileEntry
->CreationTime
.Day
;
2487 FileInfo
->CreateTime
.Hour
= ExtendedFileEntry
->CreationTime
.Hour
;
2488 FileInfo
->CreateTime
.Minute
= ExtendedFileEntry
->CreationTime
.Second
;
2489 FileInfo
->CreateTime
.Second
= ExtendedFileEntry
->CreationTime
.Second
;
2490 FileInfo
->CreateTime
.Nanosecond
=
2491 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2493 FileInfo
->LastAccessTime
.Year
=
2494 ExtendedFileEntry
->AccessTime
.Year
;
2495 FileInfo
->LastAccessTime
.Month
=
2496 ExtendedFileEntry
->AccessTime
.Month
;
2497 FileInfo
->LastAccessTime
.Day
=
2498 ExtendedFileEntry
->AccessTime
.Day
;
2499 FileInfo
->LastAccessTime
.Hour
=
2500 ExtendedFileEntry
->AccessTime
.Hour
;
2501 FileInfo
->LastAccessTime
.Minute
=
2502 ExtendedFileEntry
->AccessTime
.Minute
;
2503 FileInfo
->LastAccessTime
.Second
=
2504 ExtendedFileEntry
->AccessTime
.Second
;
2505 FileInfo
->LastAccessTime
.Nanosecond
=
2506 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2509 FileInfo
->CreateTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2510 FileInfo
->CreateTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2511 FileInfo
->LastAccessTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2512 FileInfo
->LastAccessTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2514 CopyMem ((VOID
*)&FileInfo
->ModificationTime
,
2515 (VOID
*)&FileInfo
->LastAccessTime
,
2518 if (FileName
!= NULL
) {
2519 StrCpyS (FileInfo
->FileName
, StrLen (FileName
) + 1, FileName
);
2521 FileInfo
->FileName
[0] = '\0';
2524 *BufferSize
= FileInfoLength
;
2530 Get volume and free space size information of an UDF volume.
2532 @param[in] BlockIo BlockIo interface.
2533 @param[in] DiskIo DiskIo interface.
2534 @param[in] Volume UDF volume information structure.
2535 @param[out] VolumeSize Volume size.
2536 @param[out] FreeSpaceSize Free space size.
2538 @retval EFI_SUCCESS Volume and free space size calculated.
2539 @retval EFI_NO_MEDIA The device has no media.
2540 @retval EFI_DEVICE_ERROR The device reported an error.
2541 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2542 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
2543 calculated due to lack of resources.
2548 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2549 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2550 IN UDF_VOLUME_INFO
*Volume
,
2551 OUT UINT64
*VolumeSize
,
2552 OUT UINT64
*FreeSpaceSize
2556 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
2557 UDF_EXTENT_AD
*ExtentAd
;
2559 UINT32 LogicalBlockSize
;
2560 UDF_LOGICAL_VOLUME_INTEGRITY
*LogicalVolInt
;
2561 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
2566 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
2568 ExtentAd
= &LogicalVolDesc
->IntegritySequenceExtent
;
2570 if (ExtentAd
->ExtentLength
== 0) {
2571 return EFI_VOLUME_CORRUPTED
;
2574 LogicalVolInt
= AllocatePool (ExtentAd
->ExtentLength
);
2575 if (LogicalVolInt
== NULL
) {
2576 return EFI_OUT_OF_RESOURCES
;
2580 // Get location of Logical Volume Integrity Descriptor
2582 Lsn
= (UINT64
)ExtentAd
->ExtentLocation
- Volume
->MainVdsStartLocation
;
2584 LogicalBlockSize
= LogicalVolDesc
->LogicalBlockSize
;
2589 Status
= DiskIo
->ReadDisk (
2591 BlockIo
->Media
->MediaId
,
2592 MultU64x32 (Lsn
, LogicalBlockSize
),
2593 ExtentAd
->ExtentLength
,
2596 if (EFI_ERROR (Status
)) {
2600 DescriptorTag
= &LogicalVolInt
->DescriptorTag
;
2603 // Check if read block is a Logical Volume Integrity Descriptor
2605 if (DescriptorTag
->TagIdentifier
!= UdfLogicalVolumeIntegrityDescriptor
) {
2606 Status
= EFI_VOLUME_CORRUPTED
;
2613 Length
= LogicalVolInt
->NumberOfPartitions
;
2614 for (Index
= 0; Index
< Length
; Index
+= sizeof (UINT32
)) {
2615 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2617 // Check if size is not specified
2619 if (LsnsNo
== 0xFFFFFFFFUL
) {
2623 // Accumulate free space size
2625 *FreeSpaceSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2628 Length
= LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
) * 2;
2629 for (; Index
< Length
; Index
+= sizeof (UINT32
)) {
2630 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2632 // Check if size is not specified
2634 if (LsnsNo
== 0xFFFFFFFFUL
) {
2638 // Accumulate used volume space
2640 *VolumeSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2643 Status
= EFI_SUCCESS
;
2647 // Free Logical Volume Integrity Descriptor
2649 FreePool (LogicalVolInt
);
2655 Seek a file and read its data into memory on an UDF volume.
2657 @param[in] BlockIo BlockIo interface.
2658 @param[in] DiskIo DiskIo interface.
2659 @param[in] Volume UDF volume information structure.
2660 @param[in] File File information structure.
2661 @param[in] FileSize Size of the file.
2662 @param[in, out] FilePosition File position.
2663 @param[in, out] Buffer File data.
2664 @param[in, out] BufferSize Read size.
2666 @retval EFI_SUCCESS File seeked and read.
2667 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2668 @retval EFI_NO_MEDIA The device has no media.
2669 @retval EFI_DEVICE_ERROR The device reported an error.
2670 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2671 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2677 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2678 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2679 IN UDF_VOLUME_INFO
*Volume
,
2680 IN UDF_FILE_INFO
*File
,
2682 IN OUT UINT64
*FilePosition
,
2683 IN OUT VOID
*Buffer
,
2684 IN OUT UINT64
*BufferSize
2688 UDF_READ_FILE_INFO ReadFileInfo
;
2690 ReadFileInfo
.Flags
= ReadFileSeekAndRead
;
2691 ReadFileInfo
.FilePosition
= *FilePosition
;
2692 ReadFileInfo
.FileData
= Buffer
;
2693 ReadFileInfo
.FileDataSize
= *BufferSize
;
2694 ReadFileInfo
.FileSize
= FileSize
;
2700 &File
->FileIdentifierDesc
->Icb
,
2704 if (EFI_ERROR (Status
)) {
2708 *BufferSize
= ReadFileInfo
.FileDataSize
;
2709 *FilePosition
= ReadFileInfo
.FilePosition
;
2715 Check if ControllerHandle supports an UDF file system.
2717 @param[in] This Protocol instance pointer.
2718 @param[in] ControllerHandle Handle of device to test.
2720 @retval EFI_SUCCESS UDF file system found.
2721 @retval EFI_UNSUPPORTED UDF file system not found.
2725 SupportUdfFileSystem (
2726 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2727 IN EFI_HANDLE ControllerHandle
2731 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2732 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2733 EFI_DEVICE_PATH_PROTOCOL
*LastDevicePathNode
;
2734 EFI_GUID
*VendorDefinedGuid
;
2737 // Open Device Path protocol on ControllerHandle
2739 Status
= gBS
->OpenProtocol (
2741 &gEfiDevicePathProtocolGuid
,
2742 (VOID
**)&DevicePath
,
2743 This
->DriverBindingHandle
,
2745 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2747 if (EFI_ERROR (Status
)) {
2748 return EFI_UNSUPPORTED
;
2751 Status
= EFI_UNSUPPORTED
;
2754 // Get last Device Path node
2756 LastDevicePathNode
= NULL
;
2757 DevicePathNode
= DevicePath
;
2758 while (!IsDevicePathEnd (DevicePathNode
)) {
2759 LastDevicePathNode
= DevicePathNode
;
2760 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
2763 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2764 // of an UDF file system.
2766 if (LastDevicePathNode
!= NULL
&&
2767 DevicePathType (LastDevicePathNode
) == MEDIA_DEVICE_PATH
&&
2768 DevicePathSubType (LastDevicePathNode
) == MEDIA_VENDOR_DP
) {
2769 VendorDefinedGuid
= (EFI_GUID
*)((UINTN
)LastDevicePathNode
+
2770 OFFSET_OF (VENDOR_DEVICE_PATH
, Guid
));
2771 if (CompareGuid (VendorDefinedGuid
, &gUdfDevPathGuid
)) {
2772 Status
= EFI_SUCCESS
;
2777 // Close Device Path protocol on ControllerHandle
2779 gBS
->CloseProtocol (
2781 &gEfiDevicePathProtocolGuid
,
2782 This
->DriverBindingHandle
,