2 Handle on-disk format and volume structures in UDF/ECMA-167 file systems.
4 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
5 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 // Vendor-Defined Device Path GUID for UDF file system
21 EFI_GUID gUdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
24 Find the anchor volume descriptor pointer.
26 @param[in] BlockIo BlockIo interface.
27 @param[in] DiskIo DiskIo interface.
28 @param[out] AnchorPoint Anchor volume descriptor pointer.
30 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
31 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
32 @retval other Anchor volume descriptor pointer not found.
36 FindAnchorVolumeDescriptorPointer (
37 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
38 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
39 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
45 EFI_LBA DescriptorLBAs
[4];
47 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
49 BlockSize
= BlockIo
->Media
->BlockSize
;
50 EndLBA
= BlockIo
->Media
->LastBlock
;
51 DescriptorLBAs
[0] = 256;
52 DescriptorLBAs
[1] = EndLBA
- 256;
53 DescriptorLBAs
[2] = EndLBA
;
54 DescriptorLBAs
[3] = 512;
56 for (Index
= 0; Index
< ARRAY_SIZE (DescriptorLBAs
); Index
++) {
57 Status
= DiskIo
->ReadDisk (
59 BlockIo
->Media
->MediaId
,
60 MultU64x32 (DescriptorLBAs
[Index
], BlockSize
),
61 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
),
64 if (EFI_ERROR (Status
)) {
68 DescriptorTag
= &AnchorPoint
->DescriptorTag
;
71 // Check if read LBA has a valid AVDP descriptor.
73 if (DescriptorTag
->TagIdentifier
== UdfAnchorVolumeDescriptorPointer
) {
80 return EFI_VOLUME_CORRUPTED
;
84 Save the content of Logical Volume Descriptors and Partitions Descriptors in
87 @param[in] BlockIo BlockIo interface.
88 @param[in] DiskIo DiskIo interface.
89 @param[in] AnchorPoint Anchor volume descriptor pointer.
90 @param[out] Volume UDF volume information structure.
92 @retval EFI_SUCCESS The descriptors were saved.
93 @retval EFI_OUT_OF_RESOURCES The descriptors were not saved due to lack of
95 @retval other The descriptors were not saved due to
100 StartMainVolumeDescriptorSequence (
101 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
102 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
103 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
104 OUT UDF_VOLUME_INFO
*Volume
109 UDF_EXTENT_AD
*ExtentAd
;
110 EFI_LBA SeqStartBlock
;
112 BOOLEAN StopSequence
;
114 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
115 UINT32 LogicalBlockSize
;
117 BlockSize
= BlockIo
->Media
->BlockSize
;
118 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
121 // Allocate buffer for reading disk blocks
123 Buffer
= AllocateZeroPool ((UINTN
)BlockSize
);
124 if (Buffer
== NULL
) {
125 return EFI_OUT_OF_RESOURCES
;
129 // The logical partition created by Partition driver is relative to the main
130 // VDS extent location, so we start the Main Volume Descriptor Sequence at
133 // We don't need to check again if we have valid Volume Descriptors here since
134 // Partition driver already did.
137 SeqEndBlock
= SeqStartBlock
+ DivU64x32 ((UINT64
)ExtentAd
->ExtentLength
,
139 StopSequence
= FALSE
;
140 for (; SeqStartBlock
< SeqEndBlock
&& !StopSequence
; SeqStartBlock
++) {
144 Status
= BlockIo
->ReadBlocks (
146 BlockIo
->Media
->MediaId
,
151 if (EFI_ERROR (Status
)) {
155 DescriptorTag
= Buffer
;
157 switch (DescriptorTag
->TagIdentifier
) {
158 case UdfPartitionDescriptor
:
160 // Save Partition Descriptor
162 CopyMem (&Volume
->PartitionDesc
, Buffer
, sizeof (Volume
->PartitionDesc
));
165 case UdfLogicalVolumeDescriptor
:
167 // Save Logical Volume Descriptor
169 CopyMem (&Volume
->LogicalVolDesc
, Buffer
, sizeof (Volume
->LogicalVolDesc
));
172 case UdfTerminatingDescriptor
:
182 // Determine FE (File Entry) size
184 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
185 if (LogicalBlockSize
>= UDF_LOGICAL_SECTOR_SIZE
) {
186 Volume
->FileEntrySize
= (UINTN
)LogicalBlockSize
;
188 Volume
->FileEntrySize
= UDF_LOGICAL_SECTOR_SIZE
;
191 Status
= EFI_SUCCESS
;
195 // Free block read buffer
203 Return a Partition Descriptor given a Long Allocation Descriptor. This is
204 necessary to calculate the right extent (LongAd) offset which is added up
205 with partition's starting location.
207 @param[in] Volume Volume information pointer.
208 @param[in] LongAd Long Allocation Descriptor pointer.
210 @return A pointer to a Partition Descriptor.
213 UDF_PARTITION_DESCRIPTOR
*
215 IN UDF_VOLUME_INFO
*Volume
,
216 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
219 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
222 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
224 switch (LogicalVolDesc
->DomainIdentifier
.Suffix
.Domain
.UdfRevision
) {
232 // UDF 1.02 specification:
234 // There shall be exactly one prevailing Logical Volume Descriptor recorded
235 // per Volume Set. The Partition Maps field shall contain only Type 1
238 // UDF 1.50 through 2.60 specs say:
240 // For the purpose of interchange partition maps shall be limited to
241 // Partition Map type 1, except type 2 maps as described in the document.
243 // NOTE: Only one Type 1 (Physical) Partition is supported. It has been
244 // checked already in Partition driver for existence of a single Type 1
245 // Partition map. Hence, the 'PartitionReferenceNumber' field (the index
246 // used to access Partition Maps data within the Logical Volume Descriptor)
247 // in the Long Allocation Descriptor should be 0 to indicate there is only
250 if (LongAd
->ExtentLocation
.PartitionReferenceNumber
!= 0) {
254 // Since only one partition, get the first one directly.
256 PartitionNum
= *(UINT16
*)((UINTN
)&LogicalVolDesc
->PartitionMaps
[4]);
261 // Unsupported UDF revision
267 // Check if partition number matches Partition Descriptor found in Main Volume
268 // Descriptor Sequence.
270 if (Volume
->PartitionDesc
.PartitionNumber
== PartitionNum
) {
271 return &Volume
->PartitionDesc
;
278 Return logical sector number of a given Long Allocation Descriptor.
280 @param[in] Volume Volume information pointer.
281 @param[in] LongAd Long Allocation Descriptor pointer.
282 @param[out] Lsn Logical sector number pointer.
284 @retval EFI_SUCCESS Logical sector number successfully returned.
285 @retval EFI_UNSUPPORTED Logical sector number is not returned due to
291 IN UDF_VOLUME_INFO
*Volume
,
292 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
,
296 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
298 PartitionDesc
= GetPdFromLongAd (Volume
, LongAd
);
299 if (PartitionDesc
== NULL
) {
302 "%a: Fail to get the Partition Descriptor from the given Long Allocation Descriptor.\n",
305 return EFI_UNSUPPORTED
;
308 *Lsn
= (UINT64
)PartitionDesc
->PartitionStartingLocation
-
309 Volume
->MainVdsStartLocation
+
310 LongAd
->ExtentLocation
.LogicalBlockNumber
;
316 Return logical sector number of a given Short Allocation Descriptor.
318 @param[in] Volume Volume pointer.
319 @param[in] PartitionDesc Partition Descriptor pointer.
320 @param[in] ShortAd Short Allocation Descriptor pointer.
322 @return The logical sector number of a given Short Allocation Descriptor.
327 IN UDF_VOLUME_INFO
*Volume
,
328 IN UDF_PARTITION_DESCRIPTOR
*PartitionDesc
,
329 IN UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
332 return (UINT64
)PartitionDesc
->PartitionStartingLocation
-
333 Volume
->MainVdsStartLocation
+ ShortAd
->ExtentPosition
;
337 Find File Set Descriptor of a given Logical Volume Descriptor.
339 The found FSD will contain the extent (LogicalVolumeContentsUse) where our
342 @param[in] BlockIo BlockIo interface.
343 @param[in] DiskIo DiskIo interface.
344 @param[in] Volume Volume information pointer.
346 @retval EFI_SUCCESS File Set Descriptor pointer found.
347 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
348 @retval other File Set Descriptor pointer not found.
352 FindFileSetDescriptor (
353 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
354 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
355 IN UDF_VOLUME_INFO
*Volume
360 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
361 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
363 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
364 Status
= GetLongAdLsn (Volume
, &LogicalVolDesc
->LogicalVolumeContentsUse
, &Lsn
);
365 if (EFI_ERROR (Status
)) {
370 // As per UDF 2.60 specification:
372 // There shall be exactly one File Set Descriptor recorded per Logical
377 Status
= DiskIo
->ReadDisk (
379 BlockIo
->Media
->MediaId
,
380 MultU64x32 (Lsn
, LogicalVolDesc
->LogicalBlockSize
),
381 sizeof (Volume
->FileSetDesc
),
384 if (EFI_ERROR (Status
)) {
388 DescriptorTag
= &Volume
->FileSetDesc
.DescriptorTag
;
391 // Check if read block is a File Set Descriptor
393 if (DescriptorTag
->TagIdentifier
!= UdfFileSetDescriptor
) {
394 return EFI_VOLUME_CORRUPTED
;
401 Read Volume and File Structure on an UDF file system.
403 @param[in] BlockIo BlockIo interface.
404 @param[in] DiskIo DiskIo interface.
405 @param[out] Volume Volume information pointer.
407 @retval EFI_SUCCESS Volume and File Structure were read.
408 @retval other Volume and File Structure were not read.
412 ReadVolumeFileStructure (
413 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
414 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
415 OUT UDF_VOLUME_INFO
*Volume
419 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
420 UDF_EXTENT_AD
*ExtentAd
;
423 // Find Anchor Volume Descriptor Pointer
425 Status
= FindAnchorVolumeDescriptorPointer (
430 if (EFI_ERROR (Status
)) {
435 // Save Main VDS start block number
437 ExtentAd
= &AnchorPoint
.MainVolumeDescriptorSequenceExtent
;
439 Volume
->MainVdsStartLocation
= (UINT64
)ExtentAd
->ExtentLocation
;
442 // Start Main Volume Descriptor Sequence.
444 Status
= StartMainVolumeDescriptorSequence (
450 if (EFI_ERROR (Status
)) {
458 Calculate length of a given File Identifier Descriptor.
460 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
462 @return The length of a given File Identifier Descriptor.
466 GetFidDescriptorLength (
467 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
471 (INTN
)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR
, Data
[0]) + 3 +
472 FileIdentifierDesc
->LengthOfFileIdentifier
+
473 FileIdentifierDesc
->LengthOfImplementationUse
) >> 2) << 2
478 Duplicate a given File Identifier Descriptor.
480 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
481 @param[out] NewFileIdentifierDesc The duplicated File Identifier Descriptor.
486 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
487 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**NewFileIdentifierDesc
490 *NewFileIdentifierDesc
=
491 (UDF_FILE_IDENTIFIER_DESCRIPTOR
*)AllocateCopyPool (
492 (UINTN
) GetFidDescriptorLength (FileIdentifierDesc
), 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
)) {
572 return EFI_VOLUME_CORRUPTED
;
578 Get Allocation Descriptors' data information from a given FE/EFE.
580 @attention This is boundary function that may receive untrusted input.
581 @attention The input is from FileSystem.
583 The (Extended) File Entry is external input, so this routine will do basic
584 validation for (Extended) File Entry and report status.
586 @param[in] FileEntryData (Extended) File Entry pointer.
587 @param[in] FileEntrySize Size of the (Extended) File Entry specified
589 @param[out] AdsData Buffer contains the Allocation Descriptors'
590 data from a given FE/EFE.
591 @param[out] Length Length of the data in AdsData.
593 @retval EFI_SUCCESS The data and size of Allocation Descriptors
594 were read from the FE/EFE.
595 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
600 IN VOID
*FileEntryData
,
601 IN UINTN FileEntrySize
,
606 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
607 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
608 UDF_FILE_ENTRY
*FileEntry
;
610 DescriptorTag
= FileEntryData
;
612 if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
613 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
615 *Length
= ExtendedFileEntry
->LengthOfAllocationDescriptors
;
616 *AdsData
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
617 ExtendedFileEntry
->LengthOfExtendedAttributes
);
618 } else if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
619 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
621 *Length
= FileEntry
->LengthOfAllocationDescriptors
;
622 *AdsData
= (VOID
*)((UINT8
*)FileEntry
->Data
+
623 FileEntry
->LengthOfExtendedAttributes
);
626 if ((*Length
> FileEntrySize
) ||
627 ((UINTN
)FileEntryData
> (UINTN
)(*AdsData
)) ||
628 ((UINTN
)(*AdsData
) - (UINTN
)FileEntryData
> FileEntrySize
- *Length
)) {
629 return EFI_VOLUME_CORRUPTED
;
635 Read next Long Allocation Descriptor from a given file's data.
637 @param[in] Data File's data pointer.
638 @param[in,out] Offset Starting offset of the File's data to read.
639 @param[in] Length Length of the data to read.
640 @param[out] FoundLongAd Long Allocation Descriptor pointer.
642 @retval EFI_SUCCESS A Long Allocation Descriptor was found.
643 @retval EFI_DEVICE_ERROR No more Long Allocation Descriptors.
649 IN OUT UINT64
*Offset
,
651 OUT UDF_LONG_ALLOCATION_DESCRIPTOR
**FoundLongAd
654 UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
;
655 UDF_EXTENT_FLAGS ExtentFlags
;
658 if (*Offset
>= Length
) {
660 // No more Long Allocation Descriptors.
662 return EFI_DEVICE_ERROR
;
666 (UDF_LONG_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
669 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
670 // allocated AD, then return it.
672 ExtentFlags
= GET_EXTENT_FLAGS (LongAdsSequence
, LongAd
);
673 if (ExtentFlags
== ExtentIsNextExtent
||
674 ExtentFlags
== ExtentRecordedAndAllocated
) {
679 // This AD is either not recorded but allocated, or not recorded and not
680 // allocated. Skip it.
682 *Offset
+= AD_LENGTH (LongAdsSequence
);
685 *FoundLongAd
= LongAd
;
691 Read next Short Allocation Descriptor from a given file's data.
693 @param[in] Data File's data pointer.
694 @param[in,out] Offset Starting offset of the File's data to read.
695 @param[in] Length Length of the data to read.
696 @param[out] FoundShortAd Short Allocation Descriptor pointer.
698 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
699 @retval EFI_DEVICE_ERROR No more Short Allocation Descriptors.
705 IN OUT UINT64
*Offset
,
707 OUT UDF_SHORT_ALLOCATION_DESCRIPTOR
**FoundShortAd
710 UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
;
711 UDF_EXTENT_FLAGS ExtentFlags
;
714 if (*Offset
>= Length
) {
716 // No more Short Allocation Descriptors.
718 return EFI_DEVICE_ERROR
;
722 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
725 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
726 // allocated AD, then return it.
728 ExtentFlags
= GET_EXTENT_FLAGS (ShortAdsSequence
, ShortAd
);
729 if (ExtentFlags
== ExtentIsNextExtent
||
730 ExtentFlags
== ExtentRecordedAndAllocated
) {
735 // This AD is either not recorded but allocated, or not recorded and not
736 // allocated. Skip it.
738 *Offset
+= AD_LENGTH (ShortAdsSequence
);
741 *FoundShortAd
= ShortAd
;
747 Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
750 @param[in] RecordingFlags Flag to indicate the type of descriptor.
751 @param[in] Data File's data pointer.
752 @param[in,out] Offset Starting offset of the File's data to read.
753 @param[in] Length Length of the data to read.
754 @param[out] FoundAd Allocation Descriptor pointer.
756 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
757 @retval EFI_DEVICE_ERROR No more Allocation Descriptors.
758 Invalid type of descriptor was given.
762 GetAllocationDescriptor (
763 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
765 IN OUT UINT64
*Offset
,
770 if (RecordingFlags
== LongAdsSequence
) {
771 return GetLongAdFromAds (
775 (UDF_LONG_ALLOCATION_DESCRIPTOR
**)FoundAd
777 } else if (RecordingFlags
== ShortAdsSequence
) {
778 return GetShortAdFromAds (
782 (UDF_SHORT_ALLOCATION_DESCRIPTOR
**)FoundAd
787 // Code should never reach here.
790 return EFI_DEVICE_ERROR
;
794 Return logical sector number of either Short or Long Allocation Descriptor.
796 @param[in] RecordingFlags Flag to indicate the type of descriptor.
797 @param[in] Volume Volume information pointer.
798 @param[in] ParentIcb Long Allocation Descriptor pointer.
799 @param[in] Ad Allocation Descriptor pointer.
800 @param[out] Lsn Logical sector number pointer.
802 @retval EFI_SUCCESS Logical sector number of the given Allocation
803 Descriptor successfully returned.
804 @retval EFI_UNSUPPORTED Logical sector number of the given Allocation
805 Descriptor is not returned due to unrecognized
810 GetAllocationDescriptorLsn (
811 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
812 IN UDF_VOLUME_INFO
*Volume
,
813 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
818 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
820 if (RecordingFlags
== LongAdsSequence
) {
821 return GetLongAdLsn (Volume
, (UDF_LONG_ALLOCATION_DESCRIPTOR
*)Ad
, Lsn
);
822 } else if (RecordingFlags
== ShortAdsSequence
) {
823 PartitionDesc
= GetPdFromLongAd (Volume
, ParentIcb
);
824 if (PartitionDesc
== NULL
) {
825 return EFI_UNSUPPORTED
;
828 *Lsn
= GetShortAdLsn (
831 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)Ad
837 // Code should never reach here.
840 return EFI_UNSUPPORTED
;
844 Return offset + length of a given indirect Allocation Descriptor (AED).
846 @param[in] BlockIo BlockIo interface.
847 @param[in] DiskIo DiskIo interface.
848 @param[in] Volume Volume information pointer.
849 @param[in] ParentIcb Long Allocation Descriptor pointer.
850 @param[in] RecordingFlags Flag to indicate the type of descriptor.
851 @param[in] Ad Allocation Descriptor pointer.
852 @param[out] Offset Offset of a given indirect Allocation
854 @param[out] Length Length of a given indirect Allocation
857 @retval EFI_SUCCESS The offset and length were returned.
858 @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due
859 to lack of resources.
860 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
861 @retval other The offset and length were not returned.
866 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
867 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
868 IN UDF_VOLUME_INFO
*Volume
,
869 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
870 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
880 UINT32 LogicalBlockSize
;
881 UDF_ALLOCATION_EXTENT_DESCRIPTOR
*AllocExtDesc
;
882 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
884 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
885 Status
= GetAllocationDescriptorLsn (RecordingFlags
,
890 if (EFI_ERROR (Status
)) {
894 Data
= AllocatePool (ExtentLength
);
896 return EFI_OUT_OF_RESOURCES
;
899 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
904 Status
= DiskIo
->ReadDisk (
906 BlockIo
->Media
->MediaId
,
907 MultU64x32 (Lsn
, LogicalBlockSize
),
911 if (EFI_ERROR (Status
)) {
915 AllocExtDesc
= (UDF_ALLOCATION_EXTENT_DESCRIPTOR
*)Data
;
917 DescriptorTag
= &AllocExtDesc
->DescriptorTag
;
920 // Check if read extent contains a valid tag identifier for AED.
922 if (DescriptorTag
->TagIdentifier
!= UdfAllocationExtentDescriptor
) {
923 Status
= EFI_VOLUME_CORRUPTED
;
928 // Get AED's block offset and its length.
930 *Offset
= MultU64x32 (Lsn
, LogicalBlockSize
) +
931 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR
);
932 *Length
= AllocExtDesc
->LengthOfAllocationDescriptors
;
941 Read Allocation Extent Descriptor into memory.
943 @param[in] BlockIo BlockIo interface.
944 @param[in] DiskIo DiskIo interface.
945 @param[in] Volume Volume information pointer.
946 @param[in] ParentIcb Long Allocation Descriptor pointer.
947 @param[in] RecordingFlags Flag to indicate the type of descriptor.
948 @param[in] Ad Allocation Descriptor pointer.
949 @param[out] Data Buffer that contains the Allocation Extent
951 @param[out] Length Length of Data.
953 @retval EFI_SUCCESS The Allocation Extent Descriptor was read.
954 @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read
955 due to lack of resources.
956 @retval other Fail to read the disk.
961 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
962 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
963 IN UDF_VOLUME_INFO
*Volume
,
964 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
965 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
975 // Get AED's offset + length.
977 Status
= GetAedAdsOffset (
987 if (EFI_ERROR (Status
)) {
992 // Allocate buffer to read in AED's data.
994 *Data
= AllocatePool ((UINTN
) (*Length
));
996 return EFI_OUT_OF_RESOURCES
;
999 return DiskIo
->ReadDisk (
1001 BlockIo
->Media
->MediaId
,
1009 Function used to serialise reads of Allocation Descriptors.
1011 @param[in] RecordingFlags Flag to indicate the type of descriptor.
1012 @param[in] Ad Allocation Descriptor pointer.
1013 @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.
1014 @param[in] Length Length of Buffer.
1016 @retval EFI_SUCCESS Buffer was grown to hold the next Allocation
1018 @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.
1022 GrowUpBufferToNextAd (
1023 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
1025 IN OUT VOID
**Buffer
,
1029 UINT32 ExtentLength
;
1031 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1033 if (*Buffer
== NULL
) {
1034 *Buffer
= AllocatePool (ExtentLength
);
1035 if (*Buffer
== NULL
) {
1036 return EFI_OUT_OF_RESOURCES
;
1039 *Buffer
= ReallocatePool ((UINTN
) Length
, (UINTN
) (Length
+ ExtentLength
), *Buffer
);
1040 if (*Buffer
== NULL
) {
1041 return EFI_OUT_OF_RESOURCES
;
1049 Read data or size of either a File Entry or an Extended File Entry.
1051 @param[in] BlockIo BlockIo interface.
1052 @param[in] DiskIo DiskIo interface.
1053 @param[in] Volume Volume information pointer.
1054 @param[in] ParentIcb Long Allocation Descriptor pointer.
1055 @param[in] FileEntryData FE/EFE structure pointer.
1056 @param[in, out] ReadFileInfo Read file information pointer.
1058 @retval EFI_SUCCESS Data or size of a FE/EFE was read.
1059 @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to
1061 @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is
1063 @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData
1065 @retval other Data or size of a FE/EFE was not read.
1070 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1071 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1072 IN UDF_VOLUME_INFO
*Volume
,
1073 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1074 IN VOID
*FileEntryData
,
1075 IN OUT UDF_READ_FILE_INFO
*ReadFileInfo
1079 UINT32 LogicalBlockSize
;
1087 UINT64 FilePosition
;
1092 BOOLEAN FinishedSeeking
;
1093 UINT32 ExtentLength
;
1094 UDF_FE_RECORDING_FLAGS RecordingFlags
;
1096 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
1100 // set BytesLeft to suppress incorrect compiler/analyzer warnings
1105 FinishedSeeking
= FALSE
;
1108 switch (ReadFileInfo
->Flags
) {
1109 case ReadFileGetFileSize
:
1110 case ReadFileAllocateAndRead
:
1112 // Initialise ReadFileInfo structure for either getting file size, or
1113 // reading file's recorded data.
1115 ReadFileInfo
->ReadLength
= 0;
1116 ReadFileInfo
->FileData
= NULL
;
1118 case ReadFileSeekAndRead
:
1120 // About to seek a file and/or read its data.
1122 Length
= ReadFileInfo
->FileSize
- ReadFileInfo
->FilePosition
;
1123 if (ReadFileInfo
->FileDataSize
> Length
) {
1125 // About to read beyond the EOF -- truncate it.
1127 ReadFileInfo
->FileDataSize
= Length
;
1131 // Initialise data to start seeking and/or reading a file.
1133 BytesLeft
= ReadFileInfo
->FileDataSize
;
1136 FinishedSeeking
= FALSE
;
1141 RecordingFlags
= GET_FE_RECORDING_FLAGS (FileEntryData
);
1142 switch (RecordingFlags
) {
1145 // There are no extents for this FE/EFE. All data is inline.
1147 Status
= GetFileEntryData (FileEntryData
, Volume
->FileEntrySize
, &Data
, &Length
);
1148 if (EFI_ERROR (Status
)) {
1152 if (ReadFileInfo
->Flags
== ReadFileGetFileSize
) {
1153 ReadFileInfo
->ReadLength
= Length
;
1154 } else if (ReadFileInfo
->Flags
== ReadFileAllocateAndRead
) {
1156 // Allocate buffer for starting read data.
1158 ReadFileInfo
->FileData
= AllocatePool ((UINTN
) Length
);
1159 if (ReadFileInfo
->FileData
== NULL
) {
1160 return EFI_OUT_OF_RESOURCES
;
1164 // Read all inline data into ReadFileInfo->FileData
1166 CopyMem (ReadFileInfo
->FileData
, Data
, (UINTN
) Length
);
1167 ReadFileInfo
->ReadLength
= Length
;
1168 } else if (ReadFileInfo
->Flags
== ReadFileSeekAndRead
) {
1170 // If FilePosition is non-zero, seek file to FilePosition, read
1171 // FileDataSize bytes and then updates FilePosition.
1174 ReadFileInfo
->FileData
,
1175 (VOID
*)((UINT8
*)Data
+ ReadFileInfo
->FilePosition
),
1176 (UINTN
) ReadFileInfo
->FileDataSize
1179 ReadFileInfo
->FilePosition
+= ReadFileInfo
->FileDataSize
;
1182 return EFI_INVALID_PARAMETER
;
1185 Status
= EFI_SUCCESS
;
1188 case LongAdsSequence
:
1189 case ShortAdsSequence
:
1191 // This FE/EFE contains a run of Allocation Descriptors. Get data + size
1192 // for start reading them out.
1194 Status
= GetAdsInformation (FileEntryData
, Volume
->FileEntrySize
, &Data
, &Length
);
1195 if (EFI_ERROR (Status
)) {
1205 Status
= GetAllocationDescriptor (
1212 if (Status
== EFI_DEVICE_ERROR
) {
1213 Status
= EFI_SUCCESS
;
1218 // Check if AD is an indirect AD. If so, read Allocation Extent
1219 // Descriptor and its extents (ADs).
1221 if (GET_EXTENT_FLAGS (RecordingFlags
, Ad
) == ExtentIsNextExtent
) {
1223 Status
= GetAedAdsData (
1240 if (EFI_ERROR (Status
)) {
1243 ASSERT (Data
!= NULL
);
1249 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1251 Status
= GetAllocationDescriptorLsn (RecordingFlags
,
1256 if (EFI_ERROR (Status
)) {
1260 switch (ReadFileInfo
->Flags
) {
1261 case ReadFileGetFileSize
:
1262 ReadFileInfo
->ReadLength
+= ExtentLength
;
1264 case ReadFileAllocateAndRead
:
1266 // Increase FileData (if necessary) to read next extent.
1268 Status
= GrowUpBufferToNextAd (
1271 &ReadFileInfo
->FileData
,
1272 ReadFileInfo
->ReadLength
1274 if (EFI_ERROR (Status
)) {
1275 goto Error_Alloc_Buffer_To_Next_Ad
;
1279 // Read extent's data into FileData.
1281 Status
= DiskIo
->ReadDisk (
1283 BlockIo
->Media
->MediaId
,
1284 MultU64x32 (Lsn
, LogicalBlockSize
),
1286 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1287 ReadFileInfo
->ReadLength
)
1289 if (EFI_ERROR (Status
)) {
1290 goto Error_Read_Disk_Blk
;
1293 ReadFileInfo
->ReadLength
+= ExtentLength
;
1295 case ReadFileSeekAndRead
:
1297 // Seek file first before reading in its data.
1299 if (FinishedSeeking
) {
1301 goto Skip_File_Seek
;
1304 if (FilePosition
+ ExtentLength
< ReadFileInfo
->FilePosition
) {
1305 FilePosition
+= ExtentLength
;
1309 if (FilePosition
+ ExtentLength
> ReadFileInfo
->FilePosition
) {
1310 Offset
= ReadFileInfo
->FilePosition
- FilePosition
;
1316 // Done with seeking file. Start reading its data.
1318 FinishedSeeking
= TRUE
;
1322 // Make sure we don't read more data than really wanted.
1324 if (ExtentLength
- Offset
> BytesLeft
) {
1325 DataLength
= BytesLeft
;
1327 DataLength
= ExtentLength
- Offset
;
1331 // Read extent's data into FileData.
1333 Status
= DiskIo
->ReadDisk (
1335 BlockIo
->Media
->MediaId
,
1336 Offset
+ MultU64x32 (Lsn
, LogicalBlockSize
),
1338 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1341 if (EFI_ERROR (Status
)) {
1342 goto Error_Read_Disk_Blk
;
1346 // Update current file's position.
1348 DataOffset
+= DataLength
;
1349 ReadFileInfo
->FilePosition
+= DataLength
;
1351 BytesLeft
-= DataLength
;
1352 if (BytesLeft
== 0) {
1354 // There is no more file data to read.
1356 Status
= EFI_SUCCESS
;
1365 // Point to the next AD (extent).
1367 AdOffset
+= AD_LENGTH (RecordingFlags
);
1371 case ExtendedAdsSequence
:
1372 // FIXME: Not supported. Got no volume with it, yet.
1374 Status
= EFI_UNSUPPORTED
;
1379 // A flag value reserved by the ECMA-167 standard (3rd Edition - June
1380 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
1382 Status
= EFI_UNSUPPORTED
;
1393 Error_Read_Disk_Blk
:
1394 Error_Alloc_Buffer_To_Next_Ad
:
1395 if (ReadFileInfo
->Flags
!= ReadFileSeekAndRead
) {
1396 FreePool (ReadFileInfo
->FileData
);
1408 Find a file by its filename from a given Parent file.
1410 @param[in] BlockIo BlockIo interface.
1411 @param[in] DiskIo DiskIo interface.
1412 @param[in] Volume Volume information pointer.
1413 @param[in] FileName File name string.
1414 @param[in] Parent Parent directory file.
1415 @param[in] Icb Long Allocation Descriptor pointer.
1416 @param[out] File Found file.
1418 @retval EFI_SUCCESS The file was found.
1419 @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.
1420 @retval EFI_NOT_FOUND The file was not found.
1425 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1426 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1427 IN UDF_VOLUME_INFO
*Volume
,
1428 IN CHAR16
*FileName
,
1429 IN UDF_FILE_INFO
*Parent
,
1430 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1431 OUT UDF_FILE_INFO
*File
1435 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1436 UDF_READ_DIRECTORY_INFO ReadDirInfo
;
1438 CHAR16 FoundFileName
[UDF_FILENAME_LENGTH
];
1439 VOID
*CompareFileEntry
;
1442 // Check if both Parent->FileIdentifierDesc and Icb are NULL.
1444 if ((Parent
->FileIdentifierDesc
== NULL
) && (Icb
== NULL
)) {
1445 return EFI_INVALID_PARAMETER
;
1449 // Check if parent file is really directory.
1451 if (FE_ICB_FILE_TYPE (Parent
->FileEntry
) != UdfFileEntryDirectory
) {
1452 return EFI_NOT_FOUND
;
1456 // If FileName is current file or working directory, just duplicate Parent's
1457 // FE/EFE and FID descriptors.
1459 if (StrCmp (FileName
, L
".") == 0) {
1460 if (Parent
->FileIdentifierDesc
== NULL
) {
1461 return EFI_INVALID_PARAMETER
;
1464 DuplicateFe (BlockIo
, Volume
, Parent
->FileEntry
, &File
->FileEntry
);
1465 if (File
->FileEntry
== NULL
) {
1466 return EFI_OUT_OF_RESOURCES
;
1469 DuplicateFid (Parent
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1470 if (File
->FileIdentifierDesc
== NULL
) {
1471 FreePool (File
->FileEntry
);
1472 return EFI_OUT_OF_RESOURCES
;
1479 // Start directory listing.
1481 ZeroMem ((VOID
*)&ReadDirInfo
, sizeof (UDF_READ_DIRECTORY_INFO
));
1485 Status
= ReadDirectoryEntry (
1489 (Parent
->FileIdentifierDesc
!= NULL
) ?
1490 &Parent
->FileIdentifierDesc
->Icb
:
1496 if (EFI_ERROR (Status
)) {
1497 if (Status
== EFI_DEVICE_ERROR
) {
1498 Status
= EFI_NOT_FOUND
;
1504 // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is
1505 // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code
1506 // reaches here, 'FileIdentifierDesc' must be not NULL.
1508 // The ASSERT here is for addressing a false positive NULL pointer
1509 // dereference issue raised from static analysis.
1511 ASSERT (FileIdentifierDesc
!= NULL
);
1513 if (FileIdentifierDesc
->FileCharacteristics
& PARENT_FILE
) {
1515 // This FID contains the location (FE/EFE) of the parent directory of this
1516 // directory (Parent), and if FileName is either ".." or "\\", then it's
1517 // the expected FID.
1519 if (StrCmp (FileName
, L
"..") == 0 || StrCmp (FileName
, L
"\\") == 0) {
1524 Status
= GetFileNameFromFid (FileIdentifierDesc
, ARRAY_SIZE (FoundFileName
), FoundFileName
);
1525 if (EFI_ERROR (Status
)) {
1529 if (StrCmp (FileName
, FoundFileName
) == 0) {
1531 // FID has been found. Prepare to find its respective FE/EFE.
1538 FreePool ((VOID
*)FileIdentifierDesc
);
1541 if (ReadDirInfo
.DirectoryData
!= NULL
) {
1543 // Free all allocated resources for the directory listing.
1545 FreePool (ReadDirInfo
.DirectoryData
);
1549 Status
= EFI_SUCCESS
;
1551 File
->FileIdentifierDesc
= FileIdentifierDesc
;
1554 // If the requested file is root directory, then the FE/EFE was already
1555 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1557 // Otherwise, find FE/EFE from the respective FID.
1559 if (StrCmp (FileName
, L
"\\") != 0) {
1560 Status
= FindFileEntry (
1564 &FileIdentifierDesc
->Icb
,
1567 if (EFI_ERROR (Status
)) {
1572 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1574 if (CompareMem ((VOID
*)Parent
->FileEntry
, (VOID
*)CompareFileEntry
,
1575 Volume
->FileEntrySize
) != 0) {
1576 File
->FileEntry
= CompareFileEntry
;
1578 FreePool ((VOID
*)FileIdentifierDesc
);
1579 FreePool ((VOID
*)CompareFileEntry
);
1580 Status
= EFI_NOT_FOUND
;
1588 FreePool ((VOID
*)FileIdentifierDesc
);
1594 Read volume information on a medium which contains a valid UDF file system.
1596 @param[in] BlockIo BlockIo interface.
1597 @param[in] DiskIo DiskIo interface.
1598 @param[out] Volume UDF volume information structure.
1600 @retval EFI_SUCCESS Volume information read.
1601 @retval EFI_NO_MEDIA The device has no media.
1602 @retval EFI_DEVICE_ERROR The device reported an error.
1603 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1604 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1608 ReadUdfVolumeInformation (
1609 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1610 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1611 OUT UDF_VOLUME_INFO
*Volume
1617 // Read all necessary UDF volume information and keep it private to the driver
1619 Status
= ReadVolumeFileStructure (
1624 if (EFI_ERROR (Status
)) {
1629 // Find File Set Descriptor
1631 Status
= FindFileSetDescriptor (BlockIo
, DiskIo
, Volume
);
1632 if (EFI_ERROR (Status
)) {
1640 Find the root directory on an UDF volume.
1642 @param[in] BlockIo BlockIo interface.
1643 @param[in] DiskIo DiskIo interface.
1644 @param[in] Volume UDF volume information structure.
1645 @param[out] File Root directory file.
1647 @retval EFI_SUCCESS Root directory found.
1648 @retval EFI_NO_MEDIA The device has no media.
1649 @retval EFI_DEVICE_ERROR The device reported an error.
1650 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1651 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1657 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1658 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1659 IN UDF_VOLUME_INFO
*Volume
,
1660 OUT UDF_FILE_INFO
*File
1664 UDF_FILE_INFO Parent
;
1666 Status
= FindFileEntry (
1670 &Volume
->FileSetDesc
.RootDirectoryIcb
,
1673 if (EFI_ERROR (Status
)) {
1677 Parent
.FileEntry
= File
->FileEntry
;
1678 Parent
.FileIdentifierDesc
= NULL
;
1687 &Volume
->FileSetDesc
.RootDirectoryIcb
,
1690 if (EFI_ERROR (Status
)) {
1691 FreePool (File
->FileEntry
);
1698 Find either a File Entry or a Extended File Entry from a given ICB.
1700 @param[in] BlockIo BlockIo interface.
1701 @param[in] DiskIo DiskIo interface.
1702 @param[in] Volume UDF volume information structure.
1703 @param[in] Icb ICB of the FID.
1704 @param[out] FileEntry File Entry or Extended File Entry.
1706 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1707 @retval EFI_NO_MEDIA The device has no media.
1708 @retval EFI_DEVICE_ERROR The device reported an error.
1709 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1710 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1716 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1717 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1718 IN UDF_VOLUME_INFO
*Volume
,
1719 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1720 OUT VOID
**FileEntry
1725 UINT32 LogicalBlockSize
;
1726 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
1729 Status
= GetLongAdLsn (Volume
, Icb
, &Lsn
);
1730 if (EFI_ERROR (Status
)) {
1734 LogicalBlockSize
= Volume
->LogicalVolDesc
.LogicalBlockSize
;
1736 ReadBuffer
= AllocateZeroPool (Volume
->FileEntrySize
);
1737 if (ReadBuffer
== NULL
) {
1738 return EFI_OUT_OF_RESOURCES
;
1744 Status
= DiskIo
->ReadDisk (
1746 BlockIo
->Media
->MediaId
,
1747 MultU64x32 (Lsn
, LogicalBlockSize
),
1748 Volume
->FileEntrySize
,
1751 if (EFI_ERROR (Status
)) {
1752 goto Error_Read_Disk_Blk
;
1755 DescriptorTag
= ReadBuffer
;
1758 // Check if the read extent contains a valid Tag Identifier for the expected
1761 if (DescriptorTag
->TagIdentifier
!= UdfFileEntry
&&
1762 DescriptorTag
->TagIdentifier
!= UdfExtendedFileEntry
) {
1763 Status
= EFI_VOLUME_CORRUPTED
;
1764 goto Error_Invalid_Fe
;
1767 *FileEntry
= ReadBuffer
;
1771 Error_Read_Disk_Blk
:
1772 FreePool (ReadBuffer
);
1778 Find a file given its absolute path on an UDF volume.
1780 @param[in] BlockIo BlockIo interface.
1781 @param[in] DiskIo DiskIo interface.
1782 @param[in] Volume UDF volume information structure.
1783 @param[in] FilePath File's absolute path.
1784 @param[in] Root Root directory file.
1785 @param[in] Parent Parent directory file.
1786 @param[in] Icb ICB of Parent.
1787 @param[out] File Found file.
1789 @retval EFI_SUCCESS FilePath was found.
1790 @retval EFI_NO_MEDIA The device has no media.
1791 @retval EFI_DEVICE_ERROR The device reported an error.
1792 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1793 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
1799 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1800 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1801 IN UDF_VOLUME_INFO
*Volume
,
1802 IN CHAR16
*FilePath
,
1803 IN UDF_FILE_INFO
*Root
,
1804 IN UDF_FILE_INFO
*Parent
,
1805 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1806 OUT UDF_FILE_INFO
*File
1810 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1811 CHAR16
*FileNamePointer
;
1812 UDF_FILE_INFO PreviousFile
;
1815 Status
= EFI_NOT_FOUND
;
1817 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1818 while (*FilePath
!= L
'\0') {
1819 FileNamePointer
= FileName
;
1820 while (*FilePath
!= L
'\0' && *FilePath
!= L
'\\') {
1821 if ((((UINTN
)FileNamePointer
- (UINTN
)FileName
) / sizeof (CHAR16
)) >=
1822 (ARRAY_SIZE (FileName
) - 1)) {
1823 return EFI_NOT_FOUND
;
1826 *FileNamePointer
++ = *FilePath
++;
1829 *FileNamePointer
= L
'\0';
1830 if (FileName
[0] == L
'\0') {
1832 // Open root directory.
1836 // There is no file found for the root directory yet. So, find only its
1839 // See UdfOpenVolume() function.
1841 Status
= InternalFindFile (BlockIo
,
1850 // We've already a file pointer (Root) for the root directory. Duplicate
1851 // its FE/EFE and FID descriptors.
1853 Status
= EFI_SUCCESS
;
1854 DuplicateFe (BlockIo
, Volume
, Root
->FileEntry
, &File
->FileEntry
);
1855 if (File
->FileEntry
== NULL
) {
1856 Status
= EFI_OUT_OF_RESOURCES
;
1859 // File->FileEntry is not NULL.
1861 DuplicateFid (Root
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1862 if (File
->FileIdentifierDesc
== NULL
) {
1863 FreePool (File
->FileEntry
);
1864 Status
= EFI_OUT_OF_RESOURCES
;
1870 // No root directory. Find filename from the current directory.
1872 Status
= InternalFindFile (BlockIo
,
1881 if (EFI_ERROR (Status
)) {
1886 // If the found file is a symlink, then find its respective FE/EFE and
1889 if (FE_ICB_FILE_TYPE (File
->FileEntry
) == UdfFileEntrySymlink
) {
1890 FreePool ((VOID
*)File
->FileIdentifierDesc
);
1892 FileEntry
= File
->FileEntry
;
1894 Status
= ResolveSymlink (BlockIo
,
1901 FreePool (FileEntry
);
1903 if (EFI_ERROR (Status
)) {
1908 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1909 sizeof (UDF_FILE_INFO
)) != 0) {
1910 CleanupFileInformation (&PreviousFile
);
1913 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1914 if (*FilePath
!= L
'\0' && *FilePath
== L
'\\') {
1923 Read a directory entry at a time on an UDF volume.
1925 @param[in] BlockIo BlockIo interface.
1926 @param[in] DiskIo DiskIo interface.
1927 @param[in] Volume UDF volume information structure.
1928 @param[in] ParentIcb ICB of the parent file.
1929 @param[in] FileEntryData FE/EFE of the parent file.
1930 @param[in, out] ReadDirInfo Next read directory listing structure
1932 @param[out] FoundFid File Identifier Descriptor pointer.
1934 @retval EFI_SUCCESS Directory entry read.
1935 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1936 @retval EFI_NO_MEDIA The device has no media.
1937 @retval EFI_DEVICE_ERROR The device reported an error.
1938 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1939 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1944 ReadDirectoryEntry (
1945 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1946 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1947 IN UDF_VOLUME_INFO
*Volume
,
1948 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1949 IN VOID
*FileEntryData
,
1950 IN OUT UDF_READ_DIRECTORY_INFO
*ReadDirInfo
,
1951 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**FoundFid
1955 UDF_READ_FILE_INFO ReadFileInfo
;
1956 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1958 if (ReadDirInfo
->DirectoryData
== NULL
) {
1960 // The directory's recorded data has not been read yet. So let's cache it
1961 // into memory and the next calls won't need to read it again.
1963 ReadFileInfo
.Flags
= ReadFileAllocateAndRead
;
1973 if (EFI_ERROR (Status
)) {
1978 // Fill in ReadDirInfo structure with the read directory's data information.
1980 ReadDirInfo
->DirectoryData
= ReadFileInfo
.FileData
;
1981 ReadDirInfo
->DirectoryLength
= ReadFileInfo
.ReadLength
;
1985 if (ReadDirInfo
->FidOffset
>= ReadDirInfo
->DirectoryLength
) {
1987 // There are no longer FIDs for this directory. By returning
1988 // EFI_DEVICE_ERROR to the callee will indicate end of directory
1991 return EFI_DEVICE_ERROR
;
1995 // Get FID for this entry.
1997 FileIdentifierDesc
= GET_FID_FROM_ADS (ReadDirInfo
->DirectoryData
,
1998 ReadDirInfo
->FidOffset
);
2000 // Update FidOffset to point to next FID.
2002 ReadDirInfo
->FidOffset
+= GetFidDescriptorLength (FileIdentifierDesc
);
2003 } while (FileIdentifierDesc
->FileCharacteristics
& DELETED_FILE
);
2005 DuplicateFid (FileIdentifierDesc
, FoundFid
);
2006 if (*FoundFid
== NULL
) {
2007 return EFI_OUT_OF_RESOURCES
;
2014 Get a filename (encoded in OSTA-compressed format) from a File Identifier
2015 Descriptor on an UDF volume.
2017 @attention This is boundary function that may receive untrusted input.
2018 @attention The input is from FileSystem.
2020 The File Identifier Descriptor is external input, so this routine will do
2021 basic validation for File Identifier Descriptor and report status.
2023 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
2024 @param[in] CharMax The maximum number of FileName Unicode char,
2025 including terminating null char.
2026 @param[out] FileName Decoded filename.
2028 @retval EFI_SUCCESS Filename decoded and read.
2029 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2030 @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
2034 GetFileNameFromFid (
2035 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
2037 OUT CHAR16
*FileName
2040 UINT8
*OstaCompressed
;
2041 UINT8 CompressionId
;
2044 CHAR16
*FileNameBak
;
2047 return EFI_BUFFER_TOO_SMALL
;
2052 (UINT8
*)FileIdentifierDesc
->Data
+
2053 FileIdentifierDesc
->LengthOfImplementationUse
2056 CompressionId
= OstaCompressed
[0];
2057 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2058 return EFI_VOLUME_CORRUPTED
;
2061 FileNameBak
= FileName
;
2066 Length
= FileIdentifierDesc
->LengthOfFileIdentifier
;
2067 if (CompressionId
== 16) {
2068 if (((UINTN
)Length
>> 1) > CharMax
) {
2069 return EFI_BUFFER_TOO_SMALL
;
2072 if ((Length
!= 0) && ((UINTN
)Length
- 1 > CharMax
)) {
2073 return EFI_BUFFER_TOO_SMALL
;
2077 for (Index
= 1; Index
< Length
; Index
++) {
2078 if (CompressionId
== 16) {
2079 *FileName
= OstaCompressed
[Index
++] << 8;
2084 if (Index
< Length
) {
2085 *FileName
|= (CHAR16
)(OstaCompressed
[Index
]);
2091 Index
= ((UINTN
)FileName
- (UINTN
)FileNameBak
) / sizeof (CHAR16
);
2092 if (Index
> CharMax
- 1) {
2093 Index
= CharMax
- 1;
2095 FileNameBak
[Index
] = L
'\0';
2101 Resolve a symlink file on an UDF volume.
2103 @attention This is boundary function that may receive untrusted input.
2104 @attention The input is from FileSystem.
2106 The Path Component is external input, so this routine will do basic
2107 validation for Path Component and report status.
2109 @param[in] BlockIo BlockIo interface.
2110 @param[in] DiskIo DiskIo interface.
2111 @param[in] Volume UDF volume information structure.
2112 @param[in] Parent Parent file.
2113 @param[in] FileEntryData FE/EFE structure pointer.
2114 @param[out] File Resolved file.
2116 @retval EFI_SUCCESS Symlink file resolved.
2117 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2118 @retval EFI_NO_MEDIA The device has no media.
2119 @retval EFI_DEVICE_ERROR The device reported an error.
2120 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2121 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
2127 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2128 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2129 IN UDF_VOLUME_INFO
*Volume
,
2130 IN UDF_FILE_INFO
*Parent
,
2131 IN VOID
*FileEntryData
,
2132 OUT UDF_FILE_INFO
*File
2136 UDF_READ_FILE_INFO ReadFileInfo
;
2140 UDF_PATH_COMPONENT
*PathComp
;
2141 UINT8 PathCompLength
;
2142 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
2145 UINT8 CompressionId
;
2146 UDF_FILE_INFO PreviousFile
;
2148 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
2151 // Symlink files on UDF volumes do not contain so much data other than
2152 // Path Components which resolves to real filenames, so it's OK to read in
2153 // all its data here -- usually the data will be inline with the FE/EFE for
2156 ReadFileInfo
.Flags
= ReadFileAllocateAndRead
;
2162 &Parent
->FileIdentifierDesc
->Icb
,
2166 if (EFI_ERROR (Status
)) {
2170 Length
= ReadFileInfo
.ReadLength
;
2172 Data
= (UINT8
*)ReadFileInfo
.FileData
;
2173 EndData
= Data
+ Length
;
2175 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
2178 PathComp
= (UDF_PATH_COMPONENT
*)Data
;
2180 PathCompLength
= PathComp
->LengthOfComponentIdentifier
;
2182 switch (PathComp
->ComponentType
) {
2185 // This Path Component specifies the root directory hierarchy subject to
2186 // agreement between the originator and recipient of the medium. Skip it.
2192 // "\\." of the current directory. Read next Path Component.
2194 goto Next_Path_Component
;
2197 // ".." (parent directory). Go to it.
2199 CopyMem ((VOID
*)FileName
, L
"..", 6);
2203 // "." (current file). Duplicate both FE/EFE and FID of this file.
2205 DuplicateFe (BlockIo
, Volume
, PreviousFile
.FileEntry
, &File
->FileEntry
);
2206 if (File
->FileEntry
== NULL
) {
2207 Status
= EFI_OUT_OF_RESOURCES
;
2208 goto Error_Find_File
;
2211 DuplicateFid (PreviousFile
.FileIdentifierDesc
,
2212 &File
->FileIdentifierDesc
);
2213 if (File
->FileIdentifierDesc
== NULL
) {
2214 FreePool (File
->FileEntry
);
2215 Status
= EFI_OUT_OF_RESOURCES
;
2216 goto Error_Find_File
;
2218 goto Next_Path_Component
;
2221 // This Path Component identifies an object, either a file or a
2222 // directory or an alias.
2224 // Decode it from the compressed data in ComponentIdentifier and find
2227 CompressionId
= PathComp
->ComponentIdentifier
[0];
2228 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2229 return EFI_VOLUME_CORRUPTED
;
2232 if ((UINTN
)PathComp
->ComponentIdentifier
+ PathCompLength
> (UINTN
)EndData
) {
2233 return EFI_VOLUME_CORRUPTED
;
2237 for (Index
= 1; Index
< PathCompLength
; Index
++) {
2238 if (CompressionId
== 16) {
2239 *Char
= *(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+
2243 if (Index
> ARRAY_SIZE (FileName
)) {
2244 return EFI_UNSUPPORTED
;
2249 if (Index
< Length
) {
2250 *Char
|= (CHAR16
)(*(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+ Index
));
2256 Index
= ((UINTN
)Char
- (UINTN
)FileName
) / sizeof (CHAR16
);
2257 if (Index
> ARRAY_SIZE (FileName
) - 1) {
2258 Index
= ARRAY_SIZE (FileName
) - 1;
2260 FileName
[Index
] = L
'\0';
2264 // According to the ECMA-167 standard (3rd Edition - June 1997), Section
2265 // 14.16.1.1, all other values are reserved.
2267 Status
= EFI_VOLUME_CORRUPTED
;
2268 goto Error_Find_File
;
2272 // Find file from the read filename in symlink's file data.
2274 Status
= InternalFindFile (
2283 if (EFI_ERROR (Status
)) {
2284 goto Error_Find_File
;
2287 Next_Path_Component
:
2288 Data
+= sizeof (UDF_PATH_COMPONENT
) + PathCompLength
;
2289 if (Data
>= EndData
) {
2294 // Check the content in the file info pointed by File.
2296 if ((File
->FileEntry
== NULL
) || (File
->FileIdentifierDesc
== NULL
)) {
2297 Status
= EFI_VOLUME_CORRUPTED
;
2298 goto Error_Find_File
;
2301 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
2302 sizeof (UDF_FILE_INFO
)) != 0) {
2303 CleanupFileInformation (&PreviousFile
);
2306 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
2310 // Unmap the symlink file.
2312 FreePool (ReadFileInfo
.FileData
);
2315 // Check the content in the resolved file info.
2317 if ((File
->FileEntry
== NULL
) || (File
->FileIdentifierDesc
== NULL
)) {
2318 return EFI_VOLUME_CORRUPTED
;
2324 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
2325 sizeof (UDF_FILE_INFO
)) != 0) {
2326 CleanupFileInformation (&PreviousFile
);
2329 FreePool (ReadFileInfo
.FileData
);
2335 Clean up in-memory UDF file information.
2337 @param[in] File File information pointer.
2341 CleanupFileInformation (
2342 IN UDF_FILE_INFO
*File
2345 if (File
->FileEntry
!= NULL
) {
2346 FreePool (File
->FileEntry
);
2348 if (File
->FileIdentifierDesc
!= NULL
) {
2349 FreePool ((VOID
*)File
->FileIdentifierDesc
);
2352 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
2356 Find a file from its absolute path on an UDF volume.
2358 @param[in] BlockIo BlockIo interface.
2359 @param[in] DiskIo DiskIo interface.
2360 @param[in] Volume UDF volume information structure.
2361 @param[in] File File information structure.
2362 @param[out] Size Size of the file.
2364 @retval EFI_SUCCESS File size calculated and set in Size.
2365 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2366 @retval EFI_NO_MEDIA The device has no media.
2367 @retval EFI_DEVICE_ERROR The device reported an error.
2368 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2369 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2375 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2376 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2377 IN UDF_VOLUME_INFO
*Volume
,
2378 IN UDF_FILE_INFO
*File
,
2383 UDF_READ_FILE_INFO ReadFileInfo
;
2385 ReadFileInfo
.Flags
= ReadFileGetFileSize
;
2391 &File
->FileIdentifierDesc
->Icb
,
2395 if (EFI_ERROR (Status
)) {
2399 *Size
= ReadFileInfo
.ReadLength
;
2405 Set information about a file on an UDF volume.
2407 @param[in] File File pointer.
2408 @param[in] FileSize Size of the file.
2409 @param[in] FileName Filename of the file.
2410 @param[in, out] BufferSize Size of the returned file infomation.
2411 @param[out] Buffer Data of the returned file information.
2413 @retval EFI_SUCCESS File information set.
2414 @retval EFI_NO_MEDIA The device has no media.
2415 @retval EFI_DEVICE_ERROR The device reported an error.
2416 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2417 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2423 IN UDF_FILE_INFO
*File
,
2425 IN CHAR16
*FileName
,
2426 IN OUT UINTN
*BufferSize
,
2430 UINTN FileInfoLength
;
2431 EFI_FILE_INFO
*FileInfo
;
2432 UDF_FILE_ENTRY
*FileEntry
;
2433 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
2434 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
2437 // Calculate the needed size for the EFI_FILE_INFO structure.
2439 FileInfoLength
= sizeof (EFI_FILE_INFO
) + ((FileName
!= NULL
) ?
2440 StrSize (FileName
) :
2442 if (*BufferSize
< FileInfoLength
) {
2444 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2446 *BufferSize
= FileInfoLength
;
2447 return EFI_BUFFER_TOO_SMALL
;
2451 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2452 // Now, fill it in with all necessary information about the file.
2454 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
2455 FileInfo
->Size
= FileInfoLength
;
2456 FileInfo
->Attribute
&= ~EFI_FILE_VALID_ATTR
;
2457 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
2459 if (IS_FID_DIRECTORY_FILE (File
->FileIdentifierDesc
)) {
2460 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
2461 } else if (IS_FID_NORMAL_FILE (File
->FileIdentifierDesc
)) {
2462 FileInfo
->Attribute
|= EFI_FILE_ARCHIVE
;
2465 if (IS_FID_HIDDEN_FILE (File
->FileIdentifierDesc
)) {
2466 FileInfo
->Attribute
|= EFI_FILE_HIDDEN
;
2469 DescriptorTag
= File
->FileEntry
;
2471 if (DescriptorTag
->TagIdentifier
== UdfFileEntry
) {
2472 FileEntry
= (UDF_FILE_ENTRY
*)File
->FileEntry
;
2475 // Check if FE has the system attribute set.
2477 if (FileEntry
->IcbTag
.Flags
& (1 << 10)) {
2478 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2481 FileInfo
->FileSize
= FileSize
;
2482 FileInfo
->PhysicalSize
= FileSize
;
2484 FileInfo
->CreateTime
.Year
= FileEntry
->AccessTime
.Year
;
2485 FileInfo
->CreateTime
.Month
= FileEntry
->AccessTime
.Month
;
2486 FileInfo
->CreateTime
.Day
= FileEntry
->AccessTime
.Day
;
2487 FileInfo
->CreateTime
.Hour
= FileEntry
->AccessTime
.Hour
;
2488 FileInfo
->CreateTime
.Minute
= FileEntry
->AccessTime
.Minute
;
2489 FileInfo
->CreateTime
.Second
= FileEntry
->AccessTime
.Second
;
2490 FileInfo
->CreateTime
.Nanosecond
=
2491 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2493 FileInfo
->LastAccessTime
.Year
=
2494 FileEntry
->AccessTime
.Year
;
2495 FileInfo
->LastAccessTime
.Month
=
2496 FileEntry
->AccessTime
.Month
;
2497 FileInfo
->LastAccessTime
.Day
=
2498 FileEntry
->AccessTime
.Day
;
2499 FileInfo
->LastAccessTime
.Hour
=
2500 FileEntry
->AccessTime
.Hour
;
2501 FileInfo
->LastAccessTime
.Minute
=
2502 FileEntry
->AccessTime
.Minute
;
2503 FileInfo
->LastAccessTime
.Second
=
2504 FileEntry
->AccessTime
.Second
;
2505 FileInfo
->LastAccessTime
.Nanosecond
=
2506 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2507 } else if (DescriptorTag
->TagIdentifier
== UdfExtendedFileEntry
) {
2508 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)File
->FileEntry
;
2511 // Check if EFE has the system attribute set.
2513 if (ExtendedFileEntry
->IcbTag
.Flags
& (1 << 10)) {
2514 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2517 FileInfo
->FileSize
= FileSize
;
2518 FileInfo
->PhysicalSize
= FileSize
;
2520 FileInfo
->CreateTime
.Year
= ExtendedFileEntry
->CreationTime
.Year
;
2521 FileInfo
->CreateTime
.Month
= ExtendedFileEntry
->CreationTime
.Month
;
2522 FileInfo
->CreateTime
.Day
= ExtendedFileEntry
->CreationTime
.Day
;
2523 FileInfo
->CreateTime
.Hour
= ExtendedFileEntry
->CreationTime
.Hour
;
2524 FileInfo
->CreateTime
.Minute
= ExtendedFileEntry
->CreationTime
.Second
;
2525 FileInfo
->CreateTime
.Second
= ExtendedFileEntry
->CreationTime
.Second
;
2526 FileInfo
->CreateTime
.Nanosecond
=
2527 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2529 FileInfo
->LastAccessTime
.Year
=
2530 ExtendedFileEntry
->AccessTime
.Year
;
2531 FileInfo
->LastAccessTime
.Month
=
2532 ExtendedFileEntry
->AccessTime
.Month
;
2533 FileInfo
->LastAccessTime
.Day
=
2534 ExtendedFileEntry
->AccessTime
.Day
;
2535 FileInfo
->LastAccessTime
.Hour
=
2536 ExtendedFileEntry
->AccessTime
.Hour
;
2537 FileInfo
->LastAccessTime
.Minute
=
2538 ExtendedFileEntry
->AccessTime
.Minute
;
2539 FileInfo
->LastAccessTime
.Second
=
2540 ExtendedFileEntry
->AccessTime
.Second
;
2541 FileInfo
->LastAccessTime
.Nanosecond
=
2542 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2545 FileInfo
->CreateTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2546 FileInfo
->CreateTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2547 FileInfo
->LastAccessTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2548 FileInfo
->LastAccessTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2550 CopyMem ((VOID
*)&FileInfo
->ModificationTime
,
2551 (VOID
*)&FileInfo
->LastAccessTime
,
2554 if (FileName
!= NULL
) {
2555 StrCpyS (FileInfo
->FileName
, StrLen (FileName
) + 1, FileName
);
2557 FileInfo
->FileName
[0] = '\0';
2560 *BufferSize
= FileInfoLength
;
2566 Get volume label of an UDF volume.
2568 @attention This is boundary function that may receive untrusted input.
2569 @attention The input is from FileSystem.
2571 The File Set Descriptor is external input, so this routine will do basic
2572 validation for File Set Descriptor and report status.
2574 @param[in] Volume Volume information pointer.
2575 @param[in] CharMax The maximum number of Unicode char in String,
2576 including terminating null char.
2577 @param[out] String String buffer pointer to store the volume label.
2579 @retval EFI_SUCCESS Volume label is returned.
2580 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2581 @retval EFI_BUFFER_TOO_SMALL The string buffer String cannot hold the
2587 IN UDF_VOLUME_INFO
*Volume
,
2592 UDF_FILE_SET_DESCRIPTOR
*FileSetDesc
;
2594 UINT8
*OstaCompressed
;
2595 UINT8 CompressionId
;
2598 FileSetDesc
= &Volume
->FileSetDesc
;
2600 OstaCompressed
= &FileSetDesc
->LogicalVolumeIdentifier
[0];
2602 CompressionId
= OstaCompressed
[0];
2603 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
2604 return EFI_VOLUME_CORRUPTED
;
2608 for (Index
= 1; Index
< 128; Index
++) {
2609 if (CompressionId
== 16) {
2610 if ((Index
>> 1) > CharMax
) {
2611 return EFI_BUFFER_TOO_SMALL
;
2614 *String
= *(UINT8
*)(OstaCompressed
+ Index
) << 8;
2617 if (Index
> CharMax
) {
2618 return EFI_BUFFER_TOO_SMALL
;
2625 *String
|= (CHAR16
)(*(UINT8
*)(OstaCompressed
+ Index
));
2629 // Unlike FID Identifiers, Logical Volume Identifier is stored in a
2630 // NULL-terminated OSTA compressed format, so we must check for the NULL
2633 if (*String
== L
'\0') {
2640 Index
= ((UINTN
)String
- (UINTN
)StringBak
) / sizeof (CHAR16
);
2641 if (Index
> CharMax
- 1) {
2642 Index
= CharMax
- 1;
2644 StringBak
[Index
] = L
'\0';
2650 Get volume and free space size information of an UDF volume.
2652 @attention This is boundary function that may receive untrusted input.
2653 @attention The input is from FileSystem.
2655 The Logical Volume Descriptor and the Logical Volume Integrity Descriptor are
2656 external inputs, so this routine will do basic validation for both descriptors
2659 @param[in] BlockIo BlockIo interface.
2660 @param[in] DiskIo DiskIo interface.
2661 @param[in] Volume UDF volume information structure.
2662 @param[out] VolumeSize Volume size.
2663 @param[out] FreeSpaceSize Free space size.
2665 @retval EFI_SUCCESS Volume and free space size calculated.
2666 @retval EFI_NO_MEDIA The device has no media.
2667 @retval EFI_DEVICE_ERROR The device reported an error.
2668 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2669 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
2670 calculated due to lack of resources.
2675 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2676 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2677 IN UDF_VOLUME_INFO
*Volume
,
2678 OUT UINT64
*VolumeSize
,
2679 OUT UINT64
*FreeSpaceSize
2683 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
2684 UDF_EXTENT_AD
*ExtentAd
;
2686 UINT32 LogicalBlockSize
;
2687 UDF_LOGICAL_VOLUME_INTEGRITY
*LogicalVolInt
;
2688 UDF_DESCRIPTOR_TAG
*DescriptorTag
;
2693 LogicalVolDesc
= &Volume
->LogicalVolDesc
;
2695 ExtentAd
= &LogicalVolDesc
->IntegritySequenceExtent
;
2697 if ((ExtentAd
->ExtentLength
== 0) ||
2698 (ExtentAd
->ExtentLength
< sizeof (UDF_LOGICAL_VOLUME_INTEGRITY
))) {
2699 return EFI_VOLUME_CORRUPTED
;
2702 LogicalVolInt
= AllocatePool (ExtentAd
->ExtentLength
);
2703 if (LogicalVolInt
== NULL
) {
2704 return EFI_OUT_OF_RESOURCES
;
2708 // Get location of Logical Volume Integrity Descriptor
2710 Lsn
= (UINT64
)ExtentAd
->ExtentLocation
- Volume
->MainVdsStartLocation
;
2712 LogicalBlockSize
= LogicalVolDesc
->LogicalBlockSize
;
2717 Status
= DiskIo
->ReadDisk (
2719 BlockIo
->Media
->MediaId
,
2720 MultU64x32 (Lsn
, LogicalBlockSize
),
2721 ExtentAd
->ExtentLength
,
2724 if (EFI_ERROR (Status
)) {
2728 DescriptorTag
= &LogicalVolInt
->DescriptorTag
;
2731 // Check if read block is a Logical Volume Integrity Descriptor
2733 if (DescriptorTag
->TagIdentifier
!= UdfLogicalVolumeIntegrityDescriptor
) {
2734 Status
= EFI_VOLUME_CORRUPTED
;
2738 if ((LogicalVolInt
->NumberOfPartitions
> MAX_UINT32
/ sizeof (UINT32
) / 2) ||
2739 (LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
) * 2 >
2740 ExtentAd
->ExtentLength
- sizeof (UDF_LOGICAL_VOLUME_INTEGRITY
))) {
2741 Status
= EFI_VOLUME_CORRUPTED
;
2748 Length
= LogicalVolInt
->NumberOfPartitions
;
2749 for (Index
= 0; Index
< Length
; Index
+= sizeof (UINT32
)) {
2750 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2752 // Check if size is not specified
2754 if (LsnsNo
== 0xFFFFFFFFUL
) {
2758 // Accumulate free space size
2760 *FreeSpaceSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2763 Length
= LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
) * 2;
2764 for (; Index
< Length
; Index
+= sizeof (UINT32
)) {
2765 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2767 // Check if size is not specified
2769 if (LsnsNo
== 0xFFFFFFFFUL
) {
2773 // Accumulate used volume space
2775 *VolumeSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2778 Status
= EFI_SUCCESS
;
2782 // Free Logical Volume Integrity Descriptor
2784 FreePool (LogicalVolInt
);
2790 Seek a file and read its data into memory on an UDF volume.
2792 @param[in] BlockIo BlockIo interface.
2793 @param[in] DiskIo DiskIo interface.
2794 @param[in] Volume UDF volume information structure.
2795 @param[in] File File information structure.
2796 @param[in] FileSize Size of the file.
2797 @param[in, out] FilePosition File position.
2798 @param[in, out] Buffer File data.
2799 @param[in, out] BufferSize Read size.
2801 @retval EFI_SUCCESS File seeked and read.
2802 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2803 @retval EFI_NO_MEDIA The device has no media.
2804 @retval EFI_DEVICE_ERROR The device reported an error.
2805 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2806 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2812 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2813 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2814 IN UDF_VOLUME_INFO
*Volume
,
2815 IN UDF_FILE_INFO
*File
,
2817 IN OUT UINT64
*FilePosition
,
2818 IN OUT VOID
*Buffer
,
2819 IN OUT UINT64
*BufferSize
2823 UDF_READ_FILE_INFO ReadFileInfo
;
2825 ReadFileInfo
.Flags
= ReadFileSeekAndRead
;
2826 ReadFileInfo
.FilePosition
= *FilePosition
;
2827 ReadFileInfo
.FileData
= Buffer
;
2828 ReadFileInfo
.FileDataSize
= *BufferSize
;
2829 ReadFileInfo
.FileSize
= FileSize
;
2835 &File
->FileIdentifierDesc
->Icb
,
2839 if (EFI_ERROR (Status
)) {
2843 *BufferSize
= ReadFileInfo
.FileDataSize
;
2844 *FilePosition
= ReadFileInfo
.FilePosition
;
2850 Check if ControllerHandle supports an UDF file system.
2852 @param[in] This Protocol instance pointer.
2853 @param[in] ControllerHandle Handle of device to test.
2855 @retval EFI_SUCCESS UDF file system found.
2856 @retval EFI_UNSUPPORTED UDF file system not found.
2860 SupportUdfFileSystem (
2861 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2862 IN EFI_HANDLE ControllerHandle
2866 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2867 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2868 EFI_DEVICE_PATH_PROTOCOL
*LastDevicePathNode
;
2869 EFI_GUID
*VendorDefinedGuid
;
2872 // Open Device Path protocol on ControllerHandle
2874 Status
= gBS
->OpenProtocol (
2876 &gEfiDevicePathProtocolGuid
,
2877 (VOID
**)&DevicePath
,
2878 This
->DriverBindingHandle
,
2880 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2882 if (EFI_ERROR (Status
)) {
2883 return EFI_UNSUPPORTED
;
2886 Status
= EFI_UNSUPPORTED
;
2889 // Get last Device Path node
2891 LastDevicePathNode
= NULL
;
2892 DevicePathNode
= DevicePath
;
2893 while (!IsDevicePathEnd (DevicePathNode
)) {
2894 LastDevicePathNode
= DevicePathNode
;
2895 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
2898 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2899 // of an UDF file system.
2901 if (LastDevicePathNode
!= NULL
&&
2902 DevicePathType (LastDevicePathNode
) == MEDIA_DEVICE_PATH
&&
2903 DevicePathSubType (LastDevicePathNode
) == MEDIA_VENDOR_DP
) {
2904 VendorDefinedGuid
= (EFI_GUID
*)((UINTN
)LastDevicePathNode
+
2905 OFFSET_OF (VENDOR_DEVICE_PATH
, Guid
));
2906 if (CompareGuid (VendorDefinedGuid
, &gUdfDevPathGuid
)) {
2907 Status
= EFI_SUCCESS
;
2912 // Close Device Path protocol on ControllerHandle
2914 gBS
->CloseProtocol (
2916 &gEfiDevicePathProtocolGuid
,
2917 This
->DriverBindingHandle
,