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