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 SPDX-License-Identifier: BSD-2-Clause-Patent
13 // Vendor-Defined Device Path GUID for UDF file system
15 EFI_GUID gUdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
18 Find the anchor volume descriptor pointer.
20 @param[in] BlockIo BlockIo interface.
21 @param[in] DiskIo DiskIo interface.
22 @param[out] AnchorPoint Anchor volume descriptor pointer.
24 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
25 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
26 @retval other Anchor volume descriptor pointer not found.
30 FindAnchorVolumeDescriptorPointer (
31 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
32 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
33 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
39 EFI_LBA DescriptorLBAs
[4];
41 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
43 BlockSize
= BlockIo
->Media
->BlockSize
;
44 EndLBA
= BlockIo
->Media
->LastBlock
;
45 DescriptorLBAs
[0] = 256;
46 DescriptorLBAs
[1] = EndLBA
- 256;
47 DescriptorLBAs
[2] = EndLBA
;
48 DescriptorLBAs
[3] = 512;
50 for (Index
= 0; Index
< ARRAY_SIZE (DescriptorLBAs
); Index
++) {
51 Status
= DiskIo
->ReadDisk (
53 BlockIo
->Media
->MediaId
,
54 MultU64x32 (DescriptorLBAs
[Index
], BlockSize
),
55 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
),
58 if (EFI_ERROR (Status
)) {
62 DescriptorTag
= &AnchorPoint
->DescriptorTag
;
65 // Check if read LBA has a valid AVDP descriptor.
67 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
75 return EFI_VOLUME_CORRUPTED
;
79 Save the content of Logical Volume Descriptors and Partitions Descriptors in
82 @param[in] BlockIo BlockIo interface.
83 @param[in] DiskIo DiskIo interface.
84 @param[in] AnchorPoint Anchor volume descriptor pointer.
85 @param[out] Volume UDF volume information structure.
87 @retval EFI_SUCCESS The descriptors were saved.
88 @retval EFI_OUT_OF_RESOURCES The descriptors were not saved due to lack of
90 @retval other The descriptors were not saved due to
95 StartMainVolumeDescriptorSequence (
96 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
97 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
98 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
99 OUT UDF_VOLUME_INFO
*Volume
104 UDF_EXTENT_AD
*ExtentAd
;
105 EFI_LBA SeqStartBlock
;
107 BOOLEAN StopSequence
;
109 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
110 UINT32 LogicalBlockSize
;
112 BlockSize
= BlockIo
->Media
->BlockSize
;
113 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
116 // Allocate buffer for reading disk blocks
118 Buffer
= AllocateZeroPool ((UINTN
)BlockSize
);
119 if (Buffer
== NULL
) {
120 return EFI_OUT_OF_RESOURCES
;
124 // The logical partition created by Partition driver is relative to the main
125 // VDS extent location, so we start the Main Volume Descriptor Sequence at
128 // We don't need to check again if we have valid Volume Descriptors here since
129 // Partition driver already did.
132 SeqEndBlock
= SeqStartBlock
+ DivU64x32 (
133 (UINT64
)ExtentAd
->ExtentLength
,
136 StopSequence
= FALSE
;
137 for ( ; SeqStartBlock
< SeqEndBlock
&& !StopSequence
; SeqStartBlock
++) {
141 Status
= BlockIo
->ReadBlocks (
143 BlockIo
->Media
->MediaId
,
148 if (EFI_ERROR (Status
)) {
152 DescriptorTag
= Buffer
;
154 switch (DescriptorTag
->TagIdentifier
) {
155 case UdfPartitionDescriptor
:
157 // Save Partition Descriptor
159 CopyMem (&Volume
->PartitionDesc
, Buffer
, sizeof (Volume
->PartitionDesc
));
162 case UdfLogicalVolumeDescriptor
:
164 // Save Logical Volume Descriptor
166 CopyMem (&Volume
->LogicalVolDesc
, Buffer
, sizeof (Volume
->LogicalVolDesc
));
169 case UdfTerminatingDescriptor
:
179 // Determine FE (File Entry) size
181 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
182 if (LogicalBlockSize
>= UDF_LOGICAL_SECTOR_SIZE
) {
183 Volume
->FileEntrySize
= (UINTN
)LogicalBlockSize
;
185 Volume
->FileEntrySize
= UDF_LOGICAL_SECTOR_SIZE
;
188 Status
= EFI_SUCCESS
;
192 // Free block read buffer
200 Return a Partition Descriptor given a Long Allocation Descriptor. This is
201 necessary to calculate the right extent (LongAd) offset which is added up
202 with partition's starting location.
204 @param[in] Volume Volume information pointer.
205 @param[in] LongAd Long Allocation Descriptor pointer.
207 @return A pointer to a Partition Descriptor.
210 UDF_PARTITION_DESCRIPTOR
*
212 IN UDF_VOLUME_INFO
*Volume
,
213 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
216 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
219 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
221 switch (LogicalVolDesc
->DomainIdentifier
.Suffix
.Domain
.UdfRevision
) {
229 // UDF 1.02 specification:
231 // There shall be exactly one prevailing Logical Volume Descriptor recorded
232 // per Volume Set. The Partition Maps field shall contain only Type 1
235 // UDF 1.50 through 2.60 specs say:
237 // For the purpose of interchange partition maps shall be limited to
238 // Partition Map type 1, except type 2 maps as described in the document.
240 // NOTE: Only one Type 1 (Physical) Partition is supported. It has been
241 // checked already in Partition driver for existence of a single Type 1
242 // Partition map. Hence, the 'PartitionReferenceNumber' field (the index
243 // used to access Partition Maps data within the Logical Volume Descriptor)
244 // in the Long Allocation Descriptor should be 0 to indicate there is only
247 if (LongAd
->ExtentLocation
.PartitionReferenceNumber
!= 0) {
252 // Since only one partition, get the first one directly.
254 PartitionNum
= *(UINT16
*)((UINTN
)&LogicalVolDesc
->PartitionMaps
[4]);
259 // Unsupported UDF revision
265 // Check if partition number matches Partition Descriptor found in Main Volume
266 // Descriptor Sequence.
268 if (Volume
->PartitionDesc
.PartitionNumber
== PartitionNum
) {
269 return &Volume
->PartitionDesc
;
276 Return logical sector number of a given Long Allocation Descriptor.
278 @param[in] Volume Volume information pointer.
279 @param[in] LongAd Long Allocation Descriptor pointer.
280 @param[out] Lsn Logical sector number pointer.
282 @retval EFI_SUCCESS Logical sector number successfully returned.
283 @retval EFI_UNSUPPORTED Logical sector number is not returned due to
289 IN UDF_VOLUME_INFO
*Volume
,
290 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
,
294 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
296 PartitionDesc
= GetPdFromLongAd (Volume
, LongAd
);
297 if (PartitionDesc
== NULL
) {
300 "%a: Fail to get the Partition Descriptor from the given Long Allocation Descriptor.\n",
303 return EFI_UNSUPPORTED
;
306 *Lsn
= (UINT64
)PartitionDesc
->PartitionStartingLocation
-
307 Volume
->MainVdsStartLocation
+
308 LongAd
->ExtentLocation
.LogicalBlockNumber
;
314 Return logical sector number of a given Short Allocation Descriptor.
316 @param[in] Volume Volume pointer.
317 @param[in] PartitionDesc Partition Descriptor pointer.
318 @param[in] ShortAd Short Allocation Descriptor pointer.
320 @return The logical sector number of a given Short Allocation Descriptor.
325 IN UDF_VOLUME_INFO
*Volume
,
326 IN UDF_PARTITION_DESCRIPTOR
*PartitionDesc
,
327 IN UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
330 return (UINT64
)PartitionDesc
->PartitionStartingLocation
-
331 Volume
->MainVdsStartLocation
+ ShortAd
->ExtentPosition
;
335 Find File Set Descriptor of a given Logical Volume Descriptor.
337 The found FSD will contain the extent (LogicalVolumeContentsUse) where our
340 @param[in] BlockIo BlockIo interface.
341 @param[in] DiskIo DiskIo interface.
342 @param[in] Volume Volume information pointer.
344 @retval EFI_SUCCESS File Set Descriptor pointer found.
345 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
346 @retval other File Set Descriptor pointer not found.
350 FindFileSetDescriptor (
351 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
352 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
353 IN UDF_VOLUME_INFO
*Volume
358 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
359 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
361 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
362 Status
= GetLongAdLsn (Volume
, &LogicalVolDesc
->LogicalVolumeContentsUse
, &Lsn
);
363 if (EFI_ERROR (Status
)) {
368 // As per UDF 2.60 specification:
370 // There shall be exactly one File Set Descriptor recorded per Logical
375 Status
= DiskIo
->ReadDisk (
377 BlockIo
->Media
->MediaId
,
378 MultU64x32 (Lsn
, LogicalVolDesc
->LogicalBlockSize
),
379 sizeof (Volume
->FileSetDesc
),
382 if (EFI_ERROR (Status
)) {
386 DescriptorTag
= &Volume
->FileSetDesc
.DescriptorTag
;
389 // Check if read block is a File Set Descriptor
391 if (DescriptorTag
->TagIdentifier
!= UdfFileSetDescriptor
) {
392 return EFI_VOLUME_CORRUPTED
;
399 Read Volume and File Structure on an UDF file system.
401 @param[in] BlockIo BlockIo interface.
402 @param[in] DiskIo DiskIo interface.
403 @param[out] Volume Volume information pointer.
405 @retval EFI_SUCCESS Volume and File Structure were read.
406 @retval other Volume and File Structure were not read.
410 ReadVolumeFileStructure (
411 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
412 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
413 OUT UDF_VOLUME_INFO
*Volume
417 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
418 UDF_EXTENT_AD
*ExtentAd
;
421 // Find Anchor Volume Descriptor Pointer
423 Status
= FindAnchorVolumeDescriptorPointer (
428 if (EFI_ERROR (Status
)) {
433 // Save Main VDS start block number
435 ExtentAd
= &AnchorPoint
.MainVolumeDescriptorSequenceExtent
;
437 Volume
->MainVdsStartLocation
= (UINT64
)ExtentAd
->ExtentLocation
;
440 // Start Main Volume Descriptor Sequence.
442 Status
= StartMainVolumeDescriptorSequence (
448 if (EFI_ERROR (Status
)) {
456 Calculate length of a given File Identifier Descriptor.
458 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
460 @return The length of a given File Identifier Descriptor.
464 GetFidDescriptorLength (
465 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
469 (INTN
)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR
, Data
[0]) + 3 +
470 FileIdentifierDesc
->LengthOfFileIdentifier
+
471 FileIdentifierDesc
->LengthOfImplementationUse
) >> 2) << 2
476 Duplicate a given File Identifier Descriptor.
478 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
479 @param[out] NewFileIdentifierDesc The duplicated File Identifier Descriptor.
484 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
485 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**NewFileIdentifierDesc
488 *NewFileIdentifierDesc
=
489 (UDF_FILE_IDENTIFIER_DESCRIPTOR
*)AllocateCopyPool (
490 (UINTN
)GetFidDescriptorLength (FileIdentifierDesc
),
496 Duplicate either a given File Entry or a given Extended File Entry.
498 @param[in] BlockIo BlockIo interface.
499 @param[in] Volume Volume information pointer.
500 @param[in] FileEntry (Extended) File Entry pointer.
501 @param[out] NewFileEntry The duplicated (Extended) File Entry.
506 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
507 IN UDF_VOLUME_INFO
*Volume
,
509 OUT VOID
**NewFileEntry
512 *NewFileEntry
= AllocateCopyPool (Volume
->FileEntrySize
, FileEntry
);
516 Get raw data + length of a given File Entry or Extended File Entry.
518 The file's recorded data can contain either real file content (inline) or
519 a sequence of extents (or Allocation Descriptors) which tells where file's
520 content is stored in.
522 NOTE: The FE/EFE can be thought it was an inode.
524 @attention This is boundary function that may receive untrusted input.
525 @attention The input is from FileSystem.
527 The (Extended) File Entry is external input, so this routine will do basic
528 validation for (Extended) File Entry and report status.
530 @param[in] FileEntryData (Extended) File Entry pointer.
531 @param[in] FileEntrySize Size of the (Extended) File Entry specified
533 @param[out] Data Buffer contains the raw data of a given
534 (Extended) File Entry.
535 @param[out] Length Length of the data in Buffer.
537 @retval EFI_SUCCESS Raw data and size of the FE/EFE was read.
538 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
543 IN VOID
*FileEntryData
,
544 IN UINTN FileEntrySize
,
549 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
550 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
551 UDF_FILE_ENTRY
*FileEntry
;
553 DescriptorTag
= FileEntryData
;
555 if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
556 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
558 *Length
= ExtendedFileEntry
->InformationLength
;
559 *Data
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
560 ExtendedFileEntry
->LengthOfExtendedAttributes
);
561 } else if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
562 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
564 *Length
= FileEntry
->InformationLength
;
565 *Data
= (VOID
*)((UINT8
*)FileEntry
->Data
+
566 FileEntry
->LengthOfExtendedAttributes
);
569 if ((*Length
> FileEntrySize
) ||
570 ((UINTN
)FileEntryData
> (UINTN
)(*Data
)) ||
571 ((UINTN
)(*Data
) - (UINTN
)FileEntryData
> FileEntrySize
- *Length
))
573 return EFI_VOLUME_CORRUPTED
;
580 Get Allocation Descriptors' data information from a given FE/EFE.
582 @attention This is boundary function that may receive untrusted input.
583 @attention The input is from FileSystem.
585 The (Extended) File Entry is external input, so this routine will do basic
586 validation for (Extended) File Entry and report status.
588 @param[in] FileEntryData (Extended) File Entry pointer.
589 @param[in] FileEntrySize Size of the (Extended) File Entry specified
591 @param[out] AdsData Buffer contains the Allocation Descriptors'
592 data from a given FE/EFE.
593 @param[out] Length Length of the data in AdsData.
595 @retval EFI_SUCCESS The data and size of Allocation Descriptors
596 were read from the FE/EFE.
597 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
602 IN VOID
*FileEntryData
,
603 IN UINTN FileEntrySize
,
608 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
609 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
610 UDF_FILE_ENTRY
*FileEntry
;
612 DescriptorTag
= FileEntryData
;
614 if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
615 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
617 *Length
= ExtendedFileEntry
->LengthOfAllocationDescriptors
;
618 *AdsData
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
619 ExtendedFileEntry
->LengthOfExtendedAttributes
);
620 } else if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
621 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
623 *Length
= FileEntry
->LengthOfAllocationDescriptors
;
624 *AdsData
= (VOID
*)((UINT8
*)FileEntry
->Data
+
625 FileEntry
->LengthOfExtendedAttributes
);
628 if ((*Length
> FileEntrySize
) ||
629 ((UINTN
)FileEntryData
> (UINTN
)(*AdsData
)) ||
630 ((UINTN
)(*AdsData
) - (UINTN
)FileEntryData
> FileEntrySize
- *Length
))
632 return EFI_VOLUME_CORRUPTED
;
639 Read next Long Allocation Descriptor from a given file's data.
641 @param[in] Data File's data pointer.
642 @param[in,out] Offset Starting offset of the File's data to read.
643 @param[in] Length Length of the data to read.
644 @param[out] FoundLongAd Long Allocation Descriptor pointer.
646 @retval EFI_SUCCESS A Long Allocation Descriptor was found.
647 @retval EFI_DEVICE_ERROR No more Long Allocation Descriptors.
653 IN OUT UINT64
*Offset
,
655 OUT UDF_LONG_ALLOCATION_DESCRIPTOR
**FoundLongAd
658 UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
;
659 UDF_EXTENT_FLAGS ExtentFlags
;
662 if (*Offset
>= Length
) {
664 // No more Long Allocation Descriptors.
666 return EFI_DEVICE_ERROR
;
670 (UDF_LONG_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
673 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
674 // allocated AD, then return it.
676 ExtentFlags
= GET_EXTENT_FLAGS (LongAdsSequence
, LongAd
);
677 if ((ExtentFlags
== ExtentIsNextExtent
) ||
678 (ExtentFlags
== ExtentRecordedAndAllocated
))
684 // This AD is either not recorded but allocated, or not recorded and not
685 // allocated. Skip it.
687 *Offset
+= AD_LENGTH (LongAdsSequence
);
690 *FoundLongAd
= LongAd
;
696 Read next Short Allocation Descriptor from a given file's data.
698 @param[in] Data File's data pointer.
699 @param[in,out] Offset Starting offset of the File's data to read.
700 @param[in] Length Length of the data to read.
701 @param[out] FoundShortAd Short Allocation Descriptor pointer.
703 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
704 @retval EFI_DEVICE_ERROR No more Short Allocation Descriptors.
710 IN OUT UINT64
*Offset
,
712 OUT UDF_SHORT_ALLOCATION_DESCRIPTOR
**FoundShortAd
715 UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
;
716 UDF_EXTENT_FLAGS ExtentFlags
;
719 if (*Offset
>= Length
) {
721 // No more Short Allocation Descriptors.
723 return EFI_DEVICE_ERROR
;
727 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
730 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
731 // allocated AD, then return it.
733 ExtentFlags
= GET_EXTENT_FLAGS (ShortAdsSequence
, ShortAd
);
734 if ((ExtentFlags
== ExtentIsNextExtent
) ||
735 (ExtentFlags
== ExtentRecordedAndAllocated
))
741 // This AD is either not recorded but allocated, or not recorded and not
742 // allocated. Skip it.
744 *Offset
+= AD_LENGTH (ShortAdsSequence
);
747 *FoundShortAd
= ShortAd
;
753 Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
756 @param[in] RecordingFlags Flag to indicate the type of descriptor.
757 @param[in] Data File's data pointer.
758 @param[in,out] Offset Starting offset of the File's data to read.
759 @param[in] Length Length of the data to read.
760 @param[out] FoundAd Allocation Descriptor pointer.
762 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
763 @retval EFI_DEVICE_ERROR No more Allocation Descriptors.
764 Invalid type of descriptor was given.
768 GetAllocationDescriptor (
769 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
771 IN OUT UINT64
*Offset
,
776 if (RecordingFlags
== LongAdsSequence
) {
777 return GetLongAdFromAds (
781 (UDF_LONG_ALLOCATION_DESCRIPTOR
**)FoundAd
783 } else if (RecordingFlags
== ShortAdsSequence
) {
784 return GetShortAdFromAds (
788 (UDF_SHORT_ALLOCATION_DESCRIPTOR
**)FoundAd
793 // Code should never reach here.
796 return EFI_DEVICE_ERROR
;
800 Return logical sector number of either Short or Long Allocation Descriptor.
802 @param[in] RecordingFlags Flag to indicate the type of descriptor.
803 @param[in] Volume Volume information pointer.
804 @param[in] ParentIcb Long Allocation Descriptor pointer.
805 @param[in] Ad Allocation Descriptor pointer.
806 @param[out] Lsn Logical sector number pointer.
808 @retval EFI_SUCCESS Logical sector number of the given Allocation
809 Descriptor successfully returned.
810 @retval EFI_UNSUPPORTED Logical sector number of the given Allocation
811 Descriptor is not returned due to unrecognized
816 GetAllocationDescriptorLsn (
817 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
818 IN UDF_VOLUME_INFO
*Volume
,
819 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
824 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
826 if (RecordingFlags
== LongAdsSequence
) {
827 return GetLongAdLsn (Volume
, (UDF_LONG_ALLOCATION_DESCRIPTOR
*)Ad
, Lsn
);
828 } else if (RecordingFlags
== ShortAdsSequence
) {
829 PartitionDesc
= GetPdFromLongAd (Volume
, ParentIcb
);
830 if (PartitionDesc
== NULL
) {
831 return EFI_UNSUPPORTED
;
834 *Lsn
= GetShortAdLsn (
837 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)Ad
843 // Code should never reach here.
846 return EFI_UNSUPPORTED
;
850 Return offset + length of a given indirect Allocation Descriptor (AED).
852 @param[in] BlockIo BlockIo interface.
853 @param[in] DiskIo DiskIo interface.
854 @param[in] Volume Volume information pointer.
855 @param[in] ParentIcb Long Allocation Descriptor pointer.
856 @param[in] RecordingFlags Flag to indicate the type of descriptor.
857 @param[in] Ad Allocation Descriptor pointer.
858 @param[out] Offset Offset of a given indirect Allocation
860 @param[out] Length Length of a given indirect Allocation
863 @retval EFI_SUCCESS The offset and length were returned.
864 @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due
865 to lack of resources.
866 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
867 @retval other The offset and length were not returned.
872 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
873 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
874 IN UDF_VOLUME_INFO
*Volume
,
875 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
876 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
886 UINT32 LogicalBlockSize
;
887 UDF_ALLOCATION_EXTENT_DESCRIPTOR
*AllocExtDesc
;
888 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
890 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
891 Status
= GetAllocationDescriptorLsn (
898 if (EFI_ERROR (Status
)) {
902 Data
= AllocatePool (ExtentLength
);
904 return EFI_OUT_OF_RESOURCES
;
907 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
912 Status
= DiskIo
->ReadDisk (
914 BlockIo
->Media
->MediaId
,
915 MultU64x32 (Lsn
, LogicalBlockSize
),
919 if (EFI_ERROR (Status
)) {
923 AllocExtDesc
= (UDF_ALLOCATION_EXTENT_DESCRIPTOR
*)Data
;
925 DescriptorTag
= &AllocExtDesc
->DescriptorTag
;
928 // Check if read extent contains a valid tag identifier for AED.
930 if (DescriptorTag
->TagIdentifier
!= UdfAllocationExtentDescriptor
) {
931 Status
= EFI_VOLUME_CORRUPTED
;
936 // Get AED's block offset and its length.
938 *Offset
= MultU64x32 (Lsn
, LogicalBlockSize
) +
939 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR
);
940 *Length
= AllocExtDesc
->LengthOfAllocationDescriptors
;
949 Read Allocation Extent Descriptor into memory.
951 @param[in] BlockIo BlockIo interface.
952 @param[in] DiskIo DiskIo interface.
953 @param[in] Volume Volume information pointer.
954 @param[in] ParentIcb Long Allocation Descriptor pointer.
955 @param[in] RecordingFlags Flag to indicate the type of descriptor.
956 @param[in] Ad Allocation Descriptor pointer.
957 @param[out] Data Buffer that contains the Allocation Extent
959 @param[out] Length Length of Data.
961 @retval EFI_SUCCESS The Allocation Extent Descriptor was read.
962 @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read
963 due to lack of resources.
964 @retval other Fail to read the disk.
969 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
970 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
971 IN UDF_VOLUME_INFO
*Volume
,
972 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
973 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
983 // Get AED's offset + length.
985 Status
= GetAedAdsOffset (
995 if (EFI_ERROR (Status
)) {
1000 // Allocate buffer to read in AED's data.
1002 *Data
= AllocatePool ((UINTN
)(*Length
));
1003 if (*Data
== NULL
) {
1004 return EFI_OUT_OF_RESOURCES
;
1007 return DiskIo
->ReadDisk (
1009 BlockIo
->Media
->MediaId
,
1017 Function used to serialise reads of Allocation Descriptors.
1019 @param[in] RecordingFlags Flag to indicate the type of descriptor.
1020 @param[in] Ad Allocation Descriptor pointer.
1021 @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.
1022 @param[in] Length Length of Buffer.
1024 @retval EFI_SUCCESS Buffer was grown to hold the next Allocation
1026 @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.
1030 GrowUpBufferToNextAd (
1031 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
1033 IN OUT VOID
**Buffer
,
1037 UINT32 ExtentLength
;
1039 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1041 if (*Buffer
== NULL
) {
1042 *Buffer
= AllocatePool (ExtentLength
);
1043 if (*Buffer
== NULL
) {
1044 return EFI_OUT_OF_RESOURCES
;
1047 *Buffer
= ReallocatePool ((UINTN
)Length
, (UINTN
)(Length
+ ExtentLength
), *Buffer
);
1048 if (*Buffer
== NULL
) {
1049 return EFI_OUT_OF_RESOURCES
;
1057 Read data or size of either a File Entry or an Extended File Entry.
1059 @param[in] BlockIo BlockIo interface.
1060 @param[in] DiskIo DiskIo interface.
1061 @param[in] Volume Volume information pointer.
1062 @param[in] ParentIcb Long Allocation Descriptor pointer.
1063 @param[in] FileEntryData FE/EFE structure pointer.
1064 @param[in, out] ReadFileInfo Read file information pointer.
1066 @retval EFI_SUCCESS Data or size of a FE/EFE was read.
1067 @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to
1069 @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is
1071 @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData
1073 @retval other Data or size of a FE/EFE was not read.
1078 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1079 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1080 IN UDF_VOLUME_INFO
*Volume
,
1081 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1082 IN VOID
*FileEntryData
,
1083 IN OUT UDF_READ_FILE_INFO
*ReadFileInfo
1087 UINT32 LogicalBlockSize
;
1095 UINT64 FilePosition
;
1100 BOOLEAN FinishedSeeking
;
1101 UINT32 ExtentLength
;
1102 UDF_FE_RECORDING_FLAGS RecordingFlags
;
1104 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
1108 // set BytesLeft to suppress incorrect compiler/analyzer warnings
1113 FinishedSeeking
= FALSE
;
1116 switch (ReadFileInfo
->Flags
) {
1117 case ReadFileGetFileSize
:
1118 case ReadFileAllocateAndRead
:
1120 // Initialise ReadFileInfo structure for either getting file size, or
1121 // reading file's recorded data.
1123 ReadFileInfo
->ReadLength
= 0;
1124 ReadFileInfo
->FileData
= NULL
;
1126 case ReadFileSeekAndRead
:
1128 // About to seek a file and/or read its data.
1130 Length
= ReadFileInfo
->FileSize
- ReadFileInfo
->FilePosition
;
1131 if (ReadFileInfo
->FileDataSize
> Length
) {
1133 // About to read beyond the EOF -- truncate it.
1135 ReadFileInfo
->FileDataSize
= Length
;
1139 // Initialise data to start seeking and/or reading a file.
1141 BytesLeft
= ReadFileInfo
->FileDataSize
;
1144 FinishedSeeking
= FALSE
;
1149 RecordingFlags
= GET_FE_RECORDING_FLAGS (FileEntryData
);
1150 switch (RecordingFlags
) {
1153 // There are no extents for this FE/EFE. All data is inline.
1155 Status
= GetFileEntryData (FileEntryData
, Volume
->FileEntrySize
, &Data
, &Length
);
1156 if (EFI_ERROR (Status
)) {
1160 if (ReadFileInfo
->Flags
== ReadFileGetFileSize
) {
1161 ReadFileInfo
->ReadLength
= Length
;
1162 } else if (ReadFileInfo
->Flags
== ReadFileAllocateAndRead
) {
1164 // Allocate buffer for starting read data.
1166 ReadFileInfo
->FileData
= AllocatePool ((UINTN
)Length
);
1167 if (ReadFileInfo
->FileData
== NULL
) {
1168 return EFI_OUT_OF_RESOURCES
;
1172 // Read all inline data into ReadFileInfo->FileData
1174 CopyMem (ReadFileInfo
->FileData
, Data
, (UINTN
)Length
);
1175 ReadFileInfo
->ReadLength
= Length
;
1176 } else if (ReadFileInfo
->Flags
== ReadFileSeekAndRead
) {
1178 // If FilePosition is non-zero, seek file to FilePosition, read
1179 // FileDataSize bytes and then updates FilePosition.
1182 ReadFileInfo
->FileData
,
1183 (VOID
*)((UINT8
*)Data
+ ReadFileInfo
->FilePosition
),
1184 (UINTN
)ReadFileInfo
->FileDataSize
1187 ReadFileInfo
->FilePosition
+= ReadFileInfo
->FileDataSize
;
1190 return EFI_INVALID_PARAMETER
;
1193 Status
= EFI_SUCCESS
;
1196 case LongAdsSequence
:
1197 case ShortAdsSequence
:
1199 // This FE/EFE contains a run of Allocation Descriptors. Get data + size
1200 // for start reading them out.
1202 Status
= GetAdsInformation (FileEntryData
, Volume
->FileEntrySize
, &Data
, &Length
);
1203 if (EFI_ERROR (Status
)) {
1213 Status
= GetAllocationDescriptor (
1220 if (Status
== EFI_DEVICE_ERROR
) {
1221 Status
= EFI_SUCCESS
;
1226 // Check if AD is an indirect AD. If so, read Allocation Extent
1227 // Descriptor and its extents (ADs).
1229 if (GET_EXTENT_FLAGS (RecordingFlags
, Ad
) == ExtentIsNextExtent
) {
1231 Status
= GetAedAdsData (
1248 if (EFI_ERROR (Status
)) {
1252 ASSERT (Data
!= NULL
);
1258 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1260 Status
= GetAllocationDescriptorLsn (
1267 if (EFI_ERROR (Status
)) {
1271 switch (ReadFileInfo
->Flags
) {
1272 case ReadFileGetFileSize
:
1273 ReadFileInfo
->ReadLength
+= ExtentLength
;
1275 case ReadFileAllocateAndRead
:
1277 // Increase FileData (if necessary) to read next extent.
1279 Status
= GrowUpBufferToNextAd (
1282 &ReadFileInfo
->FileData
,
1283 ReadFileInfo
->ReadLength
1285 if (EFI_ERROR (Status
)) {
1286 goto Error_Alloc_Buffer_To_Next_Ad
;
1290 // Read extent's data into FileData.
1292 Status
= DiskIo
->ReadDisk (
1294 BlockIo
->Media
->MediaId
,
1295 MultU64x32 (Lsn
, LogicalBlockSize
),
1297 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1298 ReadFileInfo
->ReadLength
)
1300 if (EFI_ERROR (Status
)) {
1301 goto Error_Read_Disk_Blk
;
1304 ReadFileInfo
->ReadLength
+= ExtentLength
;
1306 case ReadFileSeekAndRead
:
1308 // Seek file first before reading in its data.
1310 if (FinishedSeeking
) {
1312 goto Skip_File_Seek
;
1315 if (FilePosition
+ ExtentLength
< ReadFileInfo
->FilePosition
) {
1316 FilePosition
+= ExtentLength
;
1320 if (FilePosition
+ ExtentLength
> ReadFileInfo
->FilePosition
) {
1321 Offset
= ReadFileInfo
->FilePosition
- FilePosition
;
1327 // Done with seeking file. Start reading its data.
1329 FinishedSeeking
= TRUE
;
1333 // Make sure we don't read more data than really wanted.
1335 if (ExtentLength
- Offset
> BytesLeft
) {
1336 DataLength
= BytesLeft
;
1338 DataLength
= ExtentLength
- Offset
;
1342 // Read extent's data into FileData.
1344 Status
= DiskIo
->ReadDisk (
1346 BlockIo
->Media
->MediaId
,
1347 Offset
+ MultU64x32 (Lsn
, LogicalBlockSize
),
1349 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1352 if (EFI_ERROR (Status
)) {
1353 goto Error_Read_Disk_Blk
;
1357 // Update current file's position.
1359 DataOffset
+= DataLength
;
1360 ReadFileInfo
->FilePosition
+= DataLength
;
1362 BytesLeft
-= DataLength
;
1363 if (BytesLeft
== 0) {
1365 // There is no more file data to read.
1367 Status
= EFI_SUCCESS
;
1376 // Point to the next AD (extent).
1378 AdOffset
+= AD_LENGTH (RecordingFlags
);
1382 case ExtendedAdsSequence
:
1383 // FIXME: Not supported. Got no volume with it, yet.
1385 Status
= EFI_UNSUPPORTED
;
1390 // A flag value reserved by the ECMA-167 standard (3rd Edition - June
1391 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
1393 Status
= EFI_UNSUPPORTED
;
1404 Error_Read_Disk_Blk
:
1405 Error_Alloc_Buffer_To_Next_Ad
:
1406 if (ReadFileInfo
->Flags
!= ReadFileSeekAndRead
) {
1407 FreePool (ReadFileInfo
->FileData
);
1419 Find a file by its filename from a given Parent file.
1421 @param[in] BlockIo BlockIo interface.
1422 @param[in] DiskIo DiskIo interface.
1423 @param[in] Volume Volume information pointer.
1424 @param[in] FileName File name string.
1425 @param[in] Parent Parent directory file.
1426 @param[in] Icb Long Allocation Descriptor pointer.
1427 @param[out] File Found file.
1429 @retval EFI_SUCCESS The file was found.
1430 @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.
1431 @retval EFI_NOT_FOUND The file was not found.
1436 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1437 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1438 IN UDF_VOLUME_INFO
*Volume
,
1439 IN CHAR16
*FileName
,
1440 IN UDF_FILE_INFO
*Parent
,
1441 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1442 OUT UDF_FILE_INFO
*File
1446 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1447 UDF_READ_DIRECTORY_INFO ReadDirInfo
;
1449 CHAR16 FoundFileName
[UDF_FILENAME_LENGTH
];
1450 VOID
*CompareFileEntry
;
1453 // Check if both Parent->FileIdentifierDesc and Icb are NULL.
1455 if ((Parent
->FileIdentifierDesc
== NULL
) && (Icb
== NULL
)) {
1456 return EFI_INVALID_PARAMETER
;
1460 // Check if parent file is really directory.
1462 if (FE_ICB_FILE_TYPE (Parent
->FileEntry
) != UdfFileEntryDirectory
) {
1463 return EFI_NOT_FOUND
;
1467 // If FileName is current file or working directory, just duplicate Parent's
1468 // FE/EFE and FID descriptors.
1470 if (StrCmp (FileName
, L
".") == 0) {
1471 if (Parent
->FileIdentifierDesc
== NULL
) {
1472 return EFI_INVALID_PARAMETER
;
1475 DuplicateFe (BlockIo
, Volume
, Parent
->FileEntry
, &File
->FileEntry
);
1476 if (File
->FileEntry
== NULL
) {
1477 return EFI_OUT_OF_RESOURCES
;
1480 DuplicateFid (Parent
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1481 if (File
->FileIdentifierDesc
== NULL
) {
1482 FreePool (File
->FileEntry
);
1483 return EFI_OUT_OF_RESOURCES
;
1490 // Start directory listing.
1492 ZeroMem ((VOID
*)&ReadDirInfo
, sizeof (UDF_READ_DIRECTORY_INFO
));
1496 Status
= ReadDirectoryEntry (
1500 (Parent
->FileIdentifierDesc
!= NULL
) ?
1501 &Parent
->FileIdentifierDesc
->Icb
:
1507 if (EFI_ERROR (Status
)) {
1508 if (Status
== EFI_DEVICE_ERROR
) {
1509 Status
= EFI_NOT_FOUND
;
1516 // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is
1517 // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code
1518 // reaches here, 'FileIdentifierDesc' must be not NULL.
1520 // The ASSERT here is for addressing a false positive NULL pointer
1521 // dereference issue raised from static analysis.
1523 ASSERT (FileIdentifierDesc
!= NULL
);
1525 if (FileIdentifierDesc
->FileCharacteristics
& PARENT_FILE
) {
1527 // This FID contains the location (FE/EFE) of the parent directory of this
1528 // directory (Parent), and if FileName is either ".." or "\\", then it's
1529 // the expected FID.
1531 if ((StrCmp (FileName
, L
"..") == 0) || (StrCmp (FileName
, L
"\\") == 0)) {
1536 Status
= GetFileNameFromFid (FileIdentifierDesc
, ARRAY_SIZE (FoundFileName
), FoundFileName
);
1537 if (EFI_ERROR (Status
)) {
1541 if (StrCmp (FileName
, FoundFileName
) == 0) {
1543 // FID has been found. Prepare to find its respective FE/EFE.
1550 FreePool ((VOID
*)FileIdentifierDesc
);
1553 if (ReadDirInfo
.DirectoryData
!= NULL
) {
1555 // Free all allocated resources for the directory listing.
1557 FreePool (ReadDirInfo
.DirectoryData
);
1561 Status
= EFI_SUCCESS
;
1563 File
->FileIdentifierDesc
= FileIdentifierDesc
;
1566 // If the requested file is root directory, then the FE/EFE was already
1567 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1569 // Otherwise, find FE/EFE from the respective FID.
1571 if (StrCmp (FileName
, L
"\\") != 0) {
1572 Status
= FindFileEntry (
1576 &FileIdentifierDesc
->Icb
,
1579 if (EFI_ERROR (Status
)) {
1584 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1587 (VOID
*)Parent
->FileEntry
,
1588 (VOID
*)CompareFileEntry
,
1589 Volume
->FileEntrySize
1592 File
->FileEntry
= CompareFileEntry
;
1594 FreePool ((VOID
*)FileIdentifierDesc
);
1595 FreePool ((VOID
*)CompareFileEntry
);
1596 Status
= EFI_NOT_FOUND
;
1604 FreePool ((VOID
*)FileIdentifierDesc
);
1610 Read volume information on a medium which contains a valid UDF file system.
1612 @param[in] BlockIo BlockIo interface.
1613 @param[in] DiskIo DiskIo interface.
1614 @param[out] Volume UDF volume information structure.
1616 @retval EFI_SUCCESS Volume information read.
1617 @retval EFI_NO_MEDIA The device has no media.
1618 @retval EFI_DEVICE_ERROR The device reported an error.
1619 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1620 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1624 ReadUdfVolumeInformation (
1625 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1626 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1627 OUT UDF_VOLUME_INFO
*Volume
1633 // Read all necessary UDF volume information and keep it private to the driver
1635 Status
= ReadVolumeFileStructure (
1640 if (EFI_ERROR (Status
)) {
1645 // Find File Set Descriptor
1647 Status
= FindFileSetDescriptor (BlockIo
, DiskIo
, Volume
);
1648 if (EFI_ERROR (Status
)) {
1656 Find the root directory on an UDF volume.
1658 @param[in] BlockIo BlockIo interface.
1659 @param[in] DiskIo DiskIo interface.
1660 @param[in] Volume UDF volume information structure.
1661 @param[out] File Root directory file.
1663 @retval EFI_SUCCESS Root directory found.
1664 @retval EFI_NO_MEDIA The device has no media.
1665 @retval EFI_DEVICE_ERROR The device reported an error.
1666 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1667 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1673 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1674 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1675 IN UDF_VOLUME_INFO
*Volume
,
1676 OUT UDF_FILE_INFO
*File
1680 UDF_FILE_INFO Parent
;
1682 Status
= FindFileEntry (
1686 &Volume
->FileSetDesc
.RootDirectoryIcb
,
1689 if (EFI_ERROR (Status
)) {
1693 Parent
.FileEntry
= File
->FileEntry
;
1694 Parent
.FileIdentifierDesc
= NULL
;
1703 &Volume
->FileSetDesc
.RootDirectoryIcb
,
1706 if (EFI_ERROR (Status
)) {
1707 FreePool (File
->FileEntry
);
1714 Find either a File Entry or a Extended File Entry from a given ICB.
1716 @param[in] BlockIo BlockIo interface.
1717 @param[in] DiskIo DiskIo interface.
1718 @param[in] Volume UDF volume information structure.
1719 @param[in] Icb ICB of the FID.
1720 @param[out] FileEntry File Entry or Extended File Entry.
1722 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1723 @retval EFI_NO_MEDIA The device has no media.
1724 @retval EFI_DEVICE_ERROR The device reported an error.
1725 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1726 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1732 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1733 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1734 IN UDF_VOLUME_INFO
*Volume
,
1735 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1736 OUT VOID
**FileEntry
1741 UINT32 LogicalBlockSize
;
1742 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
1745 Status
= GetLongAdLsn (Volume
, Icb
, &Lsn
);
1746 if (EFI_ERROR (Status
)) {
1750 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
1752 ReadBuffer
= AllocateZeroPool (Volume
->FileEntrySize
);
1753 if (ReadBuffer
== NULL
) {
1754 return EFI_OUT_OF_RESOURCES
;
1760 Status
= DiskIo
->ReadDisk (
1762 BlockIo
->Media
->MediaId
,
1763 MultU64x32 (Lsn
, LogicalBlockSize
),
1764 Volume
->FileEntrySize
,
1767 if (EFI_ERROR (Status
)) {
1768 goto Error_Read_Disk_Blk
;
1771 DescriptorTag
= ReadBuffer
;
1774 // Check if the read extent contains a valid Tag Identifier for the expected
1777 if ((DescriptorTag
->TagIdentifier
!= UdfFileEntry
) &&
1778 (DescriptorTag
->TagIdentifier
!= UdfExtendedFileEntry
))
1780 Status
= EFI_VOLUME_CORRUPTED
;
1781 goto Error_Invalid_Fe
;
1784 *FileEntry
= ReadBuffer
;
1788 Error_Read_Disk_Blk
:
1789 FreePool (ReadBuffer
);
1795 Find a file given its absolute path on an UDF volume.
1797 @param[in] BlockIo BlockIo interface.
1798 @param[in] DiskIo DiskIo interface.
1799 @param[in] Volume UDF volume information structure.
1800 @param[in] FilePath File's absolute path.
1801 @param[in] Root Root directory file.
1802 @param[in] Parent Parent directory file.
1803 @param[in] Icb ICB of Parent.
1804 @param[out] File Found file.
1806 @retval EFI_SUCCESS FilePath was found.
1807 @retval EFI_NO_MEDIA The device has no media.
1808 @retval EFI_DEVICE_ERROR The device reported an error.
1809 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1810 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
1816 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1817 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1818 IN UDF_VOLUME_INFO
*Volume
,
1819 IN CHAR16
*FilePath
,
1820 IN UDF_FILE_INFO
*Root
,
1821 IN UDF_FILE_INFO
*Parent
,
1822 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1823 OUT UDF_FILE_INFO
*File
1827 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1828 CHAR16
*FileNamePointer
;
1829 UDF_FILE_INFO PreviousFile
;
1832 Status
= EFI_NOT_FOUND
;
1834 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1835 while (*FilePath
!= L
'\0') {
1836 FileNamePointer
= FileName
;
1837 while (*FilePath
!= L
'\0' && *FilePath
!= L
'\\') {
1838 if ((((UINTN
)FileNamePointer
- (UINTN
)FileName
) / sizeof (CHAR16
)) >=
1839 (ARRAY_SIZE (FileName
) - 1))
1841 return EFI_NOT_FOUND
;
1844 *FileNamePointer
++ = *FilePath
++;
1847 *FileNamePointer
= L
'\0';
1848 if (FileName
[0] == L
'\0') {
1850 // Open root directory.
1854 // There is no file found for the root directory yet. So, find only its
1857 // See UdfOpenVolume() function.
1859 Status
= InternalFindFile (
1870 // We've already a file pointer (Root) for the root directory. Duplicate
1871 // its FE/EFE and FID descriptors.
1873 Status
= EFI_SUCCESS
;
1874 DuplicateFe (BlockIo
, Volume
, Root
->FileEntry
, &File
->FileEntry
);
1875 if (File
->FileEntry
== NULL
) {
1876 Status
= EFI_OUT_OF_RESOURCES
;
1879 // File->FileEntry is not NULL.
1881 DuplicateFid (Root
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1882 if (File
->FileIdentifierDesc
== NULL
) {
1883 FreePool (File
->FileEntry
);
1884 Status
= EFI_OUT_OF_RESOURCES
;
1890 // No root directory. Find filename from the current directory.
1892 Status
= InternalFindFile (
1903 if (EFI_ERROR (Status
)) {
1908 // If the found file is a symlink, then find its respective FE/EFE and
1911 if (FE_ICB_FILE_TYPE (File
->FileEntry
) == UdfFileEntrySymlink
) {
1912 FreePool ((VOID
*)File
->FileIdentifierDesc
);
1914 FileEntry
= File
->FileEntry
;
1916 Status
= ResolveSymlink (
1925 FreePool (FileEntry
);
1927 if (EFI_ERROR (Status
)) {
1933 (VOID
*)&PreviousFile
,
1935 sizeof (UDF_FILE_INFO
)
1938 CleanupFileInformation (&PreviousFile
);
1941 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1942 if ((*FilePath
!= L
'\0') && (*FilePath
== L
'\\')) {
1951 Read a directory entry at a time on an UDF volume.
1953 @param[in] BlockIo BlockIo interface.
1954 @param[in] DiskIo DiskIo interface.
1955 @param[in] Volume UDF volume information structure.
1956 @param[in] ParentIcb ICB of the parent file.
1957 @param[in] FileEntryData FE/EFE of the parent file.
1958 @param[in, out] ReadDirInfo Next read directory listing structure
1960 @param[out] FoundFid File Identifier Descriptor pointer.
1962 @retval EFI_SUCCESS Directory entry read.
1963 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1964 @retval EFI_NO_MEDIA The device has no media.
1965 @retval EFI_DEVICE_ERROR The device reported an error.
1966 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1967 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1972 ReadDirectoryEntry (
1973 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1974 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1975 IN UDF_VOLUME_INFO
*Volume
,
1976 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1977 IN VOID
*FileEntryData
,
1978 IN OUT UDF_READ_DIRECTORY_INFO
*ReadDirInfo
,
1979 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**FoundFid
1983 UDF_READ_FILE_INFO ReadFileInfo
;
1984 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1986 if (ReadDirInfo
->DirectoryData
== NULL
) {
1988 // The directory's recorded data has not been read yet. So let's cache it
1989 // into memory and the next calls won't need to read it again.
1991 ReadFileInfo
.Flags
= ReadFileAllocateAndRead
;
2001 if (EFI_ERROR (Status
)) {
2006 // Fill in ReadDirInfo structure with the read directory's data information.
2008 ReadDirInfo
->DirectoryData
= ReadFileInfo
.FileData
;
2009 ReadDirInfo
->DirectoryLength
= ReadFileInfo
.ReadLength
;
2013 if (ReadDirInfo
->FidOffset
>= ReadDirInfo
->DirectoryLength
) {
2015 // There are no longer FIDs for this directory. By returning
2016 // EFI_DEVICE_ERROR to the callee will indicate end of directory
2019 return EFI_DEVICE_ERROR
;
2023 // Get FID for this entry.
2025 FileIdentifierDesc
= GET_FID_FROM_ADS (
2026 ReadDirInfo
->DirectoryData
,
2027 ReadDirInfo
->FidOffset
2030 // Update FidOffset to point to next FID.
2032 ReadDirInfo
->FidOffset
+= GetFidDescriptorLength (FileIdentifierDesc
);
2033 } while (FileIdentifierDesc
->FileCharacteristics
& DELETED_FILE
);
2035 DuplicateFid (FileIdentifierDesc
, FoundFid
);
2036 if (*FoundFid
== NULL
) {
2037 return EFI_OUT_OF_RESOURCES
;
2044 Get a filename (encoded in OSTA-compressed format) from a File Identifier
2045 Descriptor on an UDF volume.
2047 @attention This is boundary function that may receive untrusted input.
2048 @attention The input is from FileSystem.
2050 The File Identifier Descriptor is external input, so this routine will do
2051 basic validation for File Identifier Descriptor and report status.
2053 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
2054 @param[in] CharMax The maximum number of FileName Unicode char,
2055 including terminating null char.
2056 @param[out] FileName Decoded filename.
2058 @retval EFI_SUCCESS Filename decoded and read.
2059 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2060 @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
2064 GetFileNameFromFid (
2065 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
2067 OUT CHAR16
*FileName
2070 UINT8
*OstaCompressed
;
2071 UINT8 CompressionId
;
2074 CHAR16
*FileNameBak
;
2077 return EFI_BUFFER_TOO_SMALL
;
2082 (UINT8
*)FileIdentifierDesc
->Data
+
2083 FileIdentifierDesc
->LengthOfImplementationUse
2086 CompressionId
= OstaCompressed
[0];
2087 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2088 return EFI_VOLUME_CORRUPTED
;
2091 FileNameBak
= FileName
;
2096 Length
= FileIdentifierDesc
->LengthOfFileIdentifier
;
2097 if (CompressionId
== 16) {
2098 if (((UINTN
)Length
>> 1) > CharMax
) {
2099 return EFI_BUFFER_TOO_SMALL
;
2102 if ((Length
!= 0) && ((UINTN
)Length
- 1 > CharMax
)) {
2103 return EFI_BUFFER_TOO_SMALL
;
2107 for (Index
= 1; Index
< Length
; Index
++) {
2108 if (CompressionId
== 16) {
2109 *FileName
= OstaCompressed
[Index
++] << 8;
2114 if (Index
< Length
) {
2115 *FileName
|= (CHAR16
)(OstaCompressed
[Index
]);
2121 Index
= ((UINTN
)FileName
- (UINTN
)FileNameBak
) / sizeof (CHAR16
);
2122 if (Index
> CharMax
- 1) {
2123 Index
= CharMax
- 1;
2126 FileNameBak
[Index
] = L
'\0';
2132 Resolve a symlink file on an UDF volume.
2134 @attention This is boundary function that may receive untrusted input.
2135 @attention The input is from FileSystem.
2137 The Path Component is external input, so this routine will do basic
2138 validation for Path Component and report status.
2140 @param[in] BlockIo BlockIo interface.
2141 @param[in] DiskIo DiskIo interface.
2142 @param[in] Volume UDF volume information structure.
2143 @param[in] Parent Parent file.
2144 @param[in] FileEntryData FE/EFE structure pointer.
2145 @param[out] File Resolved file.
2147 @retval EFI_SUCCESS Symlink file resolved.
2148 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2149 @retval EFI_NO_MEDIA The device has no media.
2150 @retval EFI_DEVICE_ERROR The device reported an error.
2151 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2152 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
2158 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2159 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2160 IN UDF_VOLUME_INFO
*Volume
,
2161 IN UDF_FILE_INFO
*Parent
,
2162 IN VOID
*FileEntryData
,
2163 OUT UDF_FILE_INFO
*File
2167 UDF_READ_FILE_INFO ReadFileInfo
;
2171 UDF_PATH_COMPONENT
*PathComp
;
2172 UINT8 PathCompLength
;
2173 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
2176 UINT8 CompressionId
;
2177 UDF_FILE_INFO PreviousFile
;
2181 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
2184 // Symlink files on UDF volumes do not contain so much data other than
2185 // Path Components which resolves to real filenames, so it's OK to read in
2186 // all its data here -- usually the data will be inline with the FE/EFE for
2189 ReadFileInfo
.Flags
= ReadFileAllocateAndRead
;
2195 &Parent
->FileIdentifierDesc
->Icb
,
2199 if (EFI_ERROR (Status
)) {
2203 Length
= ReadFileInfo
.ReadLength
;
2205 Data
= (UINT8
*)ReadFileInfo
.FileData
;
2206 EndData
= Data
+ Length
;
2208 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
2211 PathComp
= (UDF_PATH_COMPONENT
*)Data
;
2213 PathCompLength
= PathComp
->LengthOfComponentIdentifier
;
2215 switch (PathComp
->ComponentType
) {
2218 // This Path Component specifies the root directory hierarchy subject to
2219 // agreement between the originator and recipient of the medium. Skip it.
2225 // "\\." of the current directory. Read next Path Component.
2227 goto Next_Path_Component
;
2230 // ".." (parent directory). Go to it.
2232 CopyMem ((VOID
*)FileName
, L
"..", 6);
2236 // "." (current file). Duplicate both FE/EFE and FID of this file.
2238 DuplicateFe (BlockIo
, Volume
, PreviousFile
.FileEntry
, &File
->FileEntry
);
2239 if (File
->FileEntry
== NULL
) {
2240 Status
= EFI_OUT_OF_RESOURCES
;
2241 goto Error_Find_File
;
2245 PreviousFile
.FileIdentifierDesc
,
2246 &File
->FileIdentifierDesc
2248 if (File
->FileIdentifierDesc
== NULL
) {
2249 FreePool (File
->FileEntry
);
2250 Status
= EFI_OUT_OF_RESOURCES
;
2251 goto Error_Find_File
;
2254 goto Next_Path_Component
;
2257 // This Path Component identifies an object, either a file or a
2258 // directory or an alias.
2260 // Decode it from the compressed data in ComponentIdentifier and find
2263 CompressionId
= PathComp
->ComponentIdentifier
[0];
2264 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2265 return EFI_VOLUME_CORRUPTED
;
2268 if ((UINTN
)PathComp
->ComponentIdentifier
+ PathCompLength
> (UINTN
)EndData
) {
2269 return EFI_VOLUME_CORRUPTED
;
2273 for (Index
= 1; Index
< PathCompLength
; Index
++) {
2274 if (CompressionId
== 16) {
2275 *Char
= *(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+
2279 if (Index
> ARRAY_SIZE (FileName
)) {
2280 return EFI_UNSUPPORTED
;
2286 if (Index
< Length
) {
2287 *Char
|= (CHAR16
)(*(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+ Index
));
2293 Index
= ((UINTN
)Char
- (UINTN
)FileName
) / sizeof (CHAR16
);
2294 if (Index
> ARRAY_SIZE (FileName
) - 1) {
2295 Index
= ARRAY_SIZE (FileName
) - 1;
2298 FileName
[Index
] = L
'\0';
2302 // According to the ECMA-167 standard (3rd Edition - June 1997), Section
2303 // 14.16.1.1, all other values are reserved.
2305 Status
= EFI_VOLUME_CORRUPTED
;
2306 goto Error_Find_File
;
2310 // Find file from the read filename in symlink's file data.
2312 Status
= InternalFindFile (
2321 if (EFI_ERROR (Status
)) {
2322 goto Error_Find_File
;
2325 Next_Path_Component
:
2326 Data
+= sizeof (UDF_PATH_COMPONENT
) + PathCompLength
;
2327 if (Data
>= EndData
) {
2332 // Check the content in the file info pointed by File.
2334 if ((File
->FileEntry
== NULL
) || (File
->FileIdentifierDesc
== NULL
)) {
2335 Status
= EFI_VOLUME_CORRUPTED
;
2336 goto Error_Find_File
;
2339 NotParent
= (CompareMem (
2340 (VOID
*)&PreviousFile
,
2342 sizeof (UDF_FILE_INFO
)
2344 NotFile
= (CompareMem (
2345 (VOID
*)&PreviousFile
,
2347 sizeof (UDF_FILE_INFO
)
2350 if (NotParent
&& NotFile
) {
2351 CleanupFileInformation (&PreviousFile
);
2355 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
2360 // Unmap the symlink file.
2362 FreePool (ReadFileInfo
.FileData
);
2365 // Check the content in the resolved file info.
2367 if ((File
->FileEntry
== NULL
) || (File
->FileIdentifierDesc
== NULL
)) {
2368 return EFI_VOLUME_CORRUPTED
;
2375 (VOID
*)&PreviousFile
,
2377 sizeof (UDF_FILE_INFO
)
2380 CleanupFileInformation (&PreviousFile
);
2383 FreePool (ReadFileInfo
.FileData
);
2389 Clean up in-memory UDF file information.
2391 @param[in] File File information pointer.
2395 CleanupFileInformation (
2396 IN UDF_FILE_INFO
*File
2399 if (File
->FileEntry
!= NULL
) {
2400 FreePool (File
->FileEntry
);
2403 if (File
->FileIdentifierDesc
!= NULL
) {
2404 FreePool ((VOID
*)File
->FileIdentifierDesc
);
2407 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
2411 Find a file from its absolute path on an UDF volume.
2413 @param[in] BlockIo BlockIo interface.
2414 @param[in] DiskIo DiskIo interface.
2415 @param[in] Volume UDF volume information structure.
2416 @param[in] File File information structure.
2417 @param[out] Size Size of the file.
2419 @retval EFI_SUCCESS File size calculated and set in Size.
2420 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2421 @retval EFI_NO_MEDIA The device has no media.
2422 @retval EFI_DEVICE_ERROR The device reported an error.
2423 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2424 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2430 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2431 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2432 IN UDF_VOLUME_INFO
*Volume
,
2433 IN UDF_FILE_INFO
*File
,
2438 UDF_READ_FILE_INFO ReadFileInfo
;
2440 ReadFileInfo
.Flags
= ReadFileGetFileSize
;
2446 &File
->FileIdentifierDesc
->Icb
,
2450 if (EFI_ERROR (Status
)) {
2454 *Size
= ReadFileInfo
.ReadLength
;
2460 Set information about a file on an UDF volume.
2462 @param[in] File File pointer.
2463 @param[in] FileSize Size of the file.
2464 @param[in] FileName Filename of the file.
2465 @param[in, out] BufferSize Size of the returned file infomation.
2466 @param[out] Buffer Data of the returned file information.
2468 @retval EFI_SUCCESS File information set.
2469 @retval EFI_NO_MEDIA The device has no media.
2470 @retval EFI_DEVICE_ERROR The device reported an error.
2471 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2472 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2478 IN UDF_FILE_INFO
*File
,
2480 IN CHAR16
*FileName
,
2481 IN OUT UINTN
*BufferSize
,
2485 UINTN FileInfoLength
;
2486 EFI_FILE_INFO
*FileInfo
;
2487 UDF_FILE_ENTRY
*FileEntry
;
2488 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
2489 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
2492 // Calculate the needed size for the EFI_FILE_INFO structure.
2494 FileInfoLength
= sizeof (EFI_FILE_INFO
) + ((FileName
!= NULL
) ?
2495 StrSize (FileName
) :
2497 if (*BufferSize
< FileInfoLength
) {
2499 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2501 *BufferSize
= FileInfoLength
;
2502 return EFI_BUFFER_TOO_SMALL
;
2506 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2507 // Now, fill it in with all necessary information about the file.
2509 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
2510 FileInfo
->Size
= FileInfoLength
;
2511 FileInfo
->Attribute
&= ~EFI_FILE_VALID_ATTR
;
2512 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
2514 if (IS_FID_DIRECTORY_FILE (File
->FileIdentifierDesc
)) {
2515 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
2516 } else if (IS_FID_NORMAL_FILE (File
->FileIdentifierDesc
)) {
2517 FileInfo
->Attribute
|= EFI_FILE_ARCHIVE
;
2520 if (IS_FID_HIDDEN_FILE (File
->FileIdentifierDesc
)) {
2521 FileInfo
->Attribute
|= EFI_FILE_HIDDEN
;
2524 DescriptorTag
= File
->FileEntry
;
2526 if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
2527 FileEntry
= (UDF_FILE_ENTRY
*)File
->FileEntry
;
2530 // Check if FE has the system attribute set.
2532 if (FileEntry
->IcbTag
.Flags
& (1 << 10)) {
2533 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2536 FileInfo
->FileSize
= FileSize
;
2537 FileInfo
->PhysicalSize
= FileSize
;
2539 FileInfo
->CreateTime
.Year
= FileEntry
->AccessTime
.Year
;
2540 FileInfo
->CreateTime
.Month
= FileEntry
->AccessTime
.Month
;
2541 FileInfo
->CreateTime
.Day
= FileEntry
->AccessTime
.Day
;
2542 FileInfo
->CreateTime
.Hour
= FileEntry
->AccessTime
.Hour
;
2543 FileInfo
->CreateTime
.Minute
= FileEntry
->AccessTime
.Minute
;
2544 FileInfo
->CreateTime
.Second
= FileEntry
->AccessTime
.Second
;
2545 FileInfo
->CreateTime
.Nanosecond
=
2546 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2548 FileInfo
->LastAccessTime
.Year
=
2549 FileEntry
->AccessTime
.Year
;
2550 FileInfo
->LastAccessTime
.Month
=
2551 FileEntry
->AccessTime
.Month
;
2552 FileInfo
->LastAccessTime
.Day
=
2553 FileEntry
->AccessTime
.Day
;
2554 FileInfo
->LastAccessTime
.Hour
=
2555 FileEntry
->AccessTime
.Hour
;
2556 FileInfo
->LastAccessTime
.Minute
=
2557 FileEntry
->AccessTime
.Minute
;
2558 FileInfo
->LastAccessTime
.Second
=
2559 FileEntry
->AccessTime
.Second
;
2560 FileInfo
->LastAccessTime
.Nanosecond
=
2561 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2562 } else if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
2563 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)File
->FileEntry
;
2566 // Check if EFE has the system attribute set.
2568 if (ExtendedFileEntry
->IcbTag
.Flags
& (1 << 10)) {
2569 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2572 FileInfo
->FileSize
= FileSize
;
2573 FileInfo
->PhysicalSize
= FileSize
;
2575 FileInfo
->CreateTime
.Year
= ExtendedFileEntry
->CreationTime
.Year
;
2576 FileInfo
->CreateTime
.Month
= ExtendedFileEntry
->CreationTime
.Month
;
2577 FileInfo
->CreateTime
.Day
= ExtendedFileEntry
->CreationTime
.Day
;
2578 FileInfo
->CreateTime
.Hour
= ExtendedFileEntry
->CreationTime
.Hour
;
2579 FileInfo
->CreateTime
.Minute
= ExtendedFileEntry
->CreationTime
.Second
;
2580 FileInfo
->CreateTime
.Second
= ExtendedFileEntry
->CreationTime
.Second
;
2581 FileInfo
->CreateTime
.Nanosecond
=
2582 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2584 FileInfo
->LastAccessTime
.Year
=
2585 ExtendedFileEntry
->AccessTime
.Year
;
2586 FileInfo
->LastAccessTime
.Month
=
2587 ExtendedFileEntry
->AccessTime
.Month
;
2588 FileInfo
->LastAccessTime
.Day
=
2589 ExtendedFileEntry
->AccessTime
.Day
;
2590 FileInfo
->LastAccessTime
.Hour
=
2591 ExtendedFileEntry
->AccessTime
.Hour
;
2592 FileInfo
->LastAccessTime
.Minute
=
2593 ExtendedFileEntry
->AccessTime
.Minute
;
2594 FileInfo
->LastAccessTime
.Second
=
2595 ExtendedFileEntry
->AccessTime
.Second
;
2596 FileInfo
->LastAccessTime
.Nanosecond
=
2597 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2600 FileInfo
->CreateTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2601 FileInfo
->CreateTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2602 FileInfo
->LastAccessTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2603 FileInfo
->LastAccessTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2606 (VOID
*)&FileInfo
->ModificationTime
,
2607 (VOID
*)&FileInfo
->LastAccessTime
,
2611 if (FileName
!= NULL
) {
2612 StrCpyS (FileInfo
->FileName
, StrLen (FileName
) + 1, FileName
);
2614 FileInfo
->FileName
[0] = '\0';
2617 *BufferSize
= FileInfoLength
;
2623 Get volume label of an UDF volume.
2625 @attention This is boundary function that may receive untrusted input.
2626 @attention The input is from FileSystem.
2628 The File Set Descriptor is external input, so this routine will do basic
2629 validation for File Set Descriptor and report status.
2631 @param[in] Volume Volume information pointer.
2632 @param[in] CharMax The maximum number of Unicode char in String,
2633 including terminating null char.
2634 @param[out] String String buffer pointer to store the volume label.
2636 @retval EFI_SUCCESS Volume label is returned.
2637 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2638 @retval EFI_BUFFER_TOO_SMALL The string buffer String cannot hold the
2644 IN UDF_VOLUME_INFO
*Volume
,
2649 UDF_FILE_SET_DESCRIPTOR
*FileSetDesc
;
2651 UINT8
*OstaCompressed
;
2652 UINT8 CompressionId
;
2655 FileSetDesc
= &Volume
->FileSetDesc
;
2657 OstaCompressed
= &FileSetDesc
->LogicalVolumeIdentifier
[0];
2659 CompressionId
= OstaCompressed
[0];
2660 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2661 return EFI_VOLUME_CORRUPTED
;
2665 for (Index
= 1; Index
< 128; Index
++) {
2666 if (CompressionId
== 16) {
2667 if ((Index
>> 1) > CharMax
) {
2668 return EFI_BUFFER_TOO_SMALL
;
2671 *String
= *(UINT8
*)(OstaCompressed
+ Index
) << 8;
2674 if (Index
> CharMax
) {
2675 return EFI_BUFFER_TOO_SMALL
;
2682 *String
|= (CHAR16
)(*(UINT8
*)(OstaCompressed
+ Index
));
2686 // Unlike FID Identifiers, Logical Volume Identifier is stored in a
2687 // NULL-terminated OSTA compressed format, so we must check for the NULL
2690 if (*String
== L
'\0') {
2697 Index
= ((UINTN
)String
- (UINTN
)StringBak
) / sizeof (CHAR16
);
2698 if (Index
> CharMax
- 1) {
2699 Index
= CharMax
- 1;
2702 StringBak
[Index
] = L
'\0';
2708 Get volume and free space size information of an UDF volume.
2710 @attention This is boundary function that may receive untrusted input.
2711 @attention The input is from FileSystem.
2713 The Logical Volume Descriptor and the Logical Volume Integrity Descriptor are
2714 external inputs, so this routine will do basic validation for both descriptors
2717 @param[in] BlockIo BlockIo interface.
2718 @param[in] DiskIo DiskIo interface.
2719 @param[in] Volume UDF volume information structure.
2720 @param[out] VolumeSize Volume size.
2721 @param[out] FreeSpaceSize Free space size.
2723 @retval EFI_SUCCESS Volume and free space size calculated.
2724 @retval EFI_NO_MEDIA The device has no media.
2725 @retval EFI_DEVICE_ERROR The device reported an error.
2726 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2727 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
2728 calculated due to lack of resources.
2733 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2734 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2735 IN UDF_VOLUME_INFO
*Volume
,
2736 OUT UINT64
*VolumeSize
,
2737 OUT UINT64
*FreeSpaceSize
2741 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
2742 UDF_EXTENT_AD
*ExtentAd
;
2744 UINT32 LogicalBlockSize
;
2745 UDF_LOGICAL_VOLUME_INTEGRITY
*LogicalVolInt
;
2746 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
2751 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
2753 ExtentAd
= &LogicalVolDesc
->IntegritySequenceExtent
;
2755 if ((ExtentAd
->ExtentLength
== 0) ||
2756 (ExtentAd
->ExtentLength
< sizeof (UDF_LOGICAL_VOLUME_INTEGRITY
)))
2758 return EFI_VOLUME_CORRUPTED
;
2761 LogicalVolInt
= AllocatePool (ExtentAd
->ExtentLength
);
2762 if (LogicalVolInt
== NULL
) {
2763 return EFI_OUT_OF_RESOURCES
;
2767 // Get location of Logical Volume Integrity Descriptor
2769 Lsn
= (UINT64
)ExtentAd
->ExtentLocation
- Volume
->MainVdsStartLocation
;
2771 LogicalBlockSize
= LogicalVolDesc
->LogicalBlockSize
;
2776 Status
= DiskIo
->ReadDisk (
2778 BlockIo
->Media
->MediaId
,
2779 MultU64x32 (Lsn
, LogicalBlockSize
),
2780 ExtentAd
->ExtentLength
,
2783 if (EFI_ERROR (Status
)) {
2787 DescriptorTag
= &LogicalVolInt
->DescriptorTag
;
2790 // Check if read block is a Logical Volume Integrity Descriptor
2792 if (DescriptorTag
->TagIdentifier
!= UdfLogicalVolumeIntegrityDescriptor
) {
2793 Status
= EFI_VOLUME_CORRUPTED
;
2797 if ((LogicalVolInt
->NumberOfPartitions
> MAX_UINT32
/ sizeof (UINT32
) / 2) ||
2798 (LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
) * 2 >
2799 ExtentAd
->ExtentLength
- sizeof (UDF_LOGICAL_VOLUME_INTEGRITY
)))
2801 Status
= EFI_VOLUME_CORRUPTED
;
2808 Length
= LogicalVolInt
->NumberOfPartitions
;
2809 for (Index
= 0; Index
< Length
; Index
+= sizeof (UINT32
)) {
2810 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2812 // Check if size is not specified
2814 if (LsnsNo
== 0xFFFFFFFFUL
) {
2819 // Accumulate free space size
2821 *FreeSpaceSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2824 Length
= LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
) * 2;
2825 for ( ; Index
< Length
; Index
+= sizeof (UINT32
)) {
2826 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2828 // Check if size is not specified
2830 if (LsnsNo
== 0xFFFFFFFFUL
) {
2835 // Accumulate used volume space
2837 *VolumeSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2840 Status
= EFI_SUCCESS
;
2844 // Free Logical Volume Integrity Descriptor
2846 FreePool (LogicalVolInt
);
2852 Seek a file and read its data into memory on an UDF volume.
2854 @param[in] BlockIo BlockIo interface.
2855 @param[in] DiskIo DiskIo interface.
2856 @param[in] Volume UDF volume information structure.
2857 @param[in] File File information structure.
2858 @param[in] FileSize Size of the file.
2859 @param[in, out] FilePosition File position.
2860 @param[in, out] Buffer File data.
2861 @param[in, out] BufferSize Read size.
2863 @retval EFI_SUCCESS File seeked and read.
2864 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2865 @retval EFI_NO_MEDIA The device has no media.
2866 @retval EFI_DEVICE_ERROR The device reported an error.
2867 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2868 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2874 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2875 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2876 IN UDF_VOLUME_INFO
*Volume
,
2877 IN UDF_FILE_INFO
*File
,
2879 IN OUT UINT64
*FilePosition
,
2880 IN OUT VOID
*Buffer
,
2881 IN OUT UINT64
*BufferSize
2885 UDF_READ_FILE_INFO ReadFileInfo
;
2887 ReadFileInfo
.Flags
= ReadFileSeekAndRead
;
2888 ReadFileInfo
.FilePosition
= *FilePosition
;
2889 ReadFileInfo
.FileData
= Buffer
;
2890 ReadFileInfo
.FileDataSize
= *BufferSize
;
2891 ReadFileInfo
.FileSize
= FileSize
;
2897 &File
->FileIdentifierDesc
->Icb
,
2901 if (EFI_ERROR (Status
)) {
2905 *BufferSize
= ReadFileInfo
.FileDataSize
;
2906 *FilePosition
= ReadFileInfo
.FilePosition
;
2912 Check if ControllerHandle supports an UDF file system.
2914 @param[in] This Protocol instance pointer.
2915 @param[in] ControllerHandle Handle of device to test.
2917 @retval EFI_SUCCESS UDF file system found.
2918 @retval EFI_UNSUPPORTED UDF file system not found.
2922 SupportUdfFileSystem (
2923 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2924 IN EFI_HANDLE ControllerHandle
2928 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2929 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2930 EFI_DEVICE_PATH_PROTOCOL
*LastDevicePathNode
;
2931 EFI_GUID
*VendorDefinedGuid
;
2934 // Open Device Path protocol on ControllerHandle
2936 Status
= gBS
->OpenProtocol (
2938 &gEfiDevicePathProtocolGuid
,
2939 (VOID
**)&DevicePath
,
2940 This
->DriverBindingHandle
,
2942 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2944 if (EFI_ERROR (Status
)) {
2945 return EFI_UNSUPPORTED
;
2948 Status
= EFI_UNSUPPORTED
;
2951 // Get last Device Path node
2953 LastDevicePathNode
= NULL
;
2954 DevicePathNode
= DevicePath
;
2955 while (!IsDevicePathEnd (DevicePathNode
)) {
2956 LastDevicePathNode
= DevicePathNode
;
2957 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
2961 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2962 // of an UDF file system.
2964 if ((LastDevicePathNode
!= NULL
) &&
2965 (DevicePathType (LastDevicePathNode
) == MEDIA_DEVICE_PATH
) &&
2966 (DevicePathSubType (LastDevicePathNode
) == MEDIA_VENDOR_DP
))
2968 VendorDefinedGuid
= (EFI_GUID
*)((UINTN
)LastDevicePathNode
+
2969 OFFSET_OF (VENDOR_DEVICE_PATH
, Guid
));
2970 if (CompareGuid (VendorDefinedGuid
, &gUdfDevPathGuid
)) {
2971 Status
= EFI_SUCCESS
;
2976 // Close Device Path protocol on ControllerHandle
2978 gBS
->CloseProtocol (
2980 &gEfiDevicePathProtocolGuid
,
2981 This
->DriverBindingHandle
,