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
) {
74 return EFI_VOLUME_CORRUPTED
;
78 Save the content of Logical Volume Descriptors and Partitions Descriptors in
81 @param[in] BlockIo BlockIo interface.
82 @param[in] DiskIo DiskIo interface.
83 @param[in] AnchorPoint Anchor volume descriptor pointer.
84 @param[out] Volume UDF volume information structure.
86 @retval EFI_SUCCESS The descriptors were saved.
87 @retval EFI_OUT_OF_RESOURCES The descriptors were not saved due to lack of
89 @retval other The descriptors were not saved due to
94 StartMainVolumeDescriptorSequence (
95 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
96 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
97 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
98 OUT UDF_VOLUME_INFO
*Volume
103 UDF_EXTENT_AD
*ExtentAd
;
104 EFI_LBA SeqStartBlock
;
106 BOOLEAN StopSequence
;
108 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
109 UINT32 LogicalBlockSize
;
111 BlockSize
= BlockIo
->Media
->BlockSize
;
112 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
115 // Allocate buffer for reading disk blocks
117 Buffer
= AllocateZeroPool ((UINTN
)BlockSize
);
118 if (Buffer
== NULL
) {
119 return EFI_OUT_OF_RESOURCES
;
123 // The logical partition created by Partition driver is relative to the main
124 // VDS extent location, so we start the Main Volume Descriptor Sequence at
127 // We don't need to check again if we have valid Volume Descriptors here since
128 // Partition driver already did.
131 SeqEndBlock
= SeqStartBlock
+ DivU64x32 ((UINT64
)ExtentAd
->ExtentLength
,
133 StopSequence
= FALSE
;
134 for (; SeqStartBlock
< SeqEndBlock
&& !StopSequence
; SeqStartBlock
++) {
138 Status
= BlockIo
->ReadBlocks (
140 BlockIo
->Media
->MediaId
,
145 if (EFI_ERROR (Status
)) {
149 DescriptorTag
= Buffer
;
151 switch (DescriptorTag
->TagIdentifier
) {
152 case UdfPartitionDescriptor
:
154 // Save Partition Descriptor
156 CopyMem (&Volume
->PartitionDesc
, Buffer
, sizeof (Volume
->PartitionDesc
));
159 case UdfLogicalVolumeDescriptor
:
161 // Save Logical Volume Descriptor
163 CopyMem (&Volume
->LogicalVolDesc
, Buffer
, sizeof (Volume
->LogicalVolDesc
));
166 case UdfTerminatingDescriptor
:
176 // Determine FE (File Entry) size
178 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
179 if (LogicalBlockSize
>= UDF_LOGICAL_SECTOR_SIZE
) {
180 Volume
->FileEntrySize
= (UINTN
)LogicalBlockSize
;
182 Volume
->FileEntrySize
= UDF_LOGICAL_SECTOR_SIZE
;
185 Status
= EFI_SUCCESS
;
189 // Free block read buffer
197 Return a Partition Descriptor given a Long Allocation Descriptor. This is
198 necessary to calculate the right extent (LongAd) offset which is added up
199 with partition's starting location.
201 @param[in] Volume Volume information pointer.
202 @param[in] LongAd Long Allocation Descriptor pointer.
204 @return A pointer to a Partition Descriptor.
207 UDF_PARTITION_DESCRIPTOR
*
209 IN UDF_VOLUME_INFO
*Volume
,
210 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
213 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
216 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
218 switch (LogicalVolDesc
->DomainIdentifier
.Suffix
.Domain
.UdfRevision
) {
226 // UDF 1.02 specification:
228 // There shall be exactly one prevailing Logical Volume Descriptor recorded
229 // per Volume Set. The Partition Maps field shall contain only Type 1
232 // UDF 1.50 through 2.60 specs say:
234 // For the purpose of interchange partition maps shall be limited to
235 // Partition Map type 1, except type 2 maps as described in the document.
237 // NOTE: Only one Type 1 (Physical) Partition is supported. It has been
238 // checked already in Partition driver for existence of a single Type 1
239 // Partition map. Hence, the 'PartitionReferenceNumber' field (the index
240 // used to access Partition Maps data within the Logical Volume Descriptor)
241 // in the Long Allocation Descriptor should be 0 to indicate there is only
244 if (LongAd
->ExtentLocation
.PartitionReferenceNumber
!= 0) {
248 // Since only one partition, get the first one directly.
250 PartitionNum
= *(UINT16
*)((UINTN
)&LogicalVolDesc
->PartitionMaps
[4]);
255 // Unsupported UDF revision
261 // Check if partition number matches Partition Descriptor found in Main Volume
262 // Descriptor Sequence.
264 if (Volume
->PartitionDesc
.PartitionNumber
== PartitionNum
) {
265 return &Volume
->PartitionDesc
;
272 Return logical sector number of a given Long Allocation Descriptor.
274 @param[in] Volume Volume information pointer.
275 @param[in] LongAd Long Allocation Descriptor pointer.
276 @param[out] Lsn Logical sector number pointer.
278 @retval EFI_SUCCESS Logical sector number successfully returned.
279 @retval EFI_UNSUPPORTED Logical sector number is not returned due to
285 IN UDF_VOLUME_INFO
*Volume
,
286 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
,
290 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
292 PartitionDesc
= GetPdFromLongAd (Volume
, LongAd
);
293 if (PartitionDesc
== NULL
) {
296 "%a: Fail to get the Partition Descriptor from the given Long Allocation Descriptor.\n",
299 return EFI_UNSUPPORTED
;
302 *Lsn
= (UINT64
)PartitionDesc
->PartitionStartingLocation
-
303 Volume
->MainVdsStartLocation
+
304 LongAd
->ExtentLocation
.LogicalBlockNumber
;
310 Return logical sector number of a given Short Allocation Descriptor.
312 @param[in] Volume Volume pointer.
313 @param[in] PartitionDesc Partition Descriptor pointer.
314 @param[in] ShortAd Short Allocation Descriptor pointer.
316 @return The logical sector number of a given Short Allocation Descriptor.
321 IN UDF_VOLUME_INFO
*Volume
,
322 IN UDF_PARTITION_DESCRIPTOR
*PartitionDesc
,
323 IN UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
326 return (UINT64
)PartitionDesc
->PartitionStartingLocation
-
327 Volume
->MainVdsStartLocation
+ ShortAd
->ExtentPosition
;
331 Find File Set Descriptor of a given Logical Volume Descriptor.
333 The found FSD will contain the extent (LogicalVolumeContentsUse) where our
336 @param[in] BlockIo BlockIo interface.
337 @param[in] DiskIo DiskIo interface.
338 @param[in] Volume Volume information pointer.
340 @retval EFI_SUCCESS File Set Descriptor pointer found.
341 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
342 @retval other File Set Descriptor pointer not found.
346 FindFileSetDescriptor (
347 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
348 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
349 IN UDF_VOLUME_INFO
*Volume
354 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
355 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
357 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
358 Status
= GetLongAdLsn (Volume
, &LogicalVolDesc
->LogicalVolumeContentsUse
, &Lsn
);
359 if (EFI_ERROR (Status
)) {
364 // As per UDF 2.60 specification:
366 // There shall be exactly one File Set Descriptor recorded per Logical
371 Status
= DiskIo
->ReadDisk (
373 BlockIo
->Media
->MediaId
,
374 MultU64x32 (Lsn
, LogicalVolDesc
->LogicalBlockSize
),
375 sizeof (Volume
->FileSetDesc
),
378 if (EFI_ERROR (Status
)) {
382 DescriptorTag
= &Volume
->FileSetDesc
.DescriptorTag
;
385 // Check if read block is a File Set Descriptor
387 if (DescriptorTag
->TagIdentifier
!= UdfFileSetDescriptor
) {
388 return EFI_VOLUME_CORRUPTED
;
395 Read Volume and File Structure on an UDF file system.
397 @param[in] BlockIo BlockIo interface.
398 @param[in] DiskIo DiskIo interface.
399 @param[out] Volume Volume information pointer.
401 @retval EFI_SUCCESS Volume and File Structure were read.
402 @retval other Volume and File Structure were not read.
406 ReadVolumeFileStructure (
407 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
408 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
409 OUT UDF_VOLUME_INFO
*Volume
413 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
414 UDF_EXTENT_AD
*ExtentAd
;
417 // Find Anchor Volume Descriptor Pointer
419 Status
= FindAnchorVolumeDescriptorPointer (
424 if (EFI_ERROR (Status
)) {
429 // Save Main VDS start block number
431 ExtentAd
= &AnchorPoint
.MainVolumeDescriptorSequenceExtent
;
433 Volume
->MainVdsStartLocation
= (UINT64
)ExtentAd
->ExtentLocation
;
436 // Start Main Volume Descriptor Sequence.
438 Status
= StartMainVolumeDescriptorSequence (
444 if (EFI_ERROR (Status
)) {
452 Calculate length of a given File Identifier Descriptor.
454 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
456 @return The length of a given File Identifier Descriptor.
460 GetFidDescriptorLength (
461 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
465 (INTN
)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR
, Data
[0]) + 3 +
466 FileIdentifierDesc
->LengthOfFileIdentifier
+
467 FileIdentifierDesc
->LengthOfImplementationUse
) >> 2) << 2
472 Duplicate a given File Identifier Descriptor.
474 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
475 @param[out] NewFileIdentifierDesc The duplicated File Identifier Descriptor.
480 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
481 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**NewFileIdentifierDesc
484 *NewFileIdentifierDesc
=
485 (UDF_FILE_IDENTIFIER_DESCRIPTOR
*)AllocateCopyPool (
486 (UINTN
) GetFidDescriptorLength (FileIdentifierDesc
), FileIdentifierDesc
);
490 Duplicate either a given File Entry or a given Extended File Entry.
492 @param[in] BlockIo BlockIo interface.
493 @param[in] Volume Volume information pointer.
494 @param[in] FileEntry (Extended) File Entry pointer.
495 @param[out] NewFileEntry The duplicated (Extended) File Entry.
500 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
501 IN UDF_VOLUME_INFO
*Volume
,
503 OUT VOID
**NewFileEntry
506 *NewFileEntry
= AllocateCopyPool (Volume
->FileEntrySize
, FileEntry
);
510 Get raw data + length of a given File Entry or Extended File Entry.
512 The file's recorded data can contain either real file content (inline) or
513 a sequence of extents (or Allocation Descriptors) which tells where file's
514 content is stored in.
516 NOTE: The FE/EFE can be thought it was an inode.
518 @attention This is boundary function that may receive untrusted input.
519 @attention The input is from FileSystem.
521 The (Extended) File Entry is external input, so this routine will do basic
522 validation for (Extended) File Entry and report status.
524 @param[in] FileEntryData (Extended) File Entry pointer.
525 @param[in] FileEntrySize Size of the (Extended) File Entry specified
527 @param[out] Data Buffer contains the raw data of a given
528 (Extended) File Entry.
529 @param[out] Length Length of the data in Buffer.
531 @retval EFI_SUCCESS Raw data and size of the FE/EFE was read.
532 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
537 IN VOID
*FileEntryData
,
538 IN UINTN FileEntrySize
,
543 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
544 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
545 UDF_FILE_ENTRY
*FileEntry
;
547 DescriptorTag
= FileEntryData
;
549 if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
550 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
552 *Length
= ExtendedFileEntry
->InformationLength
;
553 *Data
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
554 ExtendedFileEntry
->LengthOfExtendedAttributes
);
555 } else if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
556 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
558 *Length
= FileEntry
->InformationLength
;
559 *Data
= (VOID
*)((UINT8
*)FileEntry
->Data
+
560 FileEntry
->LengthOfExtendedAttributes
);
563 if ((*Length
> FileEntrySize
) ||
564 ((UINTN
)FileEntryData
> (UINTN
)(*Data
)) ||
565 ((UINTN
)(*Data
) - (UINTN
)FileEntryData
> FileEntrySize
- *Length
)) {
566 return EFI_VOLUME_CORRUPTED
;
572 Get Allocation Descriptors' data information from a given FE/EFE.
574 @attention This is boundary function that may receive untrusted input.
575 @attention The input is from FileSystem.
577 The (Extended) File Entry is external input, so this routine will do basic
578 validation for (Extended) File Entry and report status.
580 @param[in] FileEntryData (Extended) File Entry pointer.
581 @param[in] FileEntrySize Size of the (Extended) File Entry specified
583 @param[out] AdsData Buffer contains the Allocation Descriptors'
584 data from a given FE/EFE.
585 @param[out] Length Length of the data in AdsData.
587 @retval EFI_SUCCESS The data and size of Allocation Descriptors
588 were read from the FE/EFE.
589 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
594 IN VOID
*FileEntryData
,
595 IN UINTN FileEntrySize
,
600 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
601 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
602 UDF_FILE_ENTRY
*FileEntry
;
604 DescriptorTag
= FileEntryData
;
606 if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
607 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
609 *Length
= ExtendedFileEntry
->LengthOfAllocationDescriptors
;
610 *AdsData
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
611 ExtendedFileEntry
->LengthOfExtendedAttributes
);
612 } else if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
613 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
615 *Length
= FileEntry
->LengthOfAllocationDescriptors
;
616 *AdsData
= (VOID
*)((UINT8
*)FileEntry
->Data
+
617 FileEntry
->LengthOfExtendedAttributes
);
620 if ((*Length
> FileEntrySize
) ||
621 ((UINTN
)FileEntryData
> (UINTN
)(*AdsData
)) ||
622 ((UINTN
)(*AdsData
) - (UINTN
)FileEntryData
> FileEntrySize
- *Length
)) {
623 return EFI_VOLUME_CORRUPTED
;
629 Read next Long Allocation Descriptor from a given file's data.
631 @param[in] Data File's data pointer.
632 @param[in,out] Offset Starting offset of the File's data to read.
633 @param[in] Length Length of the data to read.
634 @param[out] FoundLongAd Long Allocation Descriptor pointer.
636 @retval EFI_SUCCESS A Long Allocation Descriptor was found.
637 @retval EFI_DEVICE_ERROR No more Long Allocation Descriptors.
643 IN OUT UINT64
*Offset
,
645 OUT UDF_LONG_ALLOCATION_DESCRIPTOR
**FoundLongAd
648 UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
;
649 UDF_EXTENT_FLAGS ExtentFlags
;
652 if (*Offset
>= Length
) {
654 // No more Long Allocation Descriptors.
656 return EFI_DEVICE_ERROR
;
660 (UDF_LONG_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
663 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
664 // allocated AD, then return it.
666 ExtentFlags
= GET_EXTENT_FLAGS (LongAdsSequence
, LongAd
);
667 if (ExtentFlags
== ExtentIsNextExtent
||
668 ExtentFlags
== ExtentRecordedAndAllocated
) {
673 // This AD is either not recorded but allocated, or not recorded and not
674 // allocated. Skip it.
676 *Offset
+= AD_LENGTH (LongAdsSequence
);
679 *FoundLongAd
= LongAd
;
685 Read next Short Allocation Descriptor from a given file's data.
687 @param[in] Data File's data pointer.
688 @param[in,out] Offset Starting offset of the File's data to read.
689 @param[in] Length Length of the data to read.
690 @param[out] FoundShortAd Short Allocation Descriptor pointer.
692 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
693 @retval EFI_DEVICE_ERROR No more Short Allocation Descriptors.
699 IN OUT UINT64
*Offset
,
701 OUT UDF_SHORT_ALLOCATION_DESCRIPTOR
**FoundShortAd
704 UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
;
705 UDF_EXTENT_FLAGS ExtentFlags
;
708 if (*Offset
>= Length
) {
710 // No more Short Allocation Descriptors.
712 return EFI_DEVICE_ERROR
;
716 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
719 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
720 // allocated AD, then return it.
722 ExtentFlags
= GET_EXTENT_FLAGS (ShortAdsSequence
, ShortAd
);
723 if (ExtentFlags
== ExtentIsNextExtent
||
724 ExtentFlags
== ExtentRecordedAndAllocated
) {
729 // This AD is either not recorded but allocated, or not recorded and not
730 // allocated. Skip it.
732 *Offset
+= AD_LENGTH (ShortAdsSequence
);
735 *FoundShortAd
= ShortAd
;
741 Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
744 @param[in] RecordingFlags Flag to indicate the type of descriptor.
745 @param[in] Data File's data pointer.
746 @param[in,out] Offset Starting offset of the File's data to read.
747 @param[in] Length Length of the data to read.
748 @param[out] FoundAd Allocation Descriptor pointer.
750 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
751 @retval EFI_DEVICE_ERROR No more Allocation Descriptors.
752 Invalid type of descriptor was given.
756 GetAllocationDescriptor (
757 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
759 IN OUT UINT64
*Offset
,
764 if (RecordingFlags
== LongAdsSequence
) {
765 return GetLongAdFromAds (
769 (UDF_LONG_ALLOCATION_DESCRIPTOR
**)FoundAd
771 } else if (RecordingFlags
== ShortAdsSequence
) {
772 return GetShortAdFromAds (
776 (UDF_SHORT_ALLOCATION_DESCRIPTOR
**)FoundAd
781 // Code should never reach here.
784 return EFI_DEVICE_ERROR
;
788 Return logical sector number of either Short or Long Allocation Descriptor.
790 @param[in] RecordingFlags Flag to indicate the type of descriptor.
791 @param[in] Volume Volume information pointer.
792 @param[in] ParentIcb Long Allocation Descriptor pointer.
793 @param[in] Ad Allocation Descriptor pointer.
794 @param[out] Lsn Logical sector number pointer.
796 @retval EFI_SUCCESS Logical sector number of the given Allocation
797 Descriptor successfully returned.
798 @retval EFI_UNSUPPORTED Logical sector number of the given Allocation
799 Descriptor is not returned due to unrecognized
804 GetAllocationDescriptorLsn (
805 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
806 IN UDF_VOLUME_INFO
*Volume
,
807 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
812 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
814 if (RecordingFlags
== LongAdsSequence
) {
815 return GetLongAdLsn (Volume
, (UDF_LONG_ALLOCATION_DESCRIPTOR
*)Ad
, Lsn
);
816 } else if (RecordingFlags
== ShortAdsSequence
) {
817 PartitionDesc
= GetPdFromLongAd (Volume
, ParentIcb
);
818 if (PartitionDesc
== NULL
) {
819 return EFI_UNSUPPORTED
;
822 *Lsn
= GetShortAdLsn (
825 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)Ad
831 // Code should never reach here.
834 return EFI_UNSUPPORTED
;
838 Return offset + length of a given indirect Allocation Descriptor (AED).
840 @param[in] BlockIo BlockIo interface.
841 @param[in] DiskIo DiskIo interface.
842 @param[in] Volume Volume information pointer.
843 @param[in] ParentIcb Long Allocation Descriptor pointer.
844 @param[in] RecordingFlags Flag to indicate the type of descriptor.
845 @param[in] Ad Allocation Descriptor pointer.
846 @param[out] Offset Offset of a given indirect Allocation
848 @param[out] Length Length of a given indirect Allocation
851 @retval EFI_SUCCESS The offset and length were returned.
852 @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due
853 to lack of resources.
854 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
855 @retval other The offset and length were not returned.
860 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
861 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
862 IN UDF_VOLUME_INFO
*Volume
,
863 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
864 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
874 UINT32 LogicalBlockSize
;
875 UDF_ALLOCATION_EXTENT_DESCRIPTOR
*AllocExtDesc
;
876 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
878 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
879 Status
= GetAllocationDescriptorLsn (RecordingFlags
,
884 if (EFI_ERROR (Status
)) {
888 Data
= AllocatePool (ExtentLength
);
890 return EFI_OUT_OF_RESOURCES
;
893 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
898 Status
= DiskIo
->ReadDisk (
900 BlockIo
->Media
->MediaId
,
901 MultU64x32 (Lsn
, LogicalBlockSize
),
905 if (EFI_ERROR (Status
)) {
909 AllocExtDesc
= (UDF_ALLOCATION_EXTENT_DESCRIPTOR
*)Data
;
911 DescriptorTag
= &AllocExtDesc
->DescriptorTag
;
914 // Check if read extent contains a valid tag identifier for AED.
916 if (DescriptorTag
->TagIdentifier
!= UdfAllocationExtentDescriptor
) {
917 Status
= EFI_VOLUME_CORRUPTED
;
922 // Get AED's block offset and its length.
924 *Offset
= MultU64x32 (Lsn
, LogicalBlockSize
) +
925 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR
);
926 *Length
= AllocExtDesc
->LengthOfAllocationDescriptors
;
935 Read Allocation Extent Descriptor into memory.
937 @param[in] BlockIo BlockIo interface.
938 @param[in] DiskIo DiskIo interface.
939 @param[in] Volume Volume information pointer.
940 @param[in] ParentIcb Long Allocation Descriptor pointer.
941 @param[in] RecordingFlags Flag to indicate the type of descriptor.
942 @param[in] Ad Allocation Descriptor pointer.
943 @param[out] Data Buffer that contains the Allocation Extent
945 @param[out] Length Length of Data.
947 @retval EFI_SUCCESS The Allocation Extent Descriptor was read.
948 @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read
949 due to lack of resources.
950 @retval other Fail to read the disk.
955 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
956 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
957 IN UDF_VOLUME_INFO
*Volume
,
958 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
959 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
969 // Get AED's offset + length.
971 Status
= GetAedAdsOffset (
981 if (EFI_ERROR (Status
)) {
986 // Allocate buffer to read in AED's data.
988 *Data
= AllocatePool ((UINTN
) (*Length
));
990 return EFI_OUT_OF_RESOURCES
;
993 return DiskIo
->ReadDisk (
995 BlockIo
->Media
->MediaId
,
1003 Function used to serialise reads of Allocation Descriptors.
1005 @param[in] RecordingFlags Flag to indicate the type of descriptor.
1006 @param[in] Ad Allocation Descriptor pointer.
1007 @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.
1008 @param[in] Length Length of Buffer.
1010 @retval EFI_SUCCESS Buffer was grown to hold the next Allocation
1012 @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.
1016 GrowUpBufferToNextAd (
1017 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
1019 IN OUT VOID
**Buffer
,
1023 UINT32 ExtentLength
;
1025 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1027 if (*Buffer
== NULL
) {
1028 *Buffer
= AllocatePool (ExtentLength
);
1029 if (*Buffer
== NULL
) {
1030 return EFI_OUT_OF_RESOURCES
;
1033 *Buffer
= ReallocatePool ((UINTN
) Length
, (UINTN
) (Length
+ ExtentLength
), *Buffer
);
1034 if (*Buffer
== NULL
) {
1035 return EFI_OUT_OF_RESOURCES
;
1043 Read data or size of either a File Entry or an Extended File Entry.
1045 @param[in] BlockIo BlockIo interface.
1046 @param[in] DiskIo DiskIo interface.
1047 @param[in] Volume Volume information pointer.
1048 @param[in] ParentIcb Long Allocation Descriptor pointer.
1049 @param[in] FileEntryData FE/EFE structure pointer.
1050 @param[in, out] ReadFileInfo Read file information pointer.
1052 @retval EFI_SUCCESS Data or size of a FE/EFE was read.
1053 @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to
1055 @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is
1057 @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData
1059 @retval other Data or size of a FE/EFE was not read.
1064 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1065 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1066 IN UDF_VOLUME_INFO
*Volume
,
1067 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1068 IN VOID
*FileEntryData
,
1069 IN OUT UDF_READ_FILE_INFO
*ReadFileInfo
1073 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
) {
1217 Status
= GetAedAdsData (
1234 if (EFI_ERROR (Status
)) {
1237 ASSERT (Data
!= NULL
);
1243 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1245 Status
= GetAllocationDescriptorLsn (RecordingFlags
,
1250 if (EFI_ERROR (Status
)) {
1254 switch (ReadFileInfo
->Flags
) {
1255 case ReadFileGetFileSize
:
1256 ReadFileInfo
->ReadLength
+= ExtentLength
;
1258 case ReadFileAllocateAndRead
:
1260 // Increase FileData (if necessary) to read next extent.
1262 Status
= GrowUpBufferToNextAd (
1265 &ReadFileInfo
->FileData
,
1266 ReadFileInfo
->ReadLength
1268 if (EFI_ERROR (Status
)) {
1269 goto Error_Alloc_Buffer_To_Next_Ad
;
1273 // Read extent's data into FileData.
1275 Status
= DiskIo
->ReadDisk (
1277 BlockIo
->Media
->MediaId
,
1278 MultU64x32 (Lsn
, LogicalBlockSize
),
1280 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1281 ReadFileInfo
->ReadLength
)
1283 if (EFI_ERROR (Status
)) {
1284 goto Error_Read_Disk_Blk
;
1287 ReadFileInfo
->ReadLength
+= ExtentLength
;
1289 case ReadFileSeekAndRead
:
1291 // Seek file first before reading in its data.
1293 if (FinishedSeeking
) {
1295 goto Skip_File_Seek
;
1298 if (FilePosition
+ ExtentLength
< ReadFileInfo
->FilePosition
) {
1299 FilePosition
+= ExtentLength
;
1303 if (FilePosition
+ ExtentLength
> ReadFileInfo
->FilePosition
) {
1304 Offset
= ReadFileInfo
->FilePosition
- FilePosition
;
1310 // Done with seeking file. Start reading its data.
1312 FinishedSeeking
= TRUE
;
1316 // Make sure we don't read more data than really wanted.
1318 if (ExtentLength
- Offset
> BytesLeft
) {
1319 DataLength
= BytesLeft
;
1321 DataLength
= ExtentLength
- Offset
;
1325 // Read extent's data into FileData.
1327 Status
= DiskIo
->ReadDisk (
1329 BlockIo
->Media
->MediaId
,
1330 Offset
+ MultU64x32 (Lsn
, LogicalBlockSize
),
1332 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1335 if (EFI_ERROR (Status
)) {
1336 goto Error_Read_Disk_Blk
;
1340 // Update current file's position.
1342 DataOffset
+= DataLength
;
1343 ReadFileInfo
->FilePosition
+= DataLength
;
1345 BytesLeft
-= DataLength
;
1346 if (BytesLeft
== 0) {
1348 // There is no more file data to read.
1350 Status
= EFI_SUCCESS
;
1359 // Point to the next AD (extent).
1361 AdOffset
+= AD_LENGTH (RecordingFlags
);
1365 case ExtendedAdsSequence
:
1366 // FIXME: Not supported. Got no volume with it, yet.
1368 Status
= EFI_UNSUPPORTED
;
1373 // A flag value reserved by the ECMA-167 standard (3rd Edition - June
1374 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
1376 Status
= EFI_UNSUPPORTED
;
1387 Error_Read_Disk_Blk
:
1388 Error_Alloc_Buffer_To_Next_Ad
:
1389 if (ReadFileInfo
->Flags
!= ReadFileSeekAndRead
) {
1390 FreePool (ReadFileInfo
->FileData
);
1402 Find a file by its filename from a given Parent file.
1404 @param[in] BlockIo BlockIo interface.
1405 @param[in] DiskIo DiskIo interface.
1406 @param[in] Volume Volume information pointer.
1407 @param[in] FileName File name string.
1408 @param[in] Parent Parent directory file.
1409 @param[in] Icb Long Allocation Descriptor pointer.
1410 @param[out] File Found file.
1412 @retval EFI_SUCCESS The file was found.
1413 @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.
1414 @retval EFI_NOT_FOUND The file was not found.
1419 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1420 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1421 IN UDF_VOLUME_INFO
*Volume
,
1422 IN CHAR16
*FileName
,
1423 IN UDF_FILE_INFO
*Parent
,
1424 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1425 OUT UDF_FILE_INFO
*File
1429 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1430 UDF_READ_DIRECTORY_INFO ReadDirInfo
;
1432 CHAR16 FoundFileName
[UDF_FILENAME_LENGTH
];
1433 VOID
*CompareFileEntry
;
1436 // Check if both Parent->FileIdentifierDesc and Icb are NULL.
1438 if ((Parent
->FileIdentifierDesc
== NULL
) && (Icb
== NULL
)) {
1439 return EFI_INVALID_PARAMETER
;
1443 // Check if parent file is really directory.
1445 if (FE_ICB_FILE_TYPE (Parent
->FileEntry
) != UdfFileEntryDirectory
) {
1446 return EFI_NOT_FOUND
;
1450 // If FileName is current file or working directory, just duplicate Parent's
1451 // FE/EFE and FID descriptors.
1453 if (StrCmp (FileName
, L
".") == 0) {
1454 if (Parent
->FileIdentifierDesc
== NULL
) {
1455 return EFI_INVALID_PARAMETER
;
1458 DuplicateFe (BlockIo
, Volume
, Parent
->FileEntry
, &File
->FileEntry
);
1459 if (File
->FileEntry
== NULL
) {
1460 return EFI_OUT_OF_RESOURCES
;
1463 DuplicateFid (Parent
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1464 if (File
->FileIdentifierDesc
== NULL
) {
1465 FreePool (File
->FileEntry
);
1466 return EFI_OUT_OF_RESOURCES
;
1473 // Start directory listing.
1475 ZeroMem ((VOID
*)&ReadDirInfo
, sizeof (UDF_READ_DIRECTORY_INFO
));
1479 Status
= ReadDirectoryEntry (
1483 (Parent
->FileIdentifierDesc
!= NULL
) ?
1484 &Parent
->FileIdentifierDesc
->Icb
:
1490 if (EFI_ERROR (Status
)) {
1491 if (Status
== EFI_DEVICE_ERROR
) {
1492 Status
= EFI_NOT_FOUND
;
1498 // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is
1499 // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code
1500 // reaches here, 'FileIdentifierDesc' must be not NULL.
1502 // The ASSERT here is for addressing a false positive NULL pointer
1503 // dereference issue raised from static analysis.
1505 ASSERT (FileIdentifierDesc
!= NULL
);
1507 if (FileIdentifierDesc
->FileCharacteristics
& PARENT_FILE
) {
1509 // This FID contains the location (FE/EFE) of the parent directory of this
1510 // directory (Parent), and if FileName is either ".." or "\\", then it's
1511 // the expected FID.
1513 if (StrCmp (FileName
, L
"..") == 0 || StrCmp (FileName
, L
"\\") == 0) {
1518 Status
= GetFileNameFromFid (FileIdentifierDesc
, ARRAY_SIZE (FoundFileName
), FoundFileName
);
1519 if (EFI_ERROR (Status
)) {
1523 if (StrCmp (FileName
, FoundFileName
) == 0) {
1525 // FID has been found. Prepare to find its respective FE/EFE.
1532 FreePool ((VOID
*)FileIdentifierDesc
);
1535 if (ReadDirInfo
.DirectoryData
!= NULL
) {
1537 // Free all allocated resources for the directory listing.
1539 FreePool (ReadDirInfo
.DirectoryData
);
1543 Status
= EFI_SUCCESS
;
1545 File
->FileIdentifierDesc
= FileIdentifierDesc
;
1548 // If the requested file is root directory, then the FE/EFE was already
1549 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1551 // Otherwise, find FE/EFE from the respective FID.
1553 if (StrCmp (FileName
, L
"\\") != 0) {
1554 Status
= FindFileEntry (
1558 &FileIdentifierDesc
->Icb
,
1561 if (EFI_ERROR (Status
)) {
1566 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1568 if (CompareMem ((VOID
*)Parent
->FileEntry
, (VOID
*)CompareFileEntry
,
1569 Volume
->FileEntrySize
) != 0) {
1570 File
->FileEntry
= CompareFileEntry
;
1572 FreePool ((VOID
*)FileIdentifierDesc
);
1573 FreePool ((VOID
*)CompareFileEntry
);
1574 Status
= EFI_NOT_FOUND
;
1582 FreePool ((VOID
*)FileIdentifierDesc
);
1588 Read volume information on a medium which contains a valid UDF file system.
1590 @param[in] BlockIo BlockIo interface.
1591 @param[in] DiskIo DiskIo interface.
1592 @param[out] Volume UDF volume information structure.
1594 @retval EFI_SUCCESS Volume information read.
1595 @retval EFI_NO_MEDIA The device has no media.
1596 @retval EFI_DEVICE_ERROR The device reported an error.
1597 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1598 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1602 ReadUdfVolumeInformation (
1603 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1604 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1605 OUT UDF_VOLUME_INFO
*Volume
1611 // Read all necessary UDF volume information and keep it private to the driver
1613 Status
= ReadVolumeFileStructure (
1618 if (EFI_ERROR (Status
)) {
1623 // Find File Set Descriptor
1625 Status
= FindFileSetDescriptor (BlockIo
, DiskIo
, Volume
);
1626 if (EFI_ERROR (Status
)) {
1634 Find the root directory on an UDF volume.
1636 @param[in] BlockIo BlockIo interface.
1637 @param[in] DiskIo DiskIo interface.
1638 @param[in] Volume UDF volume information structure.
1639 @param[out] File Root directory file.
1641 @retval EFI_SUCCESS Root directory found.
1642 @retval EFI_NO_MEDIA The device has no media.
1643 @retval EFI_DEVICE_ERROR The device reported an error.
1644 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1645 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1651 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1652 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1653 IN UDF_VOLUME_INFO
*Volume
,
1654 OUT UDF_FILE_INFO
*File
1658 UDF_FILE_INFO Parent
;
1660 Status
= FindFileEntry (
1664 &Volume
->FileSetDesc
.RootDirectoryIcb
,
1667 if (EFI_ERROR (Status
)) {
1671 Parent
.FileEntry
= File
->FileEntry
;
1672 Parent
.FileIdentifierDesc
= NULL
;
1681 &Volume
->FileSetDesc
.RootDirectoryIcb
,
1684 if (EFI_ERROR (Status
)) {
1685 FreePool (File
->FileEntry
);
1692 Find either a File Entry or a Extended File Entry from a given ICB.
1694 @param[in] BlockIo BlockIo interface.
1695 @param[in] DiskIo DiskIo interface.
1696 @param[in] Volume UDF volume information structure.
1697 @param[in] Icb ICB of the FID.
1698 @param[out] FileEntry File Entry or Extended File Entry.
1700 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1701 @retval EFI_NO_MEDIA The device has no media.
1702 @retval EFI_DEVICE_ERROR The device reported an error.
1703 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1704 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1710 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1711 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1712 IN UDF_VOLUME_INFO
*Volume
,
1713 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1714 OUT VOID
**FileEntry
1719 UINT32 LogicalBlockSize
;
1720 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
1723 Status
= GetLongAdLsn (Volume
, Icb
, &Lsn
);
1724 if (EFI_ERROR (Status
)) {
1728 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
1730 ReadBuffer
= AllocateZeroPool (Volume
->FileEntrySize
);
1731 if (ReadBuffer
== NULL
) {
1732 return EFI_OUT_OF_RESOURCES
;
1738 Status
= DiskIo
->ReadDisk (
1740 BlockIo
->Media
->MediaId
,
1741 MultU64x32 (Lsn
, LogicalBlockSize
),
1742 Volume
->FileEntrySize
,
1745 if (EFI_ERROR (Status
)) {
1746 goto Error_Read_Disk_Blk
;
1749 DescriptorTag
= ReadBuffer
;
1752 // Check if the read extent contains a valid Tag Identifier for the expected
1755 if (DescriptorTag
->TagIdentifier
!= UdfFileEntry
&&
1756 DescriptorTag
->TagIdentifier
!= UdfExtendedFileEntry
) {
1757 Status
= EFI_VOLUME_CORRUPTED
;
1758 goto Error_Invalid_Fe
;
1761 *FileEntry
= ReadBuffer
;
1765 Error_Read_Disk_Blk
:
1766 FreePool (ReadBuffer
);
1772 Find a file given its absolute path on an UDF volume.
1774 @param[in] BlockIo BlockIo interface.
1775 @param[in] DiskIo DiskIo interface.
1776 @param[in] Volume UDF volume information structure.
1777 @param[in] FilePath File's absolute path.
1778 @param[in] Root Root directory file.
1779 @param[in] Parent Parent directory file.
1780 @param[in] Icb ICB of Parent.
1781 @param[out] File Found file.
1783 @retval EFI_SUCCESS FilePath was found.
1784 @retval EFI_NO_MEDIA The device has no media.
1785 @retval EFI_DEVICE_ERROR The device reported an error.
1786 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1787 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
1793 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1794 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1795 IN UDF_VOLUME_INFO
*Volume
,
1796 IN CHAR16
*FilePath
,
1797 IN UDF_FILE_INFO
*Root
,
1798 IN UDF_FILE_INFO
*Parent
,
1799 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1800 OUT UDF_FILE_INFO
*File
1804 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1805 CHAR16
*FileNamePointer
;
1806 UDF_FILE_INFO PreviousFile
;
1809 Status
= EFI_NOT_FOUND
;
1811 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1812 while (*FilePath
!= L
'\0') {
1813 FileNamePointer
= FileName
;
1814 while (*FilePath
!= L
'\0' && *FilePath
!= L
'\\') {
1815 if ((((UINTN
)FileNamePointer
- (UINTN
)FileName
) / sizeof (CHAR16
)) >=
1816 (ARRAY_SIZE (FileName
) - 1)) {
1817 return EFI_NOT_FOUND
;
1820 *FileNamePointer
++ = *FilePath
++;
1823 *FileNamePointer
= L
'\0';
1824 if (FileName
[0] == L
'\0') {
1826 // Open root directory.
1830 // There is no file found for the root directory yet. So, find only its
1833 // See UdfOpenVolume() function.
1835 Status
= InternalFindFile (BlockIo
,
1844 // We've already a file pointer (Root) for the root directory. Duplicate
1845 // its FE/EFE and FID descriptors.
1847 Status
= EFI_SUCCESS
;
1848 DuplicateFe (BlockIo
, Volume
, Root
->FileEntry
, &File
->FileEntry
);
1849 if (File
->FileEntry
== NULL
) {
1850 Status
= EFI_OUT_OF_RESOURCES
;
1853 // File->FileEntry is not NULL.
1855 DuplicateFid (Root
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1856 if (File
->FileIdentifierDesc
== NULL
) {
1857 FreePool (File
->FileEntry
);
1858 Status
= EFI_OUT_OF_RESOURCES
;
1864 // No root directory. Find filename from the current directory.
1866 Status
= InternalFindFile (BlockIo
,
1875 if (EFI_ERROR (Status
)) {
1880 // If the found file is a symlink, then find its respective FE/EFE and
1883 if (FE_ICB_FILE_TYPE (File
->FileEntry
) == UdfFileEntrySymlink
) {
1884 FreePool ((VOID
*)File
->FileIdentifierDesc
);
1886 FileEntry
= File
->FileEntry
;
1888 Status
= ResolveSymlink (BlockIo
,
1895 FreePool (FileEntry
);
1897 if (EFI_ERROR (Status
)) {
1902 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1903 sizeof (UDF_FILE_INFO
)) != 0) {
1904 CleanupFileInformation (&PreviousFile
);
1907 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1908 if (*FilePath
!= L
'\0' && *FilePath
== L
'\\') {
1917 Read a directory entry at a time on an UDF volume.
1919 @param[in] BlockIo BlockIo interface.
1920 @param[in] DiskIo DiskIo interface.
1921 @param[in] Volume UDF volume information structure.
1922 @param[in] ParentIcb ICB of the parent file.
1923 @param[in] FileEntryData FE/EFE of the parent file.
1924 @param[in, out] ReadDirInfo Next read directory listing structure
1926 @param[out] FoundFid File Identifier Descriptor pointer.
1928 @retval EFI_SUCCESS Directory entry read.
1929 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1930 @retval EFI_NO_MEDIA The device has no media.
1931 @retval EFI_DEVICE_ERROR The device reported an error.
1932 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1933 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1938 ReadDirectoryEntry (
1939 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1940 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1941 IN UDF_VOLUME_INFO
*Volume
,
1942 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1943 IN VOID
*FileEntryData
,
1944 IN OUT UDF_READ_DIRECTORY_INFO
*ReadDirInfo
,
1945 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**FoundFid
1949 UDF_READ_FILE_INFO ReadFileInfo
;
1950 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1952 if (ReadDirInfo
->DirectoryData
== NULL
) {
1954 // The directory's recorded data has not been read yet. So let's cache it
1955 // into memory and the next calls won't need to read it again.
1957 ReadFileInfo
.Flags
= ReadFileAllocateAndRead
;
1967 if (EFI_ERROR (Status
)) {
1972 // Fill in ReadDirInfo structure with the read directory's data information.
1974 ReadDirInfo
->DirectoryData
= ReadFileInfo
.FileData
;
1975 ReadDirInfo
->DirectoryLength
= ReadFileInfo
.ReadLength
;
1979 if (ReadDirInfo
->FidOffset
>= ReadDirInfo
->DirectoryLength
) {
1981 // There are no longer FIDs for this directory. By returning
1982 // EFI_DEVICE_ERROR to the callee will indicate end of directory
1985 return EFI_DEVICE_ERROR
;
1989 // Get FID for this entry.
1991 FileIdentifierDesc
= GET_FID_FROM_ADS (ReadDirInfo
->DirectoryData
,
1992 ReadDirInfo
->FidOffset
);
1994 // Update FidOffset to point to next FID.
1996 ReadDirInfo
->FidOffset
+= GetFidDescriptorLength (FileIdentifierDesc
);
1997 } while (FileIdentifierDesc
->FileCharacteristics
& DELETED_FILE
);
1999 DuplicateFid (FileIdentifierDesc
, FoundFid
);
2000 if (*FoundFid
== NULL
) {
2001 return EFI_OUT_OF_RESOURCES
;
2008 Get a filename (encoded in OSTA-compressed format) from a File Identifier
2009 Descriptor on an UDF volume.
2011 @attention This is boundary function that may receive untrusted input.
2012 @attention The input is from FileSystem.
2014 The File Identifier Descriptor is external input, so this routine will do
2015 basic validation for File Identifier Descriptor and report status.
2017 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
2018 @param[in] CharMax The maximum number of FileName Unicode char,
2019 including terminating null char.
2020 @param[out] FileName Decoded filename.
2022 @retval EFI_SUCCESS Filename decoded and read.
2023 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2024 @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
2028 GetFileNameFromFid (
2029 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
2031 OUT CHAR16
*FileName
2034 UINT8
*OstaCompressed
;
2035 UINT8 CompressionId
;
2038 CHAR16
*FileNameBak
;
2041 return EFI_BUFFER_TOO_SMALL
;
2046 (UINT8
*)FileIdentifierDesc
->Data
+
2047 FileIdentifierDesc
->LengthOfImplementationUse
2050 CompressionId
= OstaCompressed
[0];
2051 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2052 return EFI_VOLUME_CORRUPTED
;
2055 FileNameBak
= FileName
;
2060 Length
= FileIdentifierDesc
->LengthOfFileIdentifier
;
2061 if (CompressionId
== 16) {
2062 if (((UINTN
)Length
>> 1) > CharMax
) {
2063 return EFI_BUFFER_TOO_SMALL
;
2066 if ((Length
!= 0) && ((UINTN
)Length
- 1 > CharMax
)) {
2067 return EFI_BUFFER_TOO_SMALL
;
2071 for (Index
= 1; Index
< Length
; Index
++) {
2072 if (CompressionId
== 16) {
2073 *FileName
= OstaCompressed
[Index
++] << 8;
2078 if (Index
< Length
) {
2079 *FileName
|= (CHAR16
)(OstaCompressed
[Index
]);
2085 Index
= ((UINTN
)FileName
- (UINTN
)FileNameBak
) / sizeof (CHAR16
);
2086 if (Index
> CharMax
- 1) {
2087 Index
= CharMax
- 1;
2089 FileNameBak
[Index
] = L
'\0';
2095 Resolve a symlink file on an UDF volume.
2097 @attention This is boundary function that may receive untrusted input.
2098 @attention The input is from FileSystem.
2100 The Path Component is external input, so this routine will do basic
2101 validation for Path Component and report status.
2103 @param[in] BlockIo BlockIo interface.
2104 @param[in] DiskIo DiskIo interface.
2105 @param[in] Volume UDF volume information structure.
2106 @param[in] Parent Parent file.
2107 @param[in] FileEntryData FE/EFE structure pointer.
2108 @param[out] File Resolved file.
2110 @retval EFI_SUCCESS Symlink file resolved.
2111 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2112 @retval EFI_NO_MEDIA The device has no media.
2113 @retval EFI_DEVICE_ERROR The device reported an error.
2114 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2115 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
2121 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2122 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2123 IN UDF_VOLUME_INFO
*Volume
,
2124 IN UDF_FILE_INFO
*Parent
,
2125 IN VOID
*FileEntryData
,
2126 OUT UDF_FILE_INFO
*File
2130 UDF_READ_FILE_INFO ReadFileInfo
;
2134 UDF_PATH_COMPONENT
*PathComp
;
2135 UINT8 PathCompLength
;
2136 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
2139 UINT8 CompressionId
;
2140 UDF_FILE_INFO PreviousFile
;
2144 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
2147 // Symlink files on UDF volumes do not contain so much data other than
2148 // Path Components which resolves to real filenames, so it's OK to read in
2149 // all its data here -- usually the data will be inline with the FE/EFE for
2152 ReadFileInfo
.Flags
= ReadFileAllocateAndRead
;
2158 &Parent
->FileIdentifierDesc
->Icb
,
2162 if (EFI_ERROR (Status
)) {
2166 Length
= ReadFileInfo
.ReadLength
;
2168 Data
= (UINT8
*)ReadFileInfo
.FileData
;
2169 EndData
= Data
+ Length
;
2171 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
2174 PathComp
= (UDF_PATH_COMPONENT
*)Data
;
2176 PathCompLength
= PathComp
->LengthOfComponentIdentifier
;
2178 switch (PathComp
->ComponentType
) {
2181 // This Path Component specifies the root directory hierarchy subject to
2182 // agreement between the originator and recipient of the medium. Skip it.
2188 // "\\." of the current directory. Read next Path Component.
2190 goto Next_Path_Component
;
2193 // ".." (parent directory). Go to it.
2195 CopyMem ((VOID
*)FileName
, L
"..", 6);
2199 // "." (current file). Duplicate both FE/EFE and FID of this file.
2201 DuplicateFe (BlockIo
, Volume
, PreviousFile
.FileEntry
, &File
->FileEntry
);
2202 if (File
->FileEntry
== NULL
) {
2203 Status
= EFI_OUT_OF_RESOURCES
;
2204 goto Error_Find_File
;
2207 DuplicateFid (PreviousFile
.FileIdentifierDesc
,
2208 &File
->FileIdentifierDesc
);
2209 if (File
->FileIdentifierDesc
== NULL
) {
2210 FreePool (File
->FileEntry
);
2211 Status
= EFI_OUT_OF_RESOURCES
;
2212 goto Error_Find_File
;
2214 goto Next_Path_Component
;
2217 // This Path Component identifies an object, either a file or a
2218 // directory or an alias.
2220 // Decode it from the compressed data in ComponentIdentifier and find
2223 CompressionId
= PathComp
->ComponentIdentifier
[0];
2224 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2225 return EFI_VOLUME_CORRUPTED
;
2228 if ((UINTN
)PathComp
->ComponentIdentifier
+ PathCompLength
> (UINTN
)EndData
) {
2229 return EFI_VOLUME_CORRUPTED
;
2233 for (Index
= 1; Index
< PathCompLength
; Index
++) {
2234 if (CompressionId
== 16) {
2235 *Char
= *(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+
2239 if (Index
> ARRAY_SIZE (FileName
)) {
2240 return EFI_UNSUPPORTED
;
2245 if (Index
< Length
) {
2246 *Char
|= (CHAR16
)(*(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+ Index
));
2252 Index
= ((UINTN
)Char
- (UINTN
)FileName
) / sizeof (CHAR16
);
2253 if (Index
> ARRAY_SIZE (FileName
) - 1) {
2254 Index
= ARRAY_SIZE (FileName
) - 1;
2256 FileName
[Index
] = L
'\0';
2260 // According to the ECMA-167 standard (3rd Edition - June 1997), Section
2261 // 14.16.1.1, all other values are reserved.
2263 Status
= EFI_VOLUME_CORRUPTED
;
2264 goto Error_Find_File
;
2268 // Find file from the read filename in symlink's file data.
2270 Status
= InternalFindFile (
2279 if (EFI_ERROR (Status
)) {
2280 goto Error_Find_File
;
2283 Next_Path_Component
:
2284 Data
+= sizeof (UDF_PATH_COMPONENT
) + PathCompLength
;
2285 if (Data
>= EndData
) {
2290 // Check the content in the file info pointed by File.
2292 if ((File
->FileEntry
== NULL
) || (File
->FileIdentifierDesc
== NULL
)) {
2293 Status
= EFI_VOLUME_CORRUPTED
;
2294 goto Error_Find_File
;
2297 NotParent
= (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
2298 sizeof (UDF_FILE_INFO
)) != 0);
2299 NotFile
= (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)File
,
2300 sizeof (UDF_FILE_INFO
)) != 0);
2302 if (NotParent
&& NotFile
) {
2303 CleanupFileInformation (&PreviousFile
);
2307 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
2312 // Unmap the symlink file.
2314 FreePool (ReadFileInfo
.FileData
);
2317 // Check the content in the resolved file info.
2319 if ((File
->FileEntry
== NULL
) || (File
->FileIdentifierDesc
== NULL
)) {
2320 return EFI_VOLUME_CORRUPTED
;
2326 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
2327 sizeof (UDF_FILE_INFO
)) != 0) {
2328 CleanupFileInformation (&PreviousFile
);
2331 FreePool (ReadFileInfo
.FileData
);
2337 Clean up in-memory UDF file information.
2339 @param[in] File File information pointer.
2343 CleanupFileInformation (
2344 IN UDF_FILE_INFO
*File
2347 if (File
->FileEntry
!= NULL
) {
2348 FreePool (File
->FileEntry
);
2350 if (File
->FileIdentifierDesc
!= NULL
) {
2351 FreePool ((VOID
*)File
->FileIdentifierDesc
);
2354 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
2358 Find a file from its absolute path on an UDF volume.
2360 @param[in] BlockIo BlockIo interface.
2361 @param[in] DiskIo DiskIo interface.
2362 @param[in] Volume UDF volume information structure.
2363 @param[in] File File information structure.
2364 @param[out] Size Size of the file.
2366 @retval EFI_SUCCESS File size calculated and set in Size.
2367 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2368 @retval EFI_NO_MEDIA The device has no media.
2369 @retval EFI_DEVICE_ERROR The device reported an error.
2370 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2371 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2377 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2378 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2379 IN UDF_VOLUME_INFO
*Volume
,
2380 IN UDF_FILE_INFO
*File
,
2385 UDF_READ_FILE_INFO ReadFileInfo
;
2387 ReadFileInfo
.Flags
= ReadFileGetFileSize
;
2393 &File
->FileIdentifierDesc
->Icb
,
2397 if (EFI_ERROR (Status
)) {
2401 *Size
= ReadFileInfo
.ReadLength
;
2407 Set information about a file on an UDF volume.
2409 @param[in] File File pointer.
2410 @param[in] FileSize Size of the file.
2411 @param[in] FileName Filename of the file.
2412 @param[in, out] BufferSize Size of the returned file infomation.
2413 @param[out] Buffer Data of the returned file information.
2415 @retval EFI_SUCCESS File information set.
2416 @retval EFI_NO_MEDIA The device has no media.
2417 @retval EFI_DEVICE_ERROR The device reported an error.
2418 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2419 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2425 IN UDF_FILE_INFO
*File
,
2427 IN CHAR16
*FileName
,
2428 IN OUT UINTN
*BufferSize
,
2432 UINTN FileInfoLength
;
2433 EFI_FILE_INFO
*FileInfo
;
2434 UDF_FILE_ENTRY
*FileEntry
;
2435 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
2436 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
2439 // Calculate the needed size for the EFI_FILE_INFO structure.
2441 FileInfoLength
= sizeof (EFI_FILE_INFO
) + ((FileName
!= NULL
) ?
2442 StrSize (FileName
) :
2444 if (*BufferSize
< FileInfoLength
) {
2446 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2448 *BufferSize
= FileInfoLength
;
2449 return EFI_BUFFER_TOO_SMALL
;
2453 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2454 // Now, fill it in with all necessary information about the file.
2456 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
2457 FileInfo
->Size
= FileInfoLength
;
2458 FileInfo
->Attribute
&= ~EFI_FILE_VALID_ATTR
;
2459 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
2461 if (IS_FID_DIRECTORY_FILE (File
->FileIdentifierDesc
)) {
2462 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
2463 } else if (IS_FID_NORMAL_FILE (File
->FileIdentifierDesc
)) {
2464 FileInfo
->Attribute
|= EFI_FILE_ARCHIVE
;
2467 if (IS_FID_HIDDEN_FILE (File
->FileIdentifierDesc
)) {
2468 FileInfo
->Attribute
|= EFI_FILE_HIDDEN
;
2471 DescriptorTag
= File
->FileEntry
;
2473 if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
2474 FileEntry
= (UDF_FILE_ENTRY
*)File
->FileEntry
;
2477 // Check if FE has the system attribute set.
2479 if (FileEntry
->IcbTag
.Flags
& (1 << 10)) {
2480 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2483 FileInfo
->FileSize
= FileSize
;
2484 FileInfo
->PhysicalSize
= FileSize
;
2486 FileInfo
->CreateTime
.Year
= FileEntry
->AccessTime
.Year
;
2487 FileInfo
->CreateTime
.Month
= FileEntry
->AccessTime
.Month
;
2488 FileInfo
->CreateTime
.Day
= FileEntry
->AccessTime
.Day
;
2489 FileInfo
->CreateTime
.Hour
= FileEntry
->AccessTime
.Hour
;
2490 FileInfo
->CreateTime
.Minute
= FileEntry
->AccessTime
.Minute
;
2491 FileInfo
->CreateTime
.Second
= FileEntry
->AccessTime
.Second
;
2492 FileInfo
->CreateTime
.Nanosecond
=
2493 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2495 FileInfo
->LastAccessTime
.Year
=
2496 FileEntry
->AccessTime
.Year
;
2497 FileInfo
->LastAccessTime
.Month
=
2498 FileEntry
->AccessTime
.Month
;
2499 FileInfo
->LastAccessTime
.Day
=
2500 FileEntry
->AccessTime
.Day
;
2501 FileInfo
->LastAccessTime
.Hour
=
2502 FileEntry
->AccessTime
.Hour
;
2503 FileInfo
->LastAccessTime
.Minute
=
2504 FileEntry
->AccessTime
.Minute
;
2505 FileInfo
->LastAccessTime
.Second
=
2506 FileEntry
->AccessTime
.Second
;
2507 FileInfo
->LastAccessTime
.Nanosecond
=
2508 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2509 } else if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
2510 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)File
->FileEntry
;
2513 // Check if EFE has the system attribute set.
2515 if (ExtendedFileEntry
->IcbTag
.Flags
& (1 << 10)) {
2516 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2519 FileInfo
->FileSize
= FileSize
;
2520 FileInfo
->PhysicalSize
= FileSize
;
2522 FileInfo
->CreateTime
.Year
= ExtendedFileEntry
->CreationTime
.Year
;
2523 FileInfo
->CreateTime
.Month
= ExtendedFileEntry
->CreationTime
.Month
;
2524 FileInfo
->CreateTime
.Day
= ExtendedFileEntry
->CreationTime
.Day
;
2525 FileInfo
->CreateTime
.Hour
= ExtendedFileEntry
->CreationTime
.Hour
;
2526 FileInfo
->CreateTime
.Minute
= ExtendedFileEntry
->CreationTime
.Second
;
2527 FileInfo
->CreateTime
.Second
= ExtendedFileEntry
->CreationTime
.Second
;
2528 FileInfo
->CreateTime
.Nanosecond
=
2529 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2531 FileInfo
->LastAccessTime
.Year
=
2532 ExtendedFileEntry
->AccessTime
.Year
;
2533 FileInfo
->LastAccessTime
.Month
=
2534 ExtendedFileEntry
->AccessTime
.Month
;
2535 FileInfo
->LastAccessTime
.Day
=
2536 ExtendedFileEntry
->AccessTime
.Day
;
2537 FileInfo
->LastAccessTime
.Hour
=
2538 ExtendedFileEntry
->AccessTime
.Hour
;
2539 FileInfo
->LastAccessTime
.Minute
=
2540 ExtendedFileEntry
->AccessTime
.Minute
;
2541 FileInfo
->LastAccessTime
.Second
=
2542 ExtendedFileEntry
->AccessTime
.Second
;
2543 FileInfo
->LastAccessTime
.Nanosecond
=
2544 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2547 FileInfo
->CreateTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2548 FileInfo
->CreateTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2549 FileInfo
->LastAccessTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2550 FileInfo
->LastAccessTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2552 CopyMem ((VOID
*)&FileInfo
->ModificationTime
,
2553 (VOID
*)&FileInfo
->LastAccessTime
,
2556 if (FileName
!= NULL
) {
2557 StrCpyS (FileInfo
->FileName
, StrLen (FileName
) + 1, FileName
);
2559 FileInfo
->FileName
[0] = '\0';
2562 *BufferSize
= FileInfoLength
;
2568 Get volume label of an UDF volume.
2570 @attention This is boundary function that may receive untrusted input.
2571 @attention The input is from FileSystem.
2573 The File Set Descriptor is external input, so this routine will do basic
2574 validation for File Set Descriptor and report status.
2576 @param[in] Volume Volume information pointer.
2577 @param[in] CharMax The maximum number of Unicode char in String,
2578 including terminating null char.
2579 @param[out] String String buffer pointer to store the volume label.
2581 @retval EFI_SUCCESS Volume label is returned.
2582 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2583 @retval EFI_BUFFER_TOO_SMALL The string buffer String cannot hold the
2589 IN UDF_VOLUME_INFO
*Volume
,
2594 UDF_FILE_SET_DESCRIPTOR
*FileSetDesc
;
2596 UINT8
*OstaCompressed
;
2597 UINT8 CompressionId
;
2600 FileSetDesc
= &Volume
->FileSetDesc
;
2602 OstaCompressed
= &FileSetDesc
->LogicalVolumeIdentifier
[0];
2604 CompressionId
= OstaCompressed
[0];
2605 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2606 return EFI_VOLUME_CORRUPTED
;
2610 for (Index
= 1; Index
< 128; Index
++) {
2611 if (CompressionId
== 16) {
2612 if ((Index
>> 1) > CharMax
) {
2613 return EFI_BUFFER_TOO_SMALL
;
2616 *String
= *(UINT8
*)(OstaCompressed
+ Index
) << 8;
2619 if (Index
> CharMax
) {
2620 return EFI_BUFFER_TOO_SMALL
;
2627 *String
|= (CHAR16
)(*(UINT8
*)(OstaCompressed
+ Index
));
2631 // Unlike FID Identifiers, Logical Volume Identifier is stored in a
2632 // NULL-terminated OSTA compressed format, so we must check for the NULL
2635 if (*String
== L
'\0') {
2642 Index
= ((UINTN
)String
- (UINTN
)StringBak
) / sizeof (CHAR16
);
2643 if (Index
> CharMax
- 1) {
2644 Index
= CharMax
- 1;
2646 StringBak
[Index
] = L
'\0';
2652 Get volume and free space size information of an UDF volume.
2654 @attention This is boundary function that may receive untrusted input.
2655 @attention The input is from FileSystem.
2657 The Logical Volume Descriptor and the Logical Volume Integrity Descriptor are
2658 external inputs, so this routine will do basic validation for both descriptors
2661 @param[in] BlockIo BlockIo interface.
2662 @param[in] DiskIo DiskIo interface.
2663 @param[in] Volume UDF volume information structure.
2664 @param[out] VolumeSize Volume size.
2665 @param[out] FreeSpaceSize Free space size.
2667 @retval EFI_SUCCESS Volume and free space size calculated.
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 volume and free space size were not
2672 calculated due to lack of resources.
2677 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2678 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2679 IN UDF_VOLUME_INFO
*Volume
,
2680 OUT UINT64
*VolumeSize
,
2681 OUT UINT64
*FreeSpaceSize
2685 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
2686 UDF_EXTENT_AD
*ExtentAd
;
2688 UINT32 LogicalBlockSize
;
2689 UDF_LOGICAL_VOLUME_INTEGRITY
*LogicalVolInt
;
2690 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
2695 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
2697 ExtentAd
= &LogicalVolDesc
->IntegritySequenceExtent
;
2699 if ((ExtentAd
->ExtentLength
== 0) ||
2700 (ExtentAd
->ExtentLength
< sizeof (UDF_LOGICAL_VOLUME_INTEGRITY
))) {
2701 return EFI_VOLUME_CORRUPTED
;
2704 LogicalVolInt
= AllocatePool (ExtentAd
->ExtentLength
);
2705 if (LogicalVolInt
== NULL
) {
2706 return EFI_OUT_OF_RESOURCES
;
2710 // Get location of Logical Volume Integrity Descriptor
2712 Lsn
= (UINT64
)ExtentAd
->ExtentLocation
- Volume
->MainVdsStartLocation
;
2714 LogicalBlockSize
= LogicalVolDesc
->LogicalBlockSize
;
2719 Status
= DiskIo
->ReadDisk (
2721 BlockIo
->Media
->MediaId
,
2722 MultU64x32 (Lsn
, LogicalBlockSize
),
2723 ExtentAd
->ExtentLength
,
2726 if (EFI_ERROR (Status
)) {
2730 DescriptorTag
= &LogicalVolInt
->DescriptorTag
;
2733 // Check if read block is a Logical Volume Integrity Descriptor
2735 if (DescriptorTag
->TagIdentifier
!= UdfLogicalVolumeIntegrityDescriptor
) {
2736 Status
= EFI_VOLUME_CORRUPTED
;
2740 if ((LogicalVolInt
->NumberOfPartitions
> MAX_UINT32
/ sizeof (UINT32
) / 2) ||
2741 (LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
) * 2 >
2742 ExtentAd
->ExtentLength
- sizeof (UDF_LOGICAL_VOLUME_INTEGRITY
))) {
2743 Status
= EFI_VOLUME_CORRUPTED
;
2750 Length
= LogicalVolInt
->NumberOfPartitions
;
2751 for (Index
= 0; Index
< Length
; Index
+= sizeof (UINT32
)) {
2752 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2754 // Check if size is not specified
2756 if (LsnsNo
== 0xFFFFFFFFUL
) {
2760 // Accumulate free space size
2762 *FreeSpaceSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2765 Length
= LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
) * 2;
2766 for (; Index
< Length
; Index
+= sizeof (UINT32
)) {
2767 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2769 // Check if size is not specified
2771 if (LsnsNo
== 0xFFFFFFFFUL
) {
2775 // Accumulate used volume space
2777 *VolumeSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2780 Status
= EFI_SUCCESS
;
2784 // Free Logical Volume Integrity Descriptor
2786 FreePool (LogicalVolInt
);
2792 Seek a file and read its data into memory on an UDF volume.
2794 @param[in] BlockIo BlockIo interface.
2795 @param[in] DiskIo DiskIo interface.
2796 @param[in] Volume UDF volume information structure.
2797 @param[in] File File information structure.
2798 @param[in] FileSize Size of the file.
2799 @param[in, out] FilePosition File position.
2800 @param[in, out] Buffer File data.
2801 @param[in, out] BufferSize Read size.
2803 @retval EFI_SUCCESS File seeked and read.
2804 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2805 @retval EFI_NO_MEDIA The device has no media.
2806 @retval EFI_DEVICE_ERROR The device reported an error.
2807 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2808 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2814 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2815 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2816 IN UDF_VOLUME_INFO
*Volume
,
2817 IN UDF_FILE_INFO
*File
,
2819 IN OUT UINT64
*FilePosition
,
2820 IN OUT VOID
*Buffer
,
2821 IN OUT UINT64
*BufferSize
2825 UDF_READ_FILE_INFO ReadFileInfo
;
2827 ReadFileInfo
.Flags
= ReadFileSeekAndRead
;
2828 ReadFileInfo
.FilePosition
= *FilePosition
;
2829 ReadFileInfo
.FileData
= Buffer
;
2830 ReadFileInfo
.FileDataSize
= *BufferSize
;
2831 ReadFileInfo
.FileSize
= FileSize
;
2837 &File
->FileIdentifierDesc
->Icb
,
2841 if (EFI_ERROR (Status
)) {
2845 *BufferSize
= ReadFileInfo
.FileDataSize
;
2846 *FilePosition
= ReadFileInfo
.FilePosition
;
2852 Check if ControllerHandle supports an UDF file system.
2854 @param[in] This Protocol instance pointer.
2855 @param[in] ControllerHandle Handle of device to test.
2857 @retval EFI_SUCCESS UDF file system found.
2858 @retval EFI_UNSUPPORTED UDF file system not found.
2862 SupportUdfFileSystem (
2863 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2864 IN EFI_HANDLE ControllerHandle
2868 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2869 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2870 EFI_DEVICE_PATH_PROTOCOL
*LastDevicePathNode
;
2871 EFI_GUID
*VendorDefinedGuid
;
2874 // Open Device Path protocol on ControllerHandle
2876 Status
= gBS
->OpenProtocol (
2878 &gEfiDevicePathProtocolGuid
,
2879 (VOID
**)&DevicePath
,
2880 This
->DriverBindingHandle
,
2882 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2884 if (EFI_ERROR (Status
)) {
2885 return EFI_UNSUPPORTED
;
2888 Status
= EFI_UNSUPPORTED
;
2891 // Get last Device Path node
2893 LastDevicePathNode
= NULL
;
2894 DevicePathNode
= DevicePath
;
2895 while (!IsDevicePathEnd (DevicePathNode
)) {
2896 LastDevicePathNode
= DevicePathNode
;
2897 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
2900 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2901 // of an UDF file system.
2903 if (LastDevicePathNode
!= NULL
&&
2904 DevicePathType (LastDevicePathNode
) == MEDIA_DEVICE_PATH
&&
2905 DevicePathSubType (LastDevicePathNode
) == MEDIA_VENDOR_DP
) {
2906 VendorDefinedGuid
= (EFI_GUID
*)((UINTN
)LastDevicePathNode
+
2907 OFFSET_OF (VENDOR_DEVICE_PATH
, Guid
));
2908 if (CompareGuid (VendorDefinedGuid
, &gUdfDevPathGuid
)) {
2909 Status
= EFI_SUCCESS
;
2914 // Close Device Path protocol on ControllerHandle
2916 gBS
->CloseProtocol (
2918 &gEfiDevicePathProtocolGuid
,
2919 This
->DriverBindingHandle
,