2 Handle on-disk format and volume structures in UDF/ECMA-167 file systems.
4 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
6 This program and the accompanying materials are licensed and made available
7 under the terms and conditions of the BSD License which accompanies this
8 distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
12 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 FindAnchorVolumeDescriptorPointer (
19 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
20 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
21 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
25 UINT32 BlockSize
= BlockIo
->Media
->BlockSize
;
26 EFI_LBA EndLBA
= BlockIo
->Media
->LastBlock
;
27 EFI_LBA DescriptorLBAs
[] = { 256, EndLBA
- 256, EndLBA
, 512 };
30 for (Index
= 0; Index
< ARRAY_SIZE (DescriptorLBAs
); Index
++) {
31 Status
= DiskIo
->ReadDisk (
33 BlockIo
->Media
->MediaId
,
34 MultU64x32 (DescriptorLBAs
[Index
], BlockSize
),
35 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
),
38 if (EFI_ERROR (Status
)) {
42 // Check if read LBA has a valid AVDP descriptor.
44 if (IS_AVDP (AnchorPoint
)) {
51 return EFI_VOLUME_CORRUPTED
;
55 StartMainVolumeDescriptorSequence (
56 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
57 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
58 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
59 OUT UDF_VOLUME_INFO
*Volume
64 UDF_EXTENT_AD
*ExtentAd
;
68 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
69 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
71 UINT32 LogicalBlockSize
;
74 // We've already found an ADVP on the volume. It contains the extent
75 // (MainVolumeDescriptorSequenceExtent) where the Main Volume Descriptor
76 // Sequence starts. Therefore, we'll look for Logical Volume Descriptors and
77 // Partitions Descriptors and save them in memory, accordingly.
79 // Note also that each descriptor will be aligned on a block size (BlockSize)
80 // boundary, so we need to read one block at a time.
82 BlockSize
= BlockIo
->Media
->BlockSize
;
83 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
84 StartingLsn
= (UINT64
)ExtentAd
->ExtentLocation
;
85 EndingLsn
= StartingLsn
+ DivU64x32 (
86 (UINT64
)ExtentAd
->ExtentLength
,
90 Volume
->LogicalVolDescs
=
91 (UDF_LOGICAL_VOLUME_DESCRIPTOR
**)AllocateZeroPool (ExtentAd
->ExtentLength
);
92 if (Volume
->LogicalVolDescs
== NULL
) {
93 return EFI_OUT_OF_RESOURCES
;
96 Volume
->PartitionDescs
=
97 (UDF_PARTITION_DESCRIPTOR
**)AllocateZeroPool (ExtentAd
->ExtentLength
);
98 if (Volume
->PartitionDescs
== NULL
) {
99 Status
= EFI_OUT_OF_RESOURCES
;
100 goto Error_Alloc_Pds
;
103 Buffer
= AllocateZeroPool (BlockSize
);
104 if (Buffer
== NULL
) {
105 Status
= EFI_OUT_OF_RESOURCES
;
106 goto Error_Alloc_Buf
;
109 Volume
->LogicalVolDescsNo
= 0;
110 Volume
->PartitionDescsNo
= 0;
112 while (StartingLsn
<= EndingLsn
) {
113 Status
= DiskIo
->ReadDisk (
115 BlockIo
->Media
->MediaId
,
116 MultU64x32 (StartingLsn
, BlockSize
),
120 if (EFI_ERROR (Status
)) {
121 goto Error_Read_Disk_Blk
;
124 if (IS_TD (Buffer
)) {
126 // Found a Terminating Descriptor. Stop the sequence then.
131 if (IS_LVD (Buffer
)) {
133 // Found a Logical Volume Descriptor.
136 (UDF_LOGICAL_VOLUME_DESCRIPTOR
*)
137 AllocateZeroPool (sizeof (UDF_LOGICAL_VOLUME_DESCRIPTOR
));
138 if (LogicalVolDesc
== NULL
) {
139 Status
= EFI_OUT_OF_RESOURCES
;
140 goto Error_Alloc_Lvd
;
143 CopyMem ((VOID
*)LogicalVolDesc
, Buffer
,
144 sizeof (UDF_LOGICAL_VOLUME_DESCRIPTOR
));
145 Volume
->LogicalVolDescs
[Volume
->LogicalVolDescsNo
++] = LogicalVolDesc
;
146 } else if (IS_PD (Buffer
)) {
148 // Found a Partition Descriptor.
151 (UDF_PARTITION_DESCRIPTOR
*)
152 AllocateZeroPool (sizeof (UDF_PARTITION_DESCRIPTOR
));
153 if (PartitionDesc
== NULL
) {
154 Status
= EFI_OUT_OF_RESOURCES
;
158 CopyMem ((VOID
*)PartitionDesc
, Buffer
,
159 sizeof (UDF_PARTITION_DESCRIPTOR
));
160 Volume
->PartitionDescs
[Volume
->PartitionDescsNo
++] = PartitionDesc
;
167 // When an UDF volume (revision 2.00 or higher) contains a File Entry rather
168 // than an Extended File Entry (which is not recommended as per spec), we need
169 // to make sure the size of a FE will be _at least_ 2048
170 // (UDF_LOGICAL_SECTOR_SIZE) bytes long to keep backward compatibility.
172 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
173 if (LogicalBlockSize
>= UDF_LOGICAL_SECTOR_SIZE
) {
174 Volume
->FileEntrySize
= LogicalBlockSize
;
176 Volume
->FileEntrySize
= UDF_LOGICAL_SECTOR_SIZE
;
185 for (Index
= 0; Index
< Volume
->PartitionDescsNo
; Index
++) {
186 FreePool ((VOID
*)Volume
->PartitionDescs
[Index
]);
189 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
190 FreePool ((VOID
*)Volume
->LogicalVolDescs
[Index
]);
197 FreePool ((VOID
*)Volume
->PartitionDescs
);
198 Volume
->PartitionDescs
= NULL
;
201 FreePool ((VOID
*)Volume
->LogicalVolDescs
);
202 Volume
->LogicalVolDescs
= NULL
;
208 // Return a Partition Descriptor given a Long Allocation Descriptor. This is
209 // necessary to calculate the right extent (LongAd) offset which is added up
210 // with partition's starting location.
212 UDF_PARTITION_DESCRIPTOR
*
214 IN UDF_VOLUME_INFO
*Volume
,
215 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
218 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
220 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
223 LogicalVolDesc
= Volume
->LogicalVolDescs
[UDF_DEFAULT_LV_NUM
];
225 switch (LV_UDF_REVISION (LogicalVolDesc
)) {
228 // As per UDF 1.02 specification:
230 // There shall be exactly one prevailing Logical Volume Descriptor recorded
231 // per Volume Set. The Partition Maps field shall contain only Type 1
234 PartitionNum
= *(UINT16
*)((UINTN
)&LogicalVolDesc
->PartitionMaps
[4]);
238 // Ensure Type 1 Partition map. Other types aren't supported in this
241 if (LogicalVolDesc
->PartitionMaps
[0] != 1 ||
242 LogicalVolDesc
->PartitionMaps
[1] != 6) {
245 PartitionNum
= *(UINT16
*)((UINTN
)&LogicalVolDesc
->PartitionMaps
[4]);
252 PartitionNum
= LongAd
->ExtentLocation
.PartitionReferenceNumber
;
256 for (Index
= 0; Index
< Volume
->PartitionDescsNo
; Index
++) {
257 PartitionDesc
= Volume
->PartitionDescs
[Index
];
258 if (PartitionDesc
->PartitionNumber
== PartitionNum
) {
259 return PartitionDesc
;
267 // Return logical sector number of a given Long Allocation Descriptor.
271 IN UDF_VOLUME_INFO
*Volume
,
272 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
275 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
277 PartitionDesc
= GetPdFromLongAd (Volume
, LongAd
);
278 ASSERT (PartitionDesc
!= NULL
);
280 return (UINT64
)PartitionDesc
->PartitionStartingLocation
+
281 LongAd
->ExtentLocation
.LogicalBlockNumber
;
285 // Return logical sector number of a given Short Allocation Descriptor.
289 IN UDF_PARTITION_DESCRIPTOR
*PartitionDesc
,
290 IN UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
293 return (UINT64
)PartitionDesc
->PartitionStartingLocation
+
294 ShortAd
->ExtentPosition
;
298 // Find File Set Descriptor of a given Logical Volume Descriptor.
300 // The found FSD will contain the extent (LogicalVolumeContentsUse) where our
301 // root directory is.
304 FindFileSetDescriptor (
305 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
306 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
307 IN UDF_VOLUME_INFO
*Volume
,
308 IN UINTN LogicalVolDescNum
,
309 OUT UDF_FILE_SET_DESCRIPTOR
*FileSetDesc
314 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
316 LogicalVolDesc
= Volume
->LogicalVolDescs
[LogicalVolDescNum
];
317 Lsn
= GetLongAdLsn (Volume
, &LogicalVolDesc
->LogicalVolumeContentsUse
);
320 // Read extent (Long Ad).
322 Status
= DiskIo
->ReadDisk (
324 BlockIo
->Media
->MediaId
,
325 MultU64x32 (Lsn
, LogicalVolDesc
->LogicalBlockSize
),
326 sizeof (UDF_FILE_SET_DESCRIPTOR
),
329 if (EFI_ERROR (Status
)) {
334 // Check if the read extent contains a valid FSD's tag identifier.
336 if (!IS_FSD (FileSetDesc
)) {
337 return EFI_VOLUME_CORRUPTED
;
344 // Get all File Set Descriptors for each Logical Volume Descriptor.
347 GetFileSetDescriptors (
348 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
349 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
350 IN OUT UDF_VOLUME_INFO
*Volume
355 UDF_FILE_SET_DESCRIPTOR
*FileSetDesc
;
358 Volume
->FileSetDescs
=
359 (UDF_FILE_SET_DESCRIPTOR
**)AllocateZeroPool (
360 Volume
->LogicalVolDescsNo
* sizeof (UDF_FILE_SET_DESCRIPTOR
));
361 if (Volume
->FileSetDescs
== NULL
) {
362 return EFI_OUT_OF_RESOURCES
;
365 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
366 FileSetDesc
= AllocateZeroPool (sizeof (UDF_FILE_SET_DESCRIPTOR
));
367 if (FileSetDesc
== NULL
) {
368 Status
= EFI_OUT_OF_RESOURCES
;
369 goto Error_Alloc_Fsd
;
373 // Find a FSD for this LVD.
375 Status
= FindFileSetDescriptor (
382 if (EFI_ERROR (Status
)) {
389 Volume
->FileSetDescs
[Index
] = FileSetDesc
;
392 Volume
->FileSetDescsNo
= Volume
->LogicalVolDescsNo
;
397 for (Index
= 0; Index
< Count
; Index
++) {
398 FreePool ((VOID
*)Volume
->FileSetDescs
[Index
]);
401 FreePool ((VOID
*)Volume
->FileSetDescs
);
402 Volume
->FileSetDescs
= NULL
;
409 // Read Volume and File Structure on an UDF file system.
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
;
424 Status
= FindAnchorVolumeDescriptorPointer (
429 if (EFI_ERROR (Status
)) {
434 // AVDP has been found. Start MVDS.
436 Status
= StartMainVolumeDescriptorSequence (
442 if (EFI_ERROR (Status
)) {
450 // Calculate length of a given File Identifier Descriptor.
453 GetFidDescriptorLength (
454 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
458 (INTN
)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR
, Data
[0]) + 3 +
459 FileIdentifierDesc
->LengthOfFileIdentifier
+
460 FileIdentifierDesc
->LengthOfImplementationUse
) >> 2) << 2
465 // Duplicate a given File Identifier Descriptor.
469 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
470 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**NewFileIdentifierDesc
473 *NewFileIdentifierDesc
=
474 (UDF_FILE_IDENTIFIER_DESCRIPTOR
*)AllocateCopyPool (
475 GetFidDescriptorLength (FileIdentifierDesc
), FileIdentifierDesc
);
479 // Duplicate either a given File Entry or a given Extended File Entry.
483 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
484 IN UDF_VOLUME_INFO
*Volume
,
486 OUT VOID
**NewFileEntry
489 *NewFileEntry
= AllocateCopyPool (Volume
->FileEntrySize
, FileEntry
);
493 // Get raw data + length of a given File Entry or Extended File Entry.
495 // The file's recorded data can contain either real file content (inline) or
496 // a sequence of extents (or Allocation Descriptors) which tells where file's
497 // content is stored in.
499 // NOTE: The FE/EFE can be thought it was an inode.
503 IN VOID
*FileEntryData
,
508 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
509 UDF_FILE_ENTRY
*FileEntry
;
511 if (IS_EFE (FileEntryData
)) {
512 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
514 *Length
= ExtendedFileEntry
->InformationLength
;
515 *Data
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
516 ExtendedFileEntry
->LengthOfExtendedAttributes
);
517 } else if (IS_FE (FileEntryData
)) {
518 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
520 *Length
= FileEntry
->InformationLength
;
521 *Data
= (VOID
*)((UINT8
*)FileEntry
->Data
+
522 FileEntry
->LengthOfExtendedAttributes
);
527 // Get Allocation Descriptors' data information from a given FE/EFE.
531 IN VOID
*FileEntryData
,
536 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
537 UDF_FILE_ENTRY
*FileEntry
;
539 if (IS_EFE (FileEntryData
)) {
540 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
542 *Length
= ExtendedFileEntry
->LengthOfAllocationDescriptors
;
543 *AdsData
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
544 ExtendedFileEntry
->LengthOfExtendedAttributes
);
545 } else if (IS_FE (FileEntryData
)) {
546 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
548 *Length
= FileEntry
->LengthOfAllocationDescriptors
;
549 *AdsData
= (VOID
*)((UINT8
*)FileEntry
->Data
+
550 FileEntry
->LengthOfExtendedAttributes
);
555 // Read next Long Allocation Descriptor from a given file's data.
560 IN OUT UINT64
*Offset
,
562 OUT UDF_LONG_ALLOCATION_DESCRIPTOR
**FoundLongAd
565 UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
;
566 UDF_EXTENT_FLAGS ExtentFlags
;
569 if (*Offset
>= Length
) {
571 // No more Long Allocation Descriptors.
573 return EFI_DEVICE_ERROR
;
577 (UDF_LONG_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
580 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
581 // allocated AD, then return it.
583 ExtentFlags
= GET_EXTENT_FLAGS (LONG_ADS_SEQUENCE
, LongAd
);
584 if (ExtentFlags
== EXTENT_IS_NEXT_EXTENT
||
585 ExtentFlags
== EXTENT_RECORDED_AND_ALLOCATED
) {
590 // This AD is either not recorded but allocated, or not recorded and not
591 // allocated. Skip it.
593 *Offset
+= AD_LENGTH (LONG_ADS_SEQUENCE
);
596 *FoundLongAd
= LongAd
;
602 // Read next Short Allocation Descriptor from a given file's data.
607 IN OUT UINT64
*Offset
,
609 OUT UDF_SHORT_ALLOCATION_DESCRIPTOR
**FoundShortAd
612 UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
;
613 UDF_EXTENT_FLAGS ExtentFlags
;
616 if (*Offset
>= Length
) {
618 // No more Short Allocation Descriptors.
620 return EFI_DEVICE_ERROR
;
624 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
627 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
628 // allocated AD, then return it.
630 ExtentFlags
= GET_EXTENT_FLAGS (SHORT_ADS_SEQUENCE
, ShortAd
);
631 if (ExtentFlags
== EXTENT_IS_NEXT_EXTENT
||
632 ExtentFlags
== EXTENT_RECORDED_AND_ALLOCATED
) {
637 // This AD is either not recorded but allocated, or not recorded and not
638 // allocated. Skip it.
640 *Offset
+= AD_LENGTH (SHORT_ADS_SEQUENCE
);
643 *FoundShortAd
= ShortAd
;
649 // Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
653 GetAllocationDescriptor (
654 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
656 IN OUT UINT64
*Offset
,
661 if (RecordingFlags
== LONG_ADS_SEQUENCE
) {
662 return GetLongAdFromAds (
666 (UDF_LONG_ALLOCATION_DESCRIPTOR
**)FoundAd
668 } else if (RecordingFlags
== SHORT_ADS_SEQUENCE
) {
669 return GetShortAdFromAds (
673 (UDF_SHORT_ALLOCATION_DESCRIPTOR
**)FoundAd
677 return EFI_DEVICE_ERROR
;
681 // Return logical sector number of either Short or Long Allocation Descriptor.
684 GetAllocationDescriptorLsn (
685 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
686 IN UDF_VOLUME_INFO
*Volume
,
687 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
691 if (RecordingFlags
== LONG_ADS_SEQUENCE
) {
692 return GetLongAdLsn (Volume
, (UDF_LONG_ALLOCATION_DESCRIPTOR
*)Ad
);
693 } else if (RecordingFlags
== SHORT_ADS_SEQUENCE
) {
694 return GetShortAdLsn (
695 GetPdFromLongAd (Volume
, ParentIcb
),
696 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)Ad
704 // Return offset + length of a given indirect Allocation Descriptor (AED).
708 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
709 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
710 IN UDF_VOLUME_INFO
*Volume
,
711 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
712 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
722 UINT32 LogicalBlockSize
;
723 UDF_ALLOCATION_EXTENT_DESCRIPTOR
*AllocExtDesc
;
725 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
726 Lsn
= GetAllocationDescriptorLsn (RecordingFlags
,
731 Data
= AllocatePool (ExtentLength
);
733 return EFI_OUT_OF_RESOURCES
;
736 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
741 Status
= DiskIo
->ReadDisk (
743 BlockIo
->Media
->MediaId
,
744 MultU64x32 (Lsn
, LogicalBlockSize
),
748 if (EFI_ERROR (Status
)) {
753 // Check if read extent contains a valid tag identifier for AED.
755 AllocExtDesc
= (UDF_ALLOCATION_EXTENT_DESCRIPTOR
*)Data
;
756 if (!IS_AED (AllocExtDesc
)) {
757 Status
= EFI_VOLUME_CORRUPTED
;
762 // Get AED's block offset and its length.
764 *Offset
= MultU64x32 (Lsn
, LogicalBlockSize
) +
765 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR
);
766 *Length
= AllocExtDesc
->LengthOfAllocationDescriptors
;
775 // Read Allocation Extent Descriptor into memory.
779 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
780 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
781 IN UDF_VOLUME_INFO
*Volume
,
782 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
783 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
793 // Get AED's offset + length.
795 Status
= GetAedAdsOffset (
805 if (EFI_ERROR (Status
)) {
810 // Allocate buffer to read in AED's data.
812 *Data
= AllocatePool (*Length
);
814 return EFI_OUT_OF_RESOURCES
;
817 return DiskIo
->ReadDisk (
819 BlockIo
->Media
->MediaId
,
827 // Function used to serialise reads of Allocation Descriptors.
830 GrowUpBufferToNextAd (
831 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
833 IN OUT VOID
**Buffer
,
839 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
841 if (*Buffer
== NULL
) {
842 *Buffer
= AllocatePool (ExtentLength
);
843 if (*Buffer
== NULL
) {
844 return EFI_OUT_OF_RESOURCES
;
847 *Buffer
= ReallocatePool (Length
, Length
+ ExtentLength
, *Buffer
);
848 if (*Buffer
== NULL
) {
849 return EFI_OUT_OF_RESOURCES
;
857 // Read data or size of either a File Entry or an Extended File Entry.
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 VOID
*FileEntryData
,
866 IN OUT UDF_READ_FILE_INFO
*ReadFileInfo
870 UINT32 LogicalBlockSize
;
882 BOOLEAN FinishedSeeking
;
884 UDF_FE_RECORDING_FLAGS RecordingFlags
;
886 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
889 switch (ReadFileInfo
->Flags
) {
890 case READ_FILE_GET_FILESIZE
:
891 case READ_FILE_ALLOCATE_AND_READ
:
893 // Initialise ReadFileInfo structure for either getting file size, or
894 // reading file's recorded data.
896 ReadFileInfo
->ReadLength
= 0;
897 ReadFileInfo
->FileData
= NULL
;
899 case READ_FILE_SEEK_AND_READ
:
901 // About to seek a file and/or read its data.
903 Length
= ReadFileInfo
->FileSize
- ReadFileInfo
->FilePosition
;
904 if (ReadFileInfo
->FileDataSize
> Length
) {
906 // About to read beyond the EOF -- truncate it.
908 ReadFileInfo
->FileDataSize
= Length
;
912 // Initialise data to start seeking and/or reading a file.
914 BytesLeft
= ReadFileInfo
->FileDataSize
;
917 FinishedSeeking
= FALSE
;
922 RecordingFlags
= GET_FE_RECORDING_FLAGS (FileEntryData
);
923 switch (RecordingFlags
) {
926 // There are no extents for this FE/EFE. All data is inline.
928 GetFileEntryData (FileEntryData
, &Data
, &Length
);
930 if (ReadFileInfo
->Flags
== READ_FILE_GET_FILESIZE
) {
931 ReadFileInfo
->ReadLength
= Length
;
932 } else if (ReadFileInfo
->Flags
== READ_FILE_ALLOCATE_AND_READ
) {
934 // Allocate buffer for starting read data.
936 ReadFileInfo
->FileData
= AllocatePool (Length
);
937 if (ReadFileInfo
->FileData
== NULL
) {
938 return EFI_OUT_OF_RESOURCES
;
942 // Read all inline data into ReadFileInfo->FileData
944 CopyMem (ReadFileInfo
->FileData
, Data
, Length
);
945 ReadFileInfo
->ReadLength
= Length
;
946 } else if (ReadFileInfo
->Flags
== READ_FILE_SEEK_AND_READ
) {
948 // If FilePosition is non-zero, seek file to FilePosition, read
949 // FileDataSize bytes and then updates FilePosition.
952 ReadFileInfo
->FileData
,
953 (VOID
*)((UINT8
*)Data
+ ReadFileInfo
->FilePosition
),
954 ReadFileInfo
->FileDataSize
957 ReadFileInfo
->FilePosition
+= ReadFileInfo
->FileDataSize
;
961 case LONG_ADS_SEQUENCE
:
962 case SHORT_ADS_SEQUENCE
:
964 // This FE/EFE contains a run of Allocation Descriptors. Get data + size
965 // for start reading them out.
967 GetAdsInformation (FileEntryData
, &Data
, &Length
);
974 Status
= GetAllocationDescriptor (
981 if (Status
== EFI_DEVICE_ERROR
) {
982 Status
= EFI_SUCCESS
;
987 // Check if AD is an indirect AD. If so, read Allocation Extent
988 // Descriptor and its extents (ADs).
990 if (GET_EXTENT_FLAGS (RecordingFlags
, Ad
) == EXTENT_IS_NEXT_EXTENT
) {
997 Status
= GetAedAdsData (
1007 if (EFI_ERROR (Status
)) {
1015 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1017 Lsn
= GetAllocationDescriptorLsn (RecordingFlags
,
1022 switch (ReadFileInfo
->Flags
) {
1023 case READ_FILE_GET_FILESIZE
:
1024 ReadFileInfo
->ReadLength
+= ExtentLength
;
1026 case READ_FILE_ALLOCATE_AND_READ
:
1028 // Increase FileData (if necessary) to read next extent.
1030 Status
= GrowUpBufferToNextAd (
1033 &ReadFileInfo
->FileData
,
1034 ReadFileInfo
->ReadLength
1036 if (EFI_ERROR (Status
)) {
1037 goto Error_Alloc_Buffer_To_Next_Ad
;
1041 // Read extent's data into FileData.
1043 Status
= DiskIo
->ReadDisk (
1045 BlockIo
->Media
->MediaId
,
1046 MultU64x32 (Lsn
, LogicalBlockSize
),
1048 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1049 ReadFileInfo
->ReadLength
)
1051 if (EFI_ERROR (Status
)) {
1052 goto Error_Read_Disk_Blk
;
1055 ReadFileInfo
->ReadLength
+= ExtentLength
;
1057 case READ_FILE_SEEK_AND_READ
:
1059 // Seek file first before reading in its data.
1061 if (FinishedSeeking
) {
1063 goto Skip_File_Seek
;
1066 if (FilePosition
+ ExtentLength
< ReadFileInfo
->FilePosition
) {
1067 FilePosition
+= ExtentLength
;
1071 if (FilePosition
+ ExtentLength
> ReadFileInfo
->FilePosition
) {
1072 Offset
= ReadFileInfo
->FilePosition
- FilePosition
;
1081 // Done with seeking file. Start reading its data.
1083 FinishedSeeking
= TRUE
;
1087 // Make sure we don't read more data than really wanted.
1089 if (ExtentLength
- Offset
> BytesLeft
) {
1090 DataLength
= BytesLeft
;
1092 DataLength
= ExtentLength
- Offset
;
1096 // Read extent's data into FileData.
1098 Status
= DiskIo
->ReadDisk (
1100 BlockIo
->Media
->MediaId
,
1101 Offset
+ MultU64x32 (Lsn
, LogicalBlockSize
),
1103 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1106 if (EFI_ERROR (Status
)) {
1107 goto Error_Read_Disk_Blk
;
1111 // Update current file's position.
1113 DataOffset
+= DataLength
;
1114 ReadFileInfo
->FilePosition
+= DataLength
;
1116 BytesLeft
-= DataLength
;
1117 if (BytesLeft
== 0) {
1119 // There is no more file data to read.
1121 Status
= EFI_SUCCESS
;
1130 // Point to the next AD (extent).
1132 AdOffset
+= AD_LENGTH (RecordingFlags
);
1136 case EXTENDED_ADS_SEQUENCE
:
1137 // FIXME: Not supported. Got no volume with it, yet.
1139 Status
= EFI_UNSUPPORTED
;
1150 Error_Read_Disk_Blk
:
1151 Error_Alloc_Buffer_To_Next_Ad
:
1152 if (ReadFileInfo
->Flags
!= READ_FILE_SEEK_AND_READ
) {
1153 FreePool (ReadFileInfo
->FileData
);
1165 // Find a file by its filename from a given Parent file.
1169 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1170 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1171 IN UDF_VOLUME_INFO
*Volume
,
1172 IN CHAR16
*FileName
,
1173 IN UDF_FILE_INFO
*Parent
,
1174 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1175 OUT UDF_FILE_INFO
*File
1179 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1180 UDF_READ_DIRECTORY_INFO ReadDirInfo
;
1182 CHAR16 FoundFileName
[UDF_FILENAME_LENGTH
];
1183 VOID
*CompareFileEntry
;
1186 // Check if parent file is really directory.
1188 if (!IS_FE_DIRECTORY (Parent
->FileEntry
)) {
1189 return EFI_NOT_FOUND
;
1193 // If FileName is current file or working directory, just duplicate Parent's
1194 // FE/EFE and FID descriptors.
1196 if (StrCmp (FileName
, L
".") == 0) {
1197 DuplicateFe (BlockIo
, Volume
, Parent
->FileEntry
, &File
->FileEntry
);
1198 DuplicateFid (Parent
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1204 // Start directory listing.
1206 ZeroMem ((VOID
*)&ReadDirInfo
, sizeof (UDF_READ_DIRECTORY_INFO
));
1210 Status
= ReadDirectoryEntry (
1214 Parent
->FileIdentifierDesc
?
1215 &Parent
->FileIdentifierDesc
->Icb
:
1221 if (EFI_ERROR (Status
)) {
1222 if (Status
== EFI_DEVICE_ERROR
) {
1223 Status
= EFI_NOT_FOUND
;
1229 if (IS_FID_PARENT_FILE (FileIdentifierDesc
)) {
1231 // This FID contains the location (FE/EFE) of the parent directory of this
1232 // directory (Parent), and if FileName is either ".." or "\\", then it's
1233 // the expected FID.
1235 if (StrCmp (FileName
, L
"..") == 0 || StrCmp (FileName
, L
"\\") == 0) {
1240 Status
= GetFileNameFromFid (FileIdentifierDesc
, FoundFileName
);
1241 if (EFI_ERROR (Status
)) {
1245 if (StrCmp (FileName
, FoundFileName
) == 0) {
1247 // FID has been found. Prepare to find its respective FE/EFE.
1254 FreePool ((VOID
*)FileIdentifierDesc
);
1257 if (ReadDirInfo
.DirectoryData
!= NULL
) {
1259 // Free all allocated resources for the directory listing.
1261 FreePool (ReadDirInfo
.DirectoryData
);
1265 Status
= EFI_SUCCESS
;
1267 File
->FileIdentifierDesc
= FileIdentifierDesc
;
1270 // If the requested file is root directory, then the FE/EFE was already
1271 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1273 // Otherwise, find FE/EFE from the respective FID.
1275 if (StrCmp (FileName
, L
"\\") != 0) {
1276 Status
= FindFileEntry (
1280 &FileIdentifierDesc
->Icb
,
1283 if (EFI_ERROR (Status
)) {
1288 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1290 if (CompareMem ((VOID
*)Parent
->FileEntry
, (VOID
*)CompareFileEntry
,
1291 Volume
->FileEntrySize
) != 0) {
1292 File
->FileEntry
= CompareFileEntry
;
1294 FreePool ((VOID
*)FileIdentifierDesc
);
1295 FreePool ((VOID
*)CompareFileEntry
);
1296 Status
= EFI_NOT_FOUND
;
1304 FreePool ((VOID
*)FileIdentifierDesc
);
1310 Read volume information on a medium which contains a valid UDF file system.
1312 @param[in] BlockIo BlockIo interface.
1313 @param[in] DiskIo DiskIo interface.
1314 @param[out] Volume UDF volume information structure.
1316 @retval EFI_SUCCESS Volume information read.
1317 @retval EFI_NO_MEDIA The device has no media.
1318 @retval EFI_DEVICE_ERROR The device reported an error.
1319 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1320 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1324 ReadUdfVolumeInformation (
1325 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1326 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1327 OUT UDF_VOLUME_INFO
*Volume
1332 Status
= ReadVolumeFileStructure (
1337 if (EFI_ERROR (Status
)) {
1341 Status
= GetFileSetDescriptors (
1346 if (EFI_ERROR (Status
)) {
1347 CleanupVolumeInformation (Volume
);
1354 Find the root directory on an UDF volume.
1356 @param[in] BlockIo BlockIo interface.
1357 @param[in] DiskIo DiskIo interface.
1358 @param[in] Volume UDF volume information structure.
1359 @param[out] File Root directory file.
1361 @retval EFI_SUCCESS Root directory found.
1362 @retval EFI_NO_MEDIA The device has no media.
1363 @retval EFI_DEVICE_ERROR The device reported an error.
1364 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1365 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1371 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1372 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1373 IN UDF_VOLUME_INFO
*Volume
,
1374 OUT UDF_FILE_INFO
*File
1378 UDF_FILE_INFO Parent
;
1380 Status
= FindFileEntry (
1384 &Volume
->FileSetDescs
[0]->RootDirectoryIcb
,
1387 if (EFI_ERROR (Status
)) {
1391 Parent
.FileEntry
= File
->FileEntry
;
1392 Parent
.FileIdentifierDesc
= NULL
;
1401 &Volume
->FileSetDescs
[0]->RootDirectoryIcb
,
1404 if (EFI_ERROR (Status
)) {
1405 FreePool (File
->FileEntry
);
1412 Find either a File Entry or a Extended File Entry from a given ICB.
1414 @param[in] BlockIo BlockIo interface.
1415 @param[in] DiskIo DiskIo interface.
1416 @param[in] Volume UDF volume information structure.
1417 @param[in] Icb ICB of the FID.
1418 @param[out] FileEntry File Entry or Extended File Entry.
1420 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1421 @retval EFI_NO_MEDIA The device has no media.
1422 @retval EFI_DEVICE_ERROR The device reported an error.
1423 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1424 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1430 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1431 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1432 IN UDF_VOLUME_INFO
*Volume
,
1433 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1434 OUT VOID
**FileEntry
1439 UINT32 LogicalBlockSize
;
1441 Lsn
= GetLongAdLsn (Volume
, Icb
);
1442 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
1444 *FileEntry
= AllocateZeroPool (Volume
->FileEntrySize
);
1445 if (*FileEntry
== NULL
) {
1446 return EFI_OUT_OF_RESOURCES
;
1452 Status
= DiskIo
->ReadDisk (
1454 BlockIo
->Media
->MediaId
,
1455 MultU64x32 (Lsn
, LogicalBlockSize
),
1456 Volume
->FileEntrySize
,
1459 if (EFI_ERROR (Status
)) {
1460 goto Error_Read_Disk_Blk
;
1464 // Check if the read extent contains a valid Tag Identifier for the expected
1467 if (!IS_FE (*FileEntry
) && !IS_EFE (*FileEntry
)) {
1468 Status
= EFI_VOLUME_CORRUPTED
;
1469 goto Error_Invalid_Fe
;
1475 Error_Read_Disk_Blk
:
1476 FreePool (*FileEntry
);
1482 Find a file given its absolute path on an UDF volume.
1484 @param[in] BlockIo BlockIo interface.
1485 @param[in] DiskIo DiskIo interface.
1486 @param[in] Volume UDF volume information structure.
1487 @param[in] FilePath File's absolute path.
1488 @param[in] Root Root directory file.
1489 @param[in] Parent Parent directory file.
1490 @param[out] File Found file.
1492 @retval EFI_SUCCESS @p FilePath was found.
1493 @retval EFI_NO_MEDIA The device has no media.
1494 @retval EFI_DEVICE_ERROR The device reported an error.
1495 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1496 @retval EFI_OUT_OF_RESOURCES The @p FilePath file was not found due to lack of
1502 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1503 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1504 IN UDF_VOLUME_INFO
*Volume
,
1505 IN CHAR16
*FilePath
,
1506 IN UDF_FILE_INFO
*Root
,
1507 IN UDF_FILE_INFO
*Parent
,
1508 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1509 OUT UDF_FILE_INFO
*File
1513 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1514 CHAR16
*FileNamePointer
;
1515 UDF_FILE_INFO PreviousFile
;
1518 Status
= EFI_NOT_FOUND
;
1520 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1521 while (*FilePath
!= L
'\0') {
1522 FileNamePointer
= FileName
;
1523 while (*FilePath
!= L
'\0' && *FilePath
!= L
'\\') {
1524 *FileNamePointer
++ = *FilePath
++;
1527 *FileNamePointer
= L
'\0';
1528 if (FileName
[0] == L
'\0') {
1530 // Open root directory.
1534 // There is no file found for the root directory yet. So, find only its
1537 // See UdfOpenVolume() function.
1539 Status
= InternalFindFile (BlockIo
,
1548 // We've already a file pointer (Root) for the root directory. Duplicate
1549 // its FE/EFE and FID descriptors.
1551 DuplicateFe (BlockIo
, Volume
, Root
->FileEntry
, &File
->FileEntry
);
1552 DuplicateFid (Root
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1553 Status
= EFI_SUCCESS
;
1557 // No root directory. Find filename from the current directory.
1559 Status
= InternalFindFile (BlockIo
,
1568 if (EFI_ERROR (Status
)) {
1573 // If the found file is a symlink, then find its respective FE/EFE and
1576 if (IS_FE_SYMLINK (File
->FileEntry
)) {
1577 FreePool ((VOID
*)File
->FileIdentifierDesc
);
1579 FileEntry
= File
->FileEntry
;
1581 Status
= ResolveSymlink (BlockIo
,
1588 FreePool (FileEntry
);
1590 if (EFI_ERROR (Status
)) {
1595 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1596 sizeof (UDF_FILE_INFO
)) != 0) {
1597 CleanupFileInformation (&PreviousFile
);
1600 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1601 if (*FilePath
!= L
'\0' && *FilePath
== L
'\\') {
1610 Read a directory entry at a time on an UDF volume.
1612 @param[in] BlockIo BlockIo interface.
1613 @param[in] DiskIo DiskIo interface.
1614 @param[in] Volume UDF volume information structure.
1615 @param[in] ParentIcb ICB of the parent file.
1616 @param[in] FileEntryData FE/EFE of the parent file.
1617 @param[in out] ReadDirInfo Next read directory listing structure
1619 @param[out] FoundFid File Identifier Descriptor pointer.
1621 @retval EFI_SUCCESS Directory entry read.
1622 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1623 @retval EFI_NO_MEDIA The device has no media.
1624 @retval EFI_DEVICE_ERROR The device reported an error.
1625 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1626 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1631 ReadDirectoryEntry (
1632 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1633 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1634 IN UDF_VOLUME_INFO
*Volume
,
1635 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1636 IN VOID
*FileEntryData
,
1637 IN OUT UDF_READ_DIRECTORY_INFO
*ReadDirInfo
,
1638 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**FoundFid
1642 UDF_READ_FILE_INFO ReadFileInfo
;
1643 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1645 if (ReadDirInfo
->DirectoryData
== NULL
) {
1647 // The directory's recorded data has not been read yet. So let's cache it
1648 // into memory and the next calls won't need to read it again.
1650 ReadFileInfo
.Flags
= READ_FILE_ALLOCATE_AND_READ
;
1660 if (EFI_ERROR (Status
)) {
1665 // Fill in ReadDirInfo structure with the read directory's data information.
1667 ReadDirInfo
->DirectoryData
= ReadFileInfo
.FileData
;
1668 ReadDirInfo
->DirectoryLength
= ReadFileInfo
.ReadLength
;
1672 if (ReadDirInfo
->FidOffset
>= ReadDirInfo
->DirectoryLength
) {
1674 // There are no longer FIDs for this directory. By returning
1675 // EFI_DEVICE_ERROR to the callee will indicate end of directory
1678 return EFI_DEVICE_ERROR
;
1682 // Get FID for this entry.
1684 FileIdentifierDesc
= GET_FID_FROM_ADS (ReadDirInfo
->DirectoryData
,
1685 ReadDirInfo
->FidOffset
);
1687 // Update FidOffset to point to next FID.
1689 ReadDirInfo
->FidOffset
+= GetFidDescriptorLength (FileIdentifierDesc
);
1690 } while (IS_FID_DELETED_FILE (FileIdentifierDesc
));
1692 DuplicateFid (FileIdentifierDesc
, FoundFid
);
1698 Get a filename (encoded in OSTA-compressed format) from a File Identifier
1699 Descriptor on an UDF volume.
1701 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
1702 @param[out] FileName Decoded filename.
1704 @retval EFI_SUCCESS Filename decoded and read.
1705 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1708 GetFileNameFromFid (
1709 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
1710 OUT CHAR16
*FileName
1713 UINT8
*OstaCompressed
;
1714 UINT8 CompressionId
;
1720 (UINT8
*)FileIdentifierDesc
->Data
+
1721 FileIdentifierDesc
->LengthOfImplementationUse
1724 CompressionId
= OstaCompressed
[0];
1725 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
1726 return EFI_VOLUME_CORRUPTED
;
1732 Length
= FileIdentifierDesc
->LengthOfFileIdentifier
;
1733 for (Index
= 1; Index
< Length
; Index
++) {
1734 if (CompressionId
== 16) {
1735 *FileName
= OstaCompressed
[Index
++] << 8;
1740 if (Index
< Length
) {
1741 *FileName
|= OstaCompressed
[Index
];
1753 Resolve a symlink file on an UDF volume.
1755 @param[in] BlockIo BlockIo interface.
1756 @param[in] DiskIo DiskIo interface.
1757 @param[in] Volume UDF volume information structure.
1758 @param[in] Parent Parent file.
1759 @param[in] FileEntryData FE/EFE structure pointer.
1760 @param[out] File Resolved file.
1762 @retval EFI_SUCCESS Symlink file resolved.
1763 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1764 @retval EFI_NO_MEDIA The device has no media.
1765 @retval EFI_DEVICE_ERROR The device reported an error.
1766 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1767 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
1773 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1774 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1775 IN UDF_VOLUME_INFO
*Volume
,
1776 IN UDF_FILE_INFO
*Parent
,
1777 IN VOID
*FileEntryData
,
1778 OUT UDF_FILE_INFO
*File
1782 UDF_READ_FILE_INFO ReadFileInfo
;
1786 UDF_PATH_COMPONENT
*PathComp
;
1787 UINT8 PathCompLength
;
1788 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1791 UINT8 CompressionId
;
1792 UDF_FILE_INFO PreviousFile
;
1795 // Symlink files on UDF volumes do not contain so much data other than
1796 // Path Components which resolves to real filenames, so it's OK to read in
1797 // all its data here -- usually the data will be inline with the FE/EFE for
1800 ReadFileInfo
.Flags
= READ_FILE_ALLOCATE_AND_READ
;
1806 &Parent
->FileIdentifierDesc
->Icb
,
1810 if (EFI_ERROR (Status
)) {
1814 Length
= ReadFileInfo
.ReadLength
;
1816 Data
= (UINT8
*)ReadFileInfo
.FileData
;
1817 EndData
= Data
+ Length
;
1819 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1822 PathComp
= (UDF_PATH_COMPONENT
*)Data
;
1824 PathCompLength
= PathComp
->LengthOfComponentIdentifier
;
1826 switch (PathComp
->ComponentType
) {
1829 // This Path Component specifies the root directory hierarchy subject to
1830 // agreement between the originator and recipient of the medium. Skip it.
1836 // "\\." of the current directory. Read next Path Component.
1838 goto Next_Path_Component
;
1841 // ".." (parent directory). Go to it.
1843 CopyMem ((VOID
*)FileName
, L
"..", 6);
1847 // "." (current file). Duplicate both FE/EFE and FID of this file.
1849 DuplicateFe (BlockIo
, Volume
, PreviousFile
.FileEntry
, &File
->FileEntry
);
1850 DuplicateFid (PreviousFile
.FileIdentifierDesc
,
1851 &File
->FileIdentifierDesc
);
1852 goto Next_Path_Component
;
1855 // This Path Component identifies an object, either a file or a
1856 // directory or an alias.
1858 // Decode it from the compressed data in ComponentIdentifier and find
1861 CompressionId
= PathComp
->ComponentIdentifier
[0];
1862 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
1863 return EFI_VOLUME_CORRUPTED
;
1867 for (Index
= 1; Index
< PathCompLength
; Index
++) {
1868 if (CompressionId
== 16) {
1869 *C
= *(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+
1876 if (Index
< Length
) {
1877 *C
|= *(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+ Index
);
1888 // Find file from the read filename in symlink's file data.
1890 Status
= InternalFindFile (
1899 if (EFI_ERROR (Status
)) {
1900 goto Error_Find_File
;
1903 Next_Path_Component
:
1904 Data
+= sizeof (UDF_PATH_COMPONENT
) + PathCompLength
;
1905 if (Data
>= EndData
) {
1909 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1910 sizeof (UDF_FILE_INFO
)) != 0) {
1911 CleanupFileInformation (&PreviousFile
);
1914 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1918 // Unmap the symlink file.
1920 FreePool (ReadFileInfo
.FileData
);
1925 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1926 sizeof (UDF_FILE_INFO
)) != 0) {
1927 CleanupFileInformation (&PreviousFile
);
1930 FreePool (ReadFileInfo
.FileData
);
1936 Clean up in-memory UDF volume information.
1938 @param[in] Volume Volume information pointer.
1942 CleanupVolumeInformation (
1943 IN UDF_VOLUME_INFO
*Volume
1948 if (Volume
->LogicalVolDescs
!= NULL
) {
1949 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
1950 FreePool ((VOID
*)Volume
->LogicalVolDescs
[Index
]);
1952 FreePool ((VOID
*)Volume
->LogicalVolDescs
);
1955 if (Volume
->PartitionDescs
!= NULL
) {
1956 for (Index
= 0; Index
< Volume
->PartitionDescsNo
; Index
++) {
1957 FreePool ((VOID
*)Volume
->PartitionDescs
[Index
]);
1959 FreePool ((VOID
*)Volume
->PartitionDescs
);
1962 if (Volume
->FileSetDescs
!= NULL
) {
1963 for (Index
= 0; Index
< Volume
->FileSetDescsNo
; Index
++) {
1964 FreePool ((VOID
*)Volume
->FileSetDescs
[Index
]);
1966 FreePool ((VOID
*)Volume
->FileSetDescs
);
1969 ZeroMem ((VOID
*)Volume
, sizeof (UDF_VOLUME_INFO
));
1973 Clean up in-memory UDF file information.
1975 @param[in] File File information pointer.
1979 CleanupFileInformation (
1980 IN UDF_FILE_INFO
*File
1983 if (File
->FileEntry
!= NULL
) {
1984 FreePool (File
->FileEntry
);
1986 if (File
->FileIdentifierDesc
!= NULL
) {
1987 FreePool ((VOID
*)File
->FileIdentifierDesc
);
1990 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
1994 Find a file from its absolute path on an UDF volume.
1996 @param[in] BlockIo BlockIo interface.
1997 @param[in] DiskIo DiskIo interface.
1998 @param[in] Volume UDF volume information structure.
1999 @param[in] File File information structure.
2000 @param[out] Size Size of the file.
2002 @retval EFI_SUCCESS File size calculated and set in @p Size.
2003 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2004 @retval EFI_NO_MEDIA The device has no media.
2005 @retval EFI_DEVICE_ERROR The device reported an error.
2006 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2007 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2013 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2014 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2015 IN UDF_VOLUME_INFO
*Volume
,
2016 IN UDF_FILE_INFO
*File
,
2021 UDF_READ_FILE_INFO ReadFileInfo
;
2023 ReadFileInfo
.Flags
= READ_FILE_GET_FILESIZE
;
2029 &File
->FileIdentifierDesc
->Icb
,
2033 if (EFI_ERROR (Status
)) {
2037 *Size
= ReadFileInfo
.ReadLength
;
2043 Set information about a file on an UDF volume.
2045 @param[in] File File pointer.
2046 @param[in] FileSize Size of the file.
2047 @param[in] FileName Filename of the file.
2048 @param[in out] BufferSize Size of the returned file infomation.
2049 @param[out] Buffer Data of the returned file information.
2051 @retval EFI_SUCCESS File information set.
2052 @retval EFI_NO_MEDIA The device has no media.
2053 @retval EFI_DEVICE_ERROR The device reported an error.
2054 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2055 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2061 IN UDF_FILE_INFO
*File
,
2063 IN CHAR16
*FileName
,
2064 IN OUT UINTN
*BufferSize
,
2068 UINTN FileInfoLength
;
2069 EFI_FILE_INFO
*FileInfo
;
2070 UDF_FILE_ENTRY
*FileEntry
;
2071 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
2074 // Calculate the needed size for the EFI_FILE_INFO structure.
2076 FileInfoLength
= sizeof (EFI_FILE_INFO
) + (FileName
?
2077 StrSize (FileName
) :
2079 if (*BufferSize
< FileInfoLength
) {
2081 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2083 *BufferSize
= FileInfoLength
;
2084 return EFI_BUFFER_TOO_SMALL
;
2088 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2089 // Now, fill it in with all necessary information about the file.
2091 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
2092 FileInfo
->Size
= FileInfoLength
;
2093 FileInfo
->Attribute
&= ~EFI_FILE_VALID_ATTR
;
2094 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
2096 if (IS_FID_DIRECTORY_FILE (File
->FileIdentifierDesc
)) {
2097 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
2098 } else if (IS_FID_NORMAL_FILE (File
->FileIdentifierDesc
)) {
2099 FileInfo
->Attribute
|= EFI_FILE_ARCHIVE
;
2102 if (IS_FID_HIDDEN_FILE (File
->FileIdentifierDesc
)) {
2103 FileInfo
->Attribute
|= EFI_FILE_HIDDEN
;
2106 if (IS_FE (File
->FileEntry
)) {
2107 FileEntry
= (UDF_FILE_ENTRY
*)File
->FileEntry
;
2110 // Check if FE has the system attribute set.
2112 if (FileEntry
->IcbTag
.Flags
& (1 << 10)) {
2113 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2116 FileInfo
->FileSize
= FileSize
;
2117 FileInfo
->PhysicalSize
= FileSize
;
2119 FileInfo
->CreateTime
.Year
= FileEntry
->AccessTime
.Year
;
2120 FileInfo
->CreateTime
.Month
= FileEntry
->AccessTime
.Month
;
2121 FileInfo
->CreateTime
.Day
= FileEntry
->AccessTime
.Day
;
2122 FileInfo
->CreateTime
.Hour
= FileEntry
->AccessTime
.Hour
;
2123 FileInfo
->CreateTime
.Minute
= FileEntry
->AccessTime
.Second
;
2124 FileInfo
->CreateTime
.Second
= FileEntry
->AccessTime
.Second
;
2125 FileInfo
->CreateTime
.Nanosecond
=
2126 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2128 FileInfo
->LastAccessTime
.Year
=
2129 FileEntry
->AccessTime
.Year
;
2130 FileInfo
->LastAccessTime
.Month
=
2131 FileEntry
->AccessTime
.Month
;
2132 FileInfo
->LastAccessTime
.Day
=
2133 FileEntry
->AccessTime
.Day
;
2134 FileInfo
->LastAccessTime
.Hour
=
2135 FileEntry
->AccessTime
.Hour
;
2136 FileInfo
->LastAccessTime
.Minute
=
2137 FileEntry
->AccessTime
.Minute
;
2138 FileInfo
->LastAccessTime
.Second
=
2139 FileEntry
->AccessTime
.Second
;
2140 FileInfo
->LastAccessTime
.Nanosecond
=
2141 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2142 } else if (IS_EFE (File
->FileEntry
)) {
2143 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)File
->FileEntry
;
2146 // Check if EFE has the system attribute set.
2148 if (ExtendedFileEntry
->IcbTag
.Flags
& (1 << 10)) {
2149 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2152 FileInfo
->FileSize
= FileSize
;
2153 FileInfo
->PhysicalSize
= FileSize
;
2155 FileInfo
->CreateTime
.Year
= ExtendedFileEntry
->CreationTime
.Year
;
2156 FileInfo
->CreateTime
.Month
= ExtendedFileEntry
->CreationTime
.Month
;
2157 FileInfo
->CreateTime
.Day
= ExtendedFileEntry
->CreationTime
.Day
;
2158 FileInfo
->CreateTime
.Hour
= ExtendedFileEntry
->CreationTime
.Hour
;
2159 FileInfo
->CreateTime
.Minute
= ExtendedFileEntry
->CreationTime
.Second
;
2160 FileInfo
->CreateTime
.Second
= ExtendedFileEntry
->CreationTime
.Second
;
2161 FileInfo
->CreateTime
.Nanosecond
=
2162 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2164 FileInfo
->LastAccessTime
.Year
=
2165 ExtendedFileEntry
->AccessTime
.Year
;
2166 FileInfo
->LastAccessTime
.Month
=
2167 ExtendedFileEntry
->AccessTime
.Month
;
2168 FileInfo
->LastAccessTime
.Day
=
2169 ExtendedFileEntry
->AccessTime
.Day
;
2170 FileInfo
->LastAccessTime
.Hour
=
2171 ExtendedFileEntry
->AccessTime
.Hour
;
2172 FileInfo
->LastAccessTime
.Minute
=
2173 ExtendedFileEntry
->AccessTime
.Minute
;
2174 FileInfo
->LastAccessTime
.Second
=
2175 ExtendedFileEntry
->AccessTime
.Second
;
2176 FileInfo
->LastAccessTime
.Nanosecond
=
2177 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2180 FileInfo
->CreateTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2181 FileInfo
->CreateTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2182 FileInfo
->LastAccessTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2183 FileInfo
->LastAccessTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2185 CopyMem ((VOID
*)&FileInfo
->ModificationTime
,
2186 (VOID
*)&FileInfo
->LastAccessTime
,
2189 if (FileName
!= NULL
) {
2190 StrCpyS (FileInfo
->FileName
, StrLen (FileName
) + 1, FileName
);
2192 FileInfo
->FileName
[0] = '\0';
2195 *BufferSize
= FileInfoLength
;
2201 Get volume and free space size information of an UDF volume.
2203 @param[in] BlockIo BlockIo interface.
2204 @param[in] DiskIo DiskIo interface.
2205 @param[in] Volume UDF volume information structure.
2206 @param[out] VolumeSize Volume size.
2207 @param[out] FreeSpaceSize Free space size.
2209 @retval EFI_SUCCESS Volume and free space size calculated.
2210 @retval EFI_NO_MEDIA The device has no media.
2211 @retval EFI_DEVICE_ERROR The device reported an error.
2212 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2213 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
2214 calculated due to lack of resources.
2219 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2220 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2221 IN UDF_VOLUME_INFO
*Volume
,
2222 OUT UINT64
*VolumeSize
,
2223 OUT UINT64
*FreeSpaceSize
2226 UDF_EXTENT_AD ExtentAd
;
2227 UINT32 LogicalBlockSize
;
2230 UDF_LOGICAL_VOLUME_INTEGRITY
*LogicalVolInt
;
2238 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
2239 CopyMem ((VOID
*)&ExtentAd
,
2240 (VOID
*)&Volume
->LogicalVolDescs
[Index
]->IntegritySequenceExtent
,
2241 sizeof (UDF_EXTENT_AD
));
2242 if (ExtentAd
.ExtentLength
== 0) {
2246 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, Index
);
2249 LogicalVolInt
= (UDF_LOGICAL_VOLUME_INTEGRITY
*)
2250 AllocatePool (ExtentAd
.ExtentLength
);
2251 if (LogicalVolInt
== NULL
) {
2252 return EFI_OUT_OF_RESOURCES
;
2255 Lsn
= (UINT64
)ExtentAd
.ExtentLocation
;
2257 Status
= DiskIo
->ReadDisk (
2259 BlockIo
->Media
->MediaId
,
2260 MultU64x32 (Lsn
, LogicalBlockSize
),
2261 ExtentAd
.ExtentLength
,
2262 (VOID
*)LogicalVolInt
2264 if (EFI_ERROR (Status
)) {
2265 FreePool ((VOID
*)LogicalVolInt
);
2269 if (!IS_LVID (LogicalVolInt
)) {
2270 FreePool ((VOID
*)LogicalVolInt
);
2271 return EFI_VOLUME_CORRUPTED
;
2274 Length
= LogicalVolInt
->NumberOfPartitions
;
2275 for (Index
= 0; Index
< Length
; Index
+= sizeof (UINT32
)) {
2276 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2277 if (LsnsNo
== 0xFFFFFFFFUL
) {
2279 // Size not specified.
2284 *FreeSpaceSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2287 Length
= (LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
)) << 1;
2288 for (; Index
< Length
; Index
+= sizeof (UINT32
)) {
2289 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2290 if (LsnsNo
== 0xFFFFFFFFUL
) {
2292 // Size not specified.
2297 *VolumeSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2300 CopyMem ((VOID
*)&ExtentAd
,(VOID
*)&LogicalVolInt
->NextIntegrityExtent
,
2301 sizeof (UDF_EXTENT_AD
));
2302 if (ExtentAd
.ExtentLength
> 0) {
2303 FreePool ((VOID
*)LogicalVolInt
);
2304 goto Read_Next_Sequence
;
2307 FreePool ((VOID
*)LogicalVolInt
);
2314 Seek a file and read its data into memory on an UDF volume.
2316 @param[in] BlockIo BlockIo interface.
2317 @param[in] DiskIo DiskIo interface.
2318 @param[in] Volume UDF volume information structure.
2319 @param[in] File File information structure.
2320 @param[in] FileSize Size of the file.
2321 @param[in out] FilePosition File position.
2322 @param[in out] Buffer File data.
2323 @param[in out] BufferSize Read size.
2325 @retval EFI_SUCCESS File seeked and read.
2326 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2327 @retval EFI_NO_MEDIA The device has no media.
2328 @retval EFI_DEVICE_ERROR The device reported an error.
2329 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2330 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2336 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2337 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2338 IN UDF_VOLUME_INFO
*Volume
,
2339 IN UDF_FILE_INFO
*File
,
2341 IN OUT UINT64
*FilePosition
,
2342 IN OUT VOID
*Buffer
,
2343 IN OUT UINT64
*BufferSize
2347 UDF_READ_FILE_INFO ReadFileInfo
;
2349 ReadFileInfo
.Flags
= READ_FILE_SEEK_AND_READ
;
2350 ReadFileInfo
.FilePosition
= *FilePosition
;
2351 ReadFileInfo
.FileData
= Buffer
;
2352 ReadFileInfo
.FileDataSize
= *BufferSize
;
2353 ReadFileInfo
.FileSize
= FileSize
;
2359 &File
->FileIdentifierDesc
->Icb
,
2363 if (EFI_ERROR (Status
)) {
2367 *BufferSize
= ReadFileInfo
.FileDataSize
;
2368 *FilePosition
= ReadFileInfo
.FilePosition
;
2374 Check if ControllerHandle supports an UDF file system.
2376 @param[in] This Protocol instance pointer.
2377 @param[in] ControllerHandle Handle of device to test.
2379 @retval EFI_SUCCESS UDF file system found.
2380 @retval EFI_UNSUPPORTED UDF file system not found.
2384 SupportUdfFileSystem (
2385 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2386 IN EFI_HANDLE ControllerHandle
2390 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2391 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2392 EFI_DEVICE_PATH_PROTOCOL
*LastDevicePathNode
;
2393 EFI_GUID
*VendorDefinedGuid
;
2394 EFI_GUID UdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
2397 // Open Device Path protocol on ControllerHandle
2399 Status
= gBS
->OpenProtocol (
2401 &gEfiDevicePathProtocolGuid
,
2402 (VOID
**)&DevicePath
,
2403 This
->DriverBindingHandle
,
2405 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2407 if (EFI_ERROR (Status
)) {
2408 return EFI_UNSUPPORTED
;
2411 Status
= EFI_UNSUPPORTED
;
2414 // Get last Device Path node
2416 LastDevicePathNode
= NULL
;
2417 DevicePathNode
= DevicePath
;
2418 while (!IsDevicePathEnd (DevicePathNode
)) {
2419 LastDevicePathNode
= DevicePathNode
;
2420 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
2423 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2424 // of an UDF file system.
2426 if (LastDevicePathNode
!= NULL
&&
2427 DevicePathType (LastDevicePathNode
) == MEDIA_DEVICE_PATH
&&
2428 DevicePathSubType (LastDevicePathNode
) == MEDIA_VENDOR_DP
) {
2429 VendorDefinedGuid
= (EFI_GUID
*)((UINTN
)LastDevicePathNode
+
2430 OFFSET_OF (VENDOR_DEVICE_PATH
, Guid
));
2431 if (CompareGuid (VendorDefinedGuid
, &UdfDevPathGuid
)) {
2432 Status
= EFI_SUCCESS
;
2437 // Close Device Path protocol on ControllerHandle
2439 gBS
->CloseProtocol (
2441 &gEfiDevicePathProtocolGuid
,
2442 This
->DriverBindingHandle
,