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
27 EFI_LBA DescriptorLBAs
[4];
30 BlockSize
= BlockIo
->Media
->BlockSize
;
31 EndLBA
= BlockIo
->Media
->LastBlock
;
32 DescriptorLBAs
[0] = 256;
33 DescriptorLBAs
[1] = EndLBA
- 256;
34 DescriptorLBAs
[2] = EndLBA
;
35 DescriptorLBAs
[3] = 512;
37 for (Index
= 0; Index
< ARRAY_SIZE (DescriptorLBAs
); Index
++) {
38 Status
= DiskIo
->ReadDisk (
40 BlockIo
->Media
->MediaId
,
41 MultU64x32 (DescriptorLBAs
[Index
], BlockSize
),
42 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
),
45 if (EFI_ERROR (Status
)) {
49 // Check if read LBA has a valid AVDP descriptor.
51 if (IS_AVDP (AnchorPoint
)) {
58 return EFI_VOLUME_CORRUPTED
;
62 StartMainVolumeDescriptorSequence (
63 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
64 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
65 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER
*AnchorPoint
,
66 OUT UDF_VOLUME_INFO
*Volume
71 UDF_EXTENT_AD
*ExtentAd
;
75 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
76 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
78 UINT32 LogicalBlockSize
;
81 // We've already found an ADVP on the volume. It contains the extent
82 // (MainVolumeDescriptorSequenceExtent) where the Main Volume Descriptor
83 // Sequence starts. Therefore, we'll look for Logical Volume Descriptors and
84 // Partitions Descriptors and save them in memory, accordingly.
86 // Note also that each descriptor will be aligned on a block size (BlockSize)
87 // boundary, so we need to read one block at a time.
89 BlockSize
= BlockIo
->Media
->BlockSize
;
90 ExtentAd
= &AnchorPoint
->MainVolumeDescriptorSequenceExtent
;
91 StartingLsn
= (UINT64
)ExtentAd
->ExtentLocation
;
92 EndingLsn
= StartingLsn
+ DivU64x32 (
93 (UINT64
)ExtentAd
->ExtentLength
,
97 Volume
->LogicalVolDescs
=
98 (UDF_LOGICAL_VOLUME_DESCRIPTOR
**)AllocateZeroPool (ExtentAd
->ExtentLength
);
99 if (Volume
->LogicalVolDescs
== NULL
) {
100 return EFI_OUT_OF_RESOURCES
;
103 Volume
->PartitionDescs
=
104 (UDF_PARTITION_DESCRIPTOR
**)AllocateZeroPool (ExtentAd
->ExtentLength
);
105 if (Volume
->PartitionDescs
== NULL
) {
106 Status
= EFI_OUT_OF_RESOURCES
;
107 goto Error_Alloc_Pds
;
110 Buffer
= AllocateZeroPool (BlockSize
);
111 if (Buffer
== NULL
) {
112 Status
= EFI_OUT_OF_RESOURCES
;
113 goto Error_Alloc_Buf
;
116 Volume
->LogicalVolDescsNo
= 0;
117 Volume
->PartitionDescsNo
= 0;
119 while (StartingLsn
<= EndingLsn
) {
120 Status
= DiskIo
->ReadDisk (
122 BlockIo
->Media
->MediaId
,
123 MultU64x32 (StartingLsn
, BlockSize
),
127 if (EFI_ERROR (Status
)) {
128 goto Error_Read_Disk_Blk
;
131 if (IS_TD (Buffer
)) {
133 // Found a Terminating Descriptor. Stop the sequence then.
138 if (IS_LVD (Buffer
)) {
140 // Found a Logical Volume Descriptor.
143 (UDF_LOGICAL_VOLUME_DESCRIPTOR
*)
144 AllocateZeroPool (sizeof (UDF_LOGICAL_VOLUME_DESCRIPTOR
));
145 if (LogicalVolDesc
== NULL
) {
146 Status
= EFI_OUT_OF_RESOURCES
;
147 goto Error_Alloc_Lvd
;
150 CopyMem ((VOID
*)LogicalVolDesc
, Buffer
,
151 sizeof (UDF_LOGICAL_VOLUME_DESCRIPTOR
));
152 Volume
->LogicalVolDescs
[Volume
->LogicalVolDescsNo
++] = LogicalVolDesc
;
153 } else if (IS_PD (Buffer
)) {
155 // Found a Partition Descriptor.
158 (UDF_PARTITION_DESCRIPTOR
*)
159 AllocateZeroPool (sizeof (UDF_PARTITION_DESCRIPTOR
));
160 if (PartitionDesc
== NULL
) {
161 Status
= EFI_OUT_OF_RESOURCES
;
165 CopyMem ((VOID
*)PartitionDesc
, Buffer
,
166 sizeof (UDF_PARTITION_DESCRIPTOR
));
167 Volume
->PartitionDescs
[Volume
->PartitionDescsNo
++] = PartitionDesc
;
174 // When an UDF volume (revision 2.00 or higher) contains a File Entry rather
175 // than an Extended File Entry (which is not recommended as per spec), we need
176 // to make sure the size of a FE will be _at least_ 2048
177 // (UDF_LOGICAL_SECTOR_SIZE) bytes long to keep backward compatibility.
179 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
180 if (LogicalBlockSize
>= UDF_LOGICAL_SECTOR_SIZE
) {
181 Volume
->FileEntrySize
= LogicalBlockSize
;
183 Volume
->FileEntrySize
= UDF_LOGICAL_SECTOR_SIZE
;
192 for (Index
= 0; Index
< Volume
->PartitionDescsNo
; Index
++) {
193 FreePool ((VOID
*)Volume
->PartitionDescs
[Index
]);
196 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
197 FreePool ((VOID
*)Volume
->LogicalVolDescs
[Index
]);
204 FreePool ((VOID
*)Volume
->PartitionDescs
);
205 Volume
->PartitionDescs
= NULL
;
208 FreePool ((VOID
*)Volume
->LogicalVolDescs
);
209 Volume
->LogicalVolDescs
= NULL
;
215 // Return a Partition Descriptor given a Long Allocation Descriptor. This is
216 // necessary to calculate the right extent (LongAd) offset which is added up
217 // with partition's starting location.
219 UDF_PARTITION_DESCRIPTOR
*
221 IN UDF_VOLUME_INFO
*Volume
,
222 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
225 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
227 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
230 LogicalVolDesc
= Volume
->LogicalVolDescs
[UDF_DEFAULT_LV_NUM
];
232 switch (LV_UDF_REVISION (LogicalVolDesc
)) {
235 // As per UDF 1.02 specification:
237 // There shall be exactly one prevailing Logical Volume Descriptor recorded
238 // per Volume Set. The Partition Maps field shall contain only Type 1
241 PartitionNum
= *(UINT16
*)((UINTN
)&LogicalVolDesc
->PartitionMaps
[4]);
245 // Ensure Type 1 Partition map. Other types aren't supported in this
248 if (LogicalVolDesc
->PartitionMaps
[0] != 1 ||
249 LogicalVolDesc
->PartitionMaps
[1] != 6) {
252 PartitionNum
= *(UINT16
*)((UINTN
)&LogicalVolDesc
->PartitionMaps
[4]);
259 PartitionNum
= LongAd
->ExtentLocation
.PartitionReferenceNumber
;
263 for (Index
= 0; Index
< Volume
->PartitionDescsNo
; Index
++) {
264 PartitionDesc
= Volume
->PartitionDescs
[Index
];
265 if (PartitionDesc
->PartitionNumber
== PartitionNum
) {
266 return PartitionDesc
;
274 // Return logical sector number of a given Long Allocation Descriptor.
278 IN UDF_VOLUME_INFO
*Volume
,
279 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
282 UDF_PARTITION_DESCRIPTOR
*PartitionDesc
;
284 PartitionDesc
= GetPdFromLongAd (Volume
, LongAd
);
285 ASSERT (PartitionDesc
!= NULL
);
287 return (UINT64
)PartitionDesc
->PartitionStartingLocation
+
288 LongAd
->ExtentLocation
.LogicalBlockNumber
;
292 // Return logical sector number of a given Short Allocation Descriptor.
296 IN UDF_PARTITION_DESCRIPTOR
*PartitionDesc
,
297 IN UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
300 return (UINT64
)PartitionDesc
->PartitionStartingLocation
+
301 ShortAd
->ExtentPosition
;
305 // Find File Set Descriptor of a given Logical Volume Descriptor.
307 // The found FSD will contain the extent (LogicalVolumeContentsUse) where our
308 // root directory is.
311 FindFileSetDescriptor (
312 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
313 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
314 IN UDF_VOLUME_INFO
*Volume
,
315 IN UINTN LogicalVolDescNum
,
316 OUT UDF_FILE_SET_DESCRIPTOR
*FileSetDesc
321 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
323 LogicalVolDesc
= Volume
->LogicalVolDescs
[LogicalVolDescNum
];
324 Lsn
= GetLongAdLsn (Volume
, &LogicalVolDesc
->LogicalVolumeContentsUse
);
327 // Read extent (Long Ad).
329 Status
= DiskIo
->ReadDisk (
331 BlockIo
->Media
->MediaId
,
332 MultU64x32 (Lsn
, LogicalVolDesc
->LogicalBlockSize
),
333 sizeof (UDF_FILE_SET_DESCRIPTOR
),
336 if (EFI_ERROR (Status
)) {
341 // Check if the read extent contains a valid FSD's tag identifier.
343 if (!IS_FSD (FileSetDesc
)) {
344 return EFI_VOLUME_CORRUPTED
;
351 // Get all File Set Descriptors for each Logical Volume Descriptor.
354 GetFileSetDescriptors (
355 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
356 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
357 IN OUT UDF_VOLUME_INFO
*Volume
362 UDF_FILE_SET_DESCRIPTOR
*FileSetDesc
;
365 Volume
->FileSetDescs
=
366 (UDF_FILE_SET_DESCRIPTOR
**)AllocateZeroPool (
367 Volume
->LogicalVolDescsNo
* sizeof (UDF_FILE_SET_DESCRIPTOR
));
368 if (Volume
->FileSetDescs
== NULL
) {
369 return EFI_OUT_OF_RESOURCES
;
372 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
373 FileSetDesc
= AllocateZeroPool (sizeof (UDF_FILE_SET_DESCRIPTOR
));
374 if (FileSetDesc
== NULL
) {
375 Status
= EFI_OUT_OF_RESOURCES
;
376 goto Error_Alloc_Fsd
;
380 // Find a FSD for this LVD.
382 Status
= FindFileSetDescriptor (
389 if (EFI_ERROR (Status
)) {
396 Volume
->FileSetDescs
[Index
] = FileSetDesc
;
399 Volume
->FileSetDescsNo
= Volume
->LogicalVolDescsNo
;
404 for (Index
= 0; Index
< Count
; Index
++) {
405 FreePool ((VOID
*)Volume
->FileSetDescs
[Index
]);
408 FreePool ((VOID
*)Volume
->FileSetDescs
);
409 Volume
->FileSetDescs
= NULL
;
416 // Read Volume and File Structure on an UDF file system.
419 ReadVolumeFileStructure (
420 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
421 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
422 OUT UDF_VOLUME_INFO
*Volume
426 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
431 Status
= FindAnchorVolumeDescriptorPointer (
436 if (EFI_ERROR (Status
)) {
441 // AVDP has been found. Start MVDS.
443 Status
= StartMainVolumeDescriptorSequence (
449 if (EFI_ERROR (Status
)) {
457 // Calculate length of a given File Identifier Descriptor.
460 GetFidDescriptorLength (
461 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
465 (INTN
)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR
, Data
[0]) + 3 +
466 FileIdentifierDesc
->LengthOfFileIdentifier
+
467 FileIdentifierDesc
->LengthOfImplementationUse
) >> 2) << 2
472 // Duplicate a given File Identifier Descriptor.
476 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
477 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**NewFileIdentifierDesc
480 *NewFileIdentifierDesc
=
481 (UDF_FILE_IDENTIFIER_DESCRIPTOR
*)AllocateCopyPool (
482 (UINTN
) GetFidDescriptorLength (FileIdentifierDesc
), FileIdentifierDesc
);
486 // Duplicate either a given File Entry or a given Extended File Entry.
490 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
491 IN UDF_VOLUME_INFO
*Volume
,
493 OUT VOID
**NewFileEntry
496 *NewFileEntry
= AllocateCopyPool (Volume
->FileEntrySize
, FileEntry
);
500 // Get raw data + length of a given File Entry or Extended File Entry.
502 // The file's recorded data can contain either real file content (inline) or
503 // a sequence of extents (or Allocation Descriptors) which tells where file's
504 // content is stored in.
506 // NOTE: The FE/EFE can be thought it was an inode.
510 IN VOID
*FileEntryData
,
515 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
516 UDF_FILE_ENTRY
*FileEntry
;
518 if (IS_EFE (FileEntryData
)) {
519 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
521 *Length
= ExtendedFileEntry
->InformationLength
;
522 *Data
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
523 ExtendedFileEntry
->LengthOfExtendedAttributes
);
524 } else if (IS_FE (FileEntryData
)) {
525 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
527 *Length
= FileEntry
->InformationLength
;
528 *Data
= (VOID
*)((UINT8
*)FileEntry
->Data
+
529 FileEntry
->LengthOfExtendedAttributes
);
534 // Get Allocation Descriptors' data information from a given FE/EFE.
538 IN VOID
*FileEntryData
,
543 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
544 UDF_FILE_ENTRY
*FileEntry
;
546 if (IS_EFE (FileEntryData
)) {
547 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
549 *Length
= ExtendedFileEntry
->LengthOfAllocationDescriptors
;
550 *AdsData
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
551 ExtendedFileEntry
->LengthOfExtendedAttributes
);
552 } else if (IS_FE (FileEntryData
)) {
553 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
555 *Length
= FileEntry
->LengthOfAllocationDescriptors
;
556 *AdsData
= (VOID
*)((UINT8
*)FileEntry
->Data
+
557 FileEntry
->LengthOfExtendedAttributes
);
562 // Read next Long Allocation Descriptor from a given file's data.
567 IN OUT UINT64
*Offset
,
569 OUT UDF_LONG_ALLOCATION_DESCRIPTOR
**FoundLongAd
572 UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
;
573 UDF_EXTENT_FLAGS ExtentFlags
;
576 if (*Offset
>= Length
) {
578 // No more Long Allocation Descriptors.
580 return EFI_DEVICE_ERROR
;
584 (UDF_LONG_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
587 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
588 // allocated AD, then return it.
590 ExtentFlags
= GET_EXTENT_FLAGS (LONG_ADS_SEQUENCE
, LongAd
);
591 if (ExtentFlags
== EXTENT_IS_NEXT_EXTENT
||
592 ExtentFlags
== EXTENT_RECORDED_AND_ALLOCATED
) {
597 // This AD is either not recorded but allocated, or not recorded and not
598 // allocated. Skip it.
600 *Offset
+= AD_LENGTH (LONG_ADS_SEQUENCE
);
603 *FoundLongAd
= LongAd
;
609 // Read next Short Allocation Descriptor from a given file's data.
614 IN OUT UINT64
*Offset
,
616 OUT UDF_SHORT_ALLOCATION_DESCRIPTOR
**FoundShortAd
619 UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
;
620 UDF_EXTENT_FLAGS ExtentFlags
;
623 if (*Offset
>= Length
) {
625 // No more Short Allocation Descriptors.
627 return EFI_DEVICE_ERROR
;
631 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
634 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
635 // allocated AD, then return it.
637 ExtentFlags
= GET_EXTENT_FLAGS (SHORT_ADS_SEQUENCE
, ShortAd
);
638 if (ExtentFlags
== EXTENT_IS_NEXT_EXTENT
||
639 ExtentFlags
== EXTENT_RECORDED_AND_ALLOCATED
) {
644 // This AD is either not recorded but allocated, or not recorded and not
645 // allocated. Skip it.
647 *Offset
+= AD_LENGTH (SHORT_ADS_SEQUENCE
);
650 *FoundShortAd
= ShortAd
;
656 // Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
660 GetAllocationDescriptor (
661 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
663 IN OUT UINT64
*Offset
,
668 if (RecordingFlags
== LONG_ADS_SEQUENCE
) {
669 return GetLongAdFromAds (
673 (UDF_LONG_ALLOCATION_DESCRIPTOR
**)FoundAd
675 } else if (RecordingFlags
== SHORT_ADS_SEQUENCE
) {
676 return GetShortAdFromAds (
680 (UDF_SHORT_ALLOCATION_DESCRIPTOR
**)FoundAd
684 return EFI_DEVICE_ERROR
;
688 // Return logical sector number of either Short or Long Allocation Descriptor.
691 GetAllocationDescriptorLsn (
692 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
693 IN UDF_VOLUME_INFO
*Volume
,
694 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
698 if (RecordingFlags
== LONG_ADS_SEQUENCE
) {
699 return GetLongAdLsn (Volume
, (UDF_LONG_ALLOCATION_DESCRIPTOR
*)Ad
);
700 } else if (RecordingFlags
== SHORT_ADS_SEQUENCE
) {
701 return GetShortAdLsn (
702 GetPdFromLongAd (Volume
, ParentIcb
),
703 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)Ad
711 // Return offset + length of a given indirect Allocation Descriptor (AED).
715 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
716 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
717 IN UDF_VOLUME_INFO
*Volume
,
718 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
719 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
729 UINT32 LogicalBlockSize
;
730 UDF_ALLOCATION_EXTENT_DESCRIPTOR
*AllocExtDesc
;
732 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
733 Lsn
= GetAllocationDescriptorLsn (RecordingFlags
,
738 Data
= AllocatePool (ExtentLength
);
740 return EFI_OUT_OF_RESOURCES
;
743 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
748 Status
= DiskIo
->ReadDisk (
750 BlockIo
->Media
->MediaId
,
751 MultU64x32 (Lsn
, LogicalBlockSize
),
755 if (EFI_ERROR (Status
)) {
760 // Check if read extent contains a valid tag identifier for AED.
762 AllocExtDesc
= (UDF_ALLOCATION_EXTENT_DESCRIPTOR
*)Data
;
763 if (!IS_AED (AllocExtDesc
)) {
764 Status
= EFI_VOLUME_CORRUPTED
;
769 // Get AED's block offset and its length.
771 *Offset
= MultU64x32 (Lsn
, LogicalBlockSize
) +
772 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR
);
773 *Length
= AllocExtDesc
->LengthOfAllocationDescriptors
;
782 // Read Allocation Extent Descriptor into memory.
786 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
787 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
788 IN UDF_VOLUME_INFO
*Volume
,
789 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
790 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
800 // Get AED's offset + length.
802 Status
= GetAedAdsOffset (
812 if (EFI_ERROR (Status
)) {
817 // Allocate buffer to read in AED's data.
819 *Data
= AllocatePool ((UINTN
) (*Length
));
821 return EFI_OUT_OF_RESOURCES
;
824 return DiskIo
->ReadDisk (
826 BlockIo
->Media
->MediaId
,
834 // Function used to serialise reads of Allocation Descriptors.
837 GrowUpBufferToNextAd (
838 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
840 IN OUT VOID
**Buffer
,
846 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
848 if (*Buffer
== NULL
) {
849 *Buffer
= AllocatePool (ExtentLength
);
850 if (*Buffer
== NULL
) {
851 return EFI_OUT_OF_RESOURCES
;
854 *Buffer
= ReallocatePool ((UINTN
) Length
, (UINTN
) (Length
+ ExtentLength
), *Buffer
);
855 if (*Buffer
== NULL
) {
856 return EFI_OUT_OF_RESOURCES
;
864 // Read data or size of either a File Entry or an Extended File Entry.
868 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
869 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
870 IN UDF_VOLUME_INFO
*Volume
,
871 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
872 IN VOID
*FileEntryData
,
873 IN OUT UDF_READ_FILE_INFO
*ReadFileInfo
877 UINT32 LogicalBlockSize
;
889 BOOLEAN FinishedSeeking
;
891 UDF_FE_RECORDING_FLAGS RecordingFlags
;
893 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
896 switch (ReadFileInfo
->Flags
) {
897 case READ_FILE_GET_FILESIZE
:
898 case READ_FILE_ALLOCATE_AND_READ
:
900 // Initialise ReadFileInfo structure for either getting file size, or
901 // reading file's recorded data.
903 ReadFileInfo
->ReadLength
= 0;
904 ReadFileInfo
->FileData
= NULL
;
906 case READ_FILE_SEEK_AND_READ
:
908 // About to seek a file and/or read its data.
910 Length
= ReadFileInfo
->FileSize
- ReadFileInfo
->FilePosition
;
911 if (ReadFileInfo
->FileDataSize
> Length
) {
913 // About to read beyond the EOF -- truncate it.
915 ReadFileInfo
->FileDataSize
= Length
;
919 // Initialise data to start seeking and/or reading a file.
921 BytesLeft
= ReadFileInfo
->FileDataSize
;
924 FinishedSeeking
= FALSE
;
929 RecordingFlags
= GET_FE_RECORDING_FLAGS (FileEntryData
);
930 switch (RecordingFlags
) {
933 // There are no extents for this FE/EFE. All data is inline.
935 GetFileEntryData (FileEntryData
, &Data
, &Length
);
937 if (ReadFileInfo
->Flags
== READ_FILE_GET_FILESIZE
) {
938 ReadFileInfo
->ReadLength
= Length
;
939 } else if (ReadFileInfo
->Flags
== READ_FILE_ALLOCATE_AND_READ
) {
941 // Allocate buffer for starting read data.
943 ReadFileInfo
->FileData
= AllocatePool ((UINTN
) Length
);
944 if (ReadFileInfo
->FileData
== NULL
) {
945 return EFI_OUT_OF_RESOURCES
;
949 // Read all inline data into ReadFileInfo->FileData
951 CopyMem (ReadFileInfo
->FileData
, Data
, (UINTN
) Length
);
952 ReadFileInfo
->ReadLength
= Length
;
953 } else if (ReadFileInfo
->Flags
== READ_FILE_SEEK_AND_READ
) {
955 // If FilePosition is non-zero, seek file to FilePosition, read
956 // FileDataSize bytes and then updates FilePosition.
959 ReadFileInfo
->FileData
,
960 (VOID
*)((UINT8
*)Data
+ ReadFileInfo
->FilePosition
),
961 (UINTN
) ReadFileInfo
->FileDataSize
964 ReadFileInfo
->FilePosition
+= ReadFileInfo
->FileDataSize
;
967 return EFI_INVALID_PARAMETER
;
970 Status
= EFI_SUCCESS
;
973 case LONG_ADS_SEQUENCE
:
974 case SHORT_ADS_SEQUENCE
:
976 // This FE/EFE contains a run of Allocation Descriptors. Get data + size
977 // for start reading them out.
979 GetAdsInformation (FileEntryData
, &Data
, &Length
);
986 Status
= GetAllocationDescriptor (
993 if (Status
== EFI_DEVICE_ERROR
) {
994 Status
= EFI_SUCCESS
;
999 // Check if AD is an indirect AD. If so, read Allocation Extent
1000 // Descriptor and its extents (ADs).
1002 if (GET_EXTENT_FLAGS (RecordingFlags
, Ad
) == EXTENT_IS_NEXT_EXTENT
) {
1009 Status
= GetAedAdsData (
1019 if (EFI_ERROR (Status
)) {
1027 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1029 Lsn
= GetAllocationDescriptorLsn (RecordingFlags
,
1034 switch (ReadFileInfo
->Flags
) {
1035 case READ_FILE_GET_FILESIZE
:
1036 ReadFileInfo
->ReadLength
+= ExtentLength
;
1038 case READ_FILE_ALLOCATE_AND_READ
:
1040 // Increase FileData (if necessary) to read next extent.
1042 Status
= GrowUpBufferToNextAd (
1045 &ReadFileInfo
->FileData
,
1046 ReadFileInfo
->ReadLength
1048 if (EFI_ERROR (Status
)) {
1049 goto Error_Alloc_Buffer_To_Next_Ad
;
1053 // Read extent's data into FileData.
1055 Status
= DiskIo
->ReadDisk (
1057 BlockIo
->Media
->MediaId
,
1058 MultU64x32 (Lsn
, LogicalBlockSize
),
1060 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1061 ReadFileInfo
->ReadLength
)
1063 if (EFI_ERROR (Status
)) {
1064 goto Error_Read_Disk_Blk
;
1067 ReadFileInfo
->ReadLength
+= ExtentLength
;
1069 case READ_FILE_SEEK_AND_READ
:
1071 // Seek file first before reading in its data.
1073 if (FinishedSeeking
) {
1075 goto Skip_File_Seek
;
1078 if (FilePosition
+ ExtentLength
< ReadFileInfo
->FilePosition
) {
1079 FilePosition
+= ExtentLength
;
1083 if (FilePosition
+ ExtentLength
> ReadFileInfo
->FilePosition
) {
1084 Offset
= ReadFileInfo
->FilePosition
- FilePosition
;
1090 // Done with seeking file. Start reading its data.
1092 FinishedSeeking
= TRUE
;
1096 // Make sure we don't read more data than really wanted.
1098 if (ExtentLength
- Offset
> BytesLeft
) {
1099 DataLength
= BytesLeft
;
1101 DataLength
= ExtentLength
- Offset
;
1105 // Read extent's data into FileData.
1107 Status
= DiskIo
->ReadDisk (
1109 BlockIo
->Media
->MediaId
,
1110 Offset
+ MultU64x32 (Lsn
, LogicalBlockSize
),
1112 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1115 if (EFI_ERROR (Status
)) {
1116 goto Error_Read_Disk_Blk
;
1120 // Update current file's position.
1122 DataOffset
+= DataLength
;
1123 ReadFileInfo
->FilePosition
+= DataLength
;
1125 BytesLeft
-= DataLength
;
1126 if (BytesLeft
== 0) {
1128 // There is no more file data to read.
1130 Status
= EFI_SUCCESS
;
1139 // Point to the next AD (extent).
1141 AdOffset
+= AD_LENGTH (RecordingFlags
);
1145 case EXTENDED_ADS_SEQUENCE
:
1146 // FIXME: Not supported. Got no volume with it, yet.
1148 Status
= EFI_UNSUPPORTED
;
1159 Error_Read_Disk_Blk
:
1160 Error_Alloc_Buffer_To_Next_Ad
:
1161 if (ReadFileInfo
->Flags
!= READ_FILE_SEEK_AND_READ
) {
1162 FreePool (ReadFileInfo
->FileData
);
1174 // Find a file by its filename from a given Parent file.
1178 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1179 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1180 IN UDF_VOLUME_INFO
*Volume
,
1181 IN CHAR16
*FileName
,
1182 IN UDF_FILE_INFO
*Parent
,
1183 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1184 OUT UDF_FILE_INFO
*File
1188 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1189 UDF_READ_DIRECTORY_INFO ReadDirInfo
;
1191 CHAR16 FoundFileName
[UDF_FILENAME_LENGTH
];
1192 VOID
*CompareFileEntry
;
1195 // Check if parent file is really directory.
1197 if (!IS_FE_DIRECTORY (Parent
->FileEntry
)) {
1198 return EFI_NOT_FOUND
;
1202 // If FileName is current file or working directory, just duplicate Parent's
1203 // FE/EFE and FID descriptors.
1205 if (StrCmp (FileName
, L
".") == 0) {
1206 DuplicateFe (BlockIo
, Volume
, Parent
->FileEntry
, &File
->FileEntry
);
1207 DuplicateFid (Parent
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1213 // Start directory listing.
1215 ZeroMem ((VOID
*)&ReadDirInfo
, sizeof (UDF_READ_DIRECTORY_INFO
));
1219 Status
= ReadDirectoryEntry (
1223 Parent
->FileIdentifierDesc
?
1224 &Parent
->FileIdentifierDesc
->Icb
:
1230 if (EFI_ERROR (Status
)) {
1231 if (Status
== EFI_DEVICE_ERROR
) {
1232 Status
= EFI_NOT_FOUND
;
1238 if (IS_FID_PARENT_FILE (FileIdentifierDesc
)) {
1240 // This FID contains the location (FE/EFE) of the parent directory of this
1241 // directory (Parent), and if FileName is either ".." or "\\", then it's
1242 // the expected FID.
1244 if (StrCmp (FileName
, L
"..") == 0 || StrCmp (FileName
, L
"\\") == 0) {
1249 Status
= GetFileNameFromFid (FileIdentifierDesc
, FoundFileName
);
1250 if (EFI_ERROR (Status
)) {
1254 if (StrCmp (FileName
, FoundFileName
) == 0) {
1256 // FID has been found. Prepare to find its respective FE/EFE.
1263 FreePool ((VOID
*)FileIdentifierDesc
);
1266 if (ReadDirInfo
.DirectoryData
!= NULL
) {
1268 // Free all allocated resources for the directory listing.
1270 FreePool (ReadDirInfo
.DirectoryData
);
1274 Status
= EFI_SUCCESS
;
1276 File
->FileIdentifierDesc
= FileIdentifierDesc
;
1279 // If the requested file is root directory, then the FE/EFE was already
1280 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1282 // Otherwise, find FE/EFE from the respective FID.
1284 if (StrCmp (FileName
, L
"\\") != 0) {
1285 Status
= FindFileEntry (
1289 &FileIdentifierDesc
->Icb
,
1292 if (EFI_ERROR (Status
)) {
1297 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1299 if (CompareMem ((VOID
*)Parent
->FileEntry
, (VOID
*)CompareFileEntry
,
1300 Volume
->FileEntrySize
) != 0) {
1301 File
->FileEntry
= CompareFileEntry
;
1303 FreePool ((VOID
*)FileIdentifierDesc
);
1304 FreePool ((VOID
*)CompareFileEntry
);
1305 Status
= EFI_NOT_FOUND
;
1313 FreePool ((VOID
*)FileIdentifierDesc
);
1319 Read volume information on a medium which contains a valid UDF file system.
1321 @param[in] BlockIo BlockIo interface.
1322 @param[in] DiskIo DiskIo interface.
1323 @param[out] Volume UDF volume information structure.
1325 @retval EFI_SUCCESS Volume information read.
1326 @retval EFI_NO_MEDIA The device has no media.
1327 @retval EFI_DEVICE_ERROR The device reported an error.
1328 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1329 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1333 ReadUdfVolumeInformation (
1334 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1335 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1336 OUT UDF_VOLUME_INFO
*Volume
1341 Status
= ReadVolumeFileStructure (
1346 if (EFI_ERROR (Status
)) {
1350 Status
= GetFileSetDescriptors (
1355 if (EFI_ERROR (Status
)) {
1356 CleanupVolumeInformation (Volume
);
1363 Find the root directory on an UDF volume.
1365 @param[in] BlockIo BlockIo interface.
1366 @param[in] DiskIo DiskIo interface.
1367 @param[in] Volume UDF volume information structure.
1368 @param[out] File Root directory file.
1370 @retval EFI_SUCCESS Root directory found.
1371 @retval EFI_NO_MEDIA The device has no media.
1372 @retval EFI_DEVICE_ERROR The device reported an error.
1373 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1374 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1380 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1381 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1382 IN UDF_VOLUME_INFO
*Volume
,
1383 OUT UDF_FILE_INFO
*File
1387 UDF_FILE_INFO Parent
;
1389 Status
= FindFileEntry (
1393 &Volume
->FileSetDescs
[0]->RootDirectoryIcb
,
1396 if (EFI_ERROR (Status
)) {
1400 Parent
.FileEntry
= File
->FileEntry
;
1401 Parent
.FileIdentifierDesc
= NULL
;
1410 &Volume
->FileSetDescs
[0]->RootDirectoryIcb
,
1413 if (EFI_ERROR (Status
)) {
1414 FreePool (File
->FileEntry
);
1421 Find either a File Entry or a Extended File Entry from a given ICB.
1423 @param[in] BlockIo BlockIo interface.
1424 @param[in] DiskIo DiskIo interface.
1425 @param[in] Volume UDF volume information structure.
1426 @param[in] Icb ICB of the FID.
1427 @param[out] FileEntry File Entry or Extended File Entry.
1429 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1430 @retval EFI_NO_MEDIA The device has no media.
1431 @retval EFI_DEVICE_ERROR The device reported an error.
1432 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1433 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1439 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1440 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1441 IN UDF_VOLUME_INFO
*Volume
,
1442 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1443 OUT VOID
**FileEntry
1448 UINT32 LogicalBlockSize
;
1450 Lsn
= GetLongAdLsn (Volume
, Icb
);
1451 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
1453 *FileEntry
= AllocateZeroPool (Volume
->FileEntrySize
);
1454 if (*FileEntry
== NULL
) {
1455 return EFI_OUT_OF_RESOURCES
;
1461 Status
= DiskIo
->ReadDisk (
1463 BlockIo
->Media
->MediaId
,
1464 MultU64x32 (Lsn
, LogicalBlockSize
),
1465 Volume
->FileEntrySize
,
1468 if (EFI_ERROR (Status
)) {
1469 goto Error_Read_Disk_Blk
;
1473 // Check if the read extent contains a valid Tag Identifier for the expected
1476 if (!IS_FE (*FileEntry
) && !IS_EFE (*FileEntry
)) {
1477 Status
= EFI_VOLUME_CORRUPTED
;
1478 goto Error_Invalid_Fe
;
1484 Error_Read_Disk_Blk
:
1485 FreePool (*FileEntry
);
1491 Find a file given its absolute path on an UDF volume.
1493 @param[in] BlockIo BlockIo interface.
1494 @param[in] DiskIo DiskIo interface.
1495 @param[in] Volume UDF volume information structure.
1496 @param[in] FilePath File's absolute path.
1497 @param[in] Root Root directory file.
1498 @param[in] Parent Parent directory file.
1499 @param[out] File Found file.
1501 @retval EFI_SUCCESS @p FilePath was found.
1502 @retval EFI_NO_MEDIA The device has no media.
1503 @retval EFI_DEVICE_ERROR The device reported an error.
1504 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1505 @retval EFI_OUT_OF_RESOURCES The @p FilePath file was not found due to lack of
1511 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1512 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1513 IN UDF_VOLUME_INFO
*Volume
,
1514 IN CHAR16
*FilePath
,
1515 IN UDF_FILE_INFO
*Root
,
1516 IN UDF_FILE_INFO
*Parent
,
1517 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1518 OUT UDF_FILE_INFO
*File
1522 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1523 CHAR16
*FileNamePointer
;
1524 UDF_FILE_INFO PreviousFile
;
1527 Status
= EFI_NOT_FOUND
;
1529 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1530 while (*FilePath
!= L
'\0') {
1531 FileNamePointer
= FileName
;
1532 while (*FilePath
!= L
'\0' && *FilePath
!= L
'\\') {
1533 *FileNamePointer
++ = *FilePath
++;
1536 *FileNamePointer
= L
'\0';
1537 if (FileName
[0] == L
'\0') {
1539 // Open root directory.
1543 // There is no file found for the root directory yet. So, find only its
1546 // See UdfOpenVolume() function.
1548 Status
= InternalFindFile (BlockIo
,
1557 // We've already a file pointer (Root) for the root directory. Duplicate
1558 // its FE/EFE and FID descriptors.
1560 DuplicateFe (BlockIo
, Volume
, Root
->FileEntry
, &File
->FileEntry
);
1561 DuplicateFid (Root
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1562 Status
= EFI_SUCCESS
;
1566 // No root directory. Find filename from the current directory.
1568 Status
= InternalFindFile (BlockIo
,
1577 if (EFI_ERROR (Status
)) {
1582 // If the found file is a symlink, then find its respective FE/EFE and
1585 if (IS_FE_SYMLINK (File
->FileEntry
)) {
1586 FreePool ((VOID
*)File
->FileIdentifierDesc
);
1588 FileEntry
= File
->FileEntry
;
1590 Status
= ResolveSymlink (BlockIo
,
1597 FreePool (FileEntry
);
1599 if (EFI_ERROR (Status
)) {
1604 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1605 sizeof (UDF_FILE_INFO
)) != 0) {
1606 CleanupFileInformation (&PreviousFile
);
1609 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1610 if (*FilePath
!= L
'\0' && *FilePath
== L
'\\') {
1619 Read a directory entry at a time on an UDF volume.
1621 @param[in] BlockIo BlockIo interface.
1622 @param[in] DiskIo DiskIo interface.
1623 @param[in] Volume UDF volume information structure.
1624 @param[in] ParentIcb ICB of the parent file.
1625 @param[in] FileEntryData FE/EFE of the parent file.
1626 @param[in out] ReadDirInfo Next read directory listing structure
1628 @param[out] FoundFid File Identifier Descriptor pointer.
1630 @retval EFI_SUCCESS Directory entry read.
1631 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1632 @retval EFI_NO_MEDIA The device has no media.
1633 @retval EFI_DEVICE_ERROR The device reported an error.
1634 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1635 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1640 ReadDirectoryEntry (
1641 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1642 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1643 IN UDF_VOLUME_INFO
*Volume
,
1644 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1645 IN VOID
*FileEntryData
,
1646 IN OUT UDF_READ_DIRECTORY_INFO
*ReadDirInfo
,
1647 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**FoundFid
1651 UDF_READ_FILE_INFO ReadFileInfo
;
1652 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1654 if (ReadDirInfo
->DirectoryData
== NULL
) {
1656 // The directory's recorded data has not been read yet. So let's cache it
1657 // into memory and the next calls won't need to read it again.
1659 ReadFileInfo
.Flags
= READ_FILE_ALLOCATE_AND_READ
;
1669 if (EFI_ERROR (Status
)) {
1674 // Fill in ReadDirInfo structure with the read directory's data information.
1676 ReadDirInfo
->DirectoryData
= ReadFileInfo
.FileData
;
1677 ReadDirInfo
->DirectoryLength
= ReadFileInfo
.ReadLength
;
1681 if (ReadDirInfo
->FidOffset
>= ReadDirInfo
->DirectoryLength
) {
1683 // There are no longer FIDs for this directory. By returning
1684 // EFI_DEVICE_ERROR to the callee will indicate end of directory
1687 return EFI_DEVICE_ERROR
;
1691 // Get FID for this entry.
1693 FileIdentifierDesc
= GET_FID_FROM_ADS (ReadDirInfo
->DirectoryData
,
1694 ReadDirInfo
->FidOffset
);
1696 // Update FidOffset to point to next FID.
1698 ReadDirInfo
->FidOffset
+= GetFidDescriptorLength (FileIdentifierDesc
);
1699 } while (IS_FID_DELETED_FILE (FileIdentifierDesc
));
1701 DuplicateFid (FileIdentifierDesc
, FoundFid
);
1707 Get a filename (encoded in OSTA-compressed format) from a File Identifier
1708 Descriptor on an UDF volume.
1710 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
1711 @param[out] FileName Decoded filename.
1713 @retval EFI_SUCCESS Filename decoded and read.
1714 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1717 GetFileNameFromFid (
1718 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
1719 OUT CHAR16
*FileName
1722 UINT8
*OstaCompressed
;
1723 UINT8 CompressionId
;
1729 (UINT8
*)FileIdentifierDesc
->Data
+
1730 FileIdentifierDesc
->LengthOfImplementationUse
1733 CompressionId
= OstaCompressed
[0];
1734 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
1735 return EFI_VOLUME_CORRUPTED
;
1741 Length
= FileIdentifierDesc
->LengthOfFileIdentifier
;
1742 for (Index
= 1; Index
< Length
; Index
++) {
1743 if (CompressionId
== 16) {
1744 *FileName
= OstaCompressed
[Index
++] << 8;
1749 if (Index
< Length
) {
1750 *FileName
|= OstaCompressed
[Index
];
1762 Resolve a symlink file on an UDF volume.
1764 @param[in] BlockIo BlockIo interface.
1765 @param[in] DiskIo DiskIo interface.
1766 @param[in] Volume UDF volume information structure.
1767 @param[in] Parent Parent file.
1768 @param[in] FileEntryData FE/EFE structure pointer.
1769 @param[out] File Resolved file.
1771 @retval EFI_SUCCESS Symlink file resolved.
1772 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1773 @retval EFI_NO_MEDIA The device has no media.
1774 @retval EFI_DEVICE_ERROR The device reported an error.
1775 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1776 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
1782 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1783 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1784 IN UDF_VOLUME_INFO
*Volume
,
1785 IN UDF_FILE_INFO
*Parent
,
1786 IN VOID
*FileEntryData
,
1787 OUT UDF_FILE_INFO
*File
1791 UDF_READ_FILE_INFO ReadFileInfo
;
1795 UDF_PATH_COMPONENT
*PathComp
;
1796 UINT8 PathCompLength
;
1797 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1800 UINT8 CompressionId
;
1801 UDF_FILE_INFO PreviousFile
;
1804 // Symlink files on UDF volumes do not contain so much data other than
1805 // Path Components which resolves to real filenames, so it's OK to read in
1806 // all its data here -- usually the data will be inline with the FE/EFE for
1809 ReadFileInfo
.Flags
= READ_FILE_ALLOCATE_AND_READ
;
1815 &Parent
->FileIdentifierDesc
->Icb
,
1819 if (EFI_ERROR (Status
)) {
1823 Length
= ReadFileInfo
.ReadLength
;
1825 Data
= (UINT8
*)ReadFileInfo
.FileData
;
1826 EndData
= Data
+ Length
;
1828 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1831 PathComp
= (UDF_PATH_COMPONENT
*)Data
;
1833 PathCompLength
= PathComp
->LengthOfComponentIdentifier
;
1835 switch (PathComp
->ComponentType
) {
1838 // This Path Component specifies the root directory hierarchy subject to
1839 // agreement between the originator and recipient of the medium. Skip it.
1845 // "\\." of the current directory. Read next Path Component.
1847 goto Next_Path_Component
;
1850 // ".." (parent directory). Go to it.
1852 CopyMem ((VOID
*)FileName
, L
"..", 6);
1856 // "." (current file). Duplicate both FE/EFE and FID of this file.
1858 DuplicateFe (BlockIo
, Volume
, PreviousFile
.FileEntry
, &File
->FileEntry
);
1859 DuplicateFid (PreviousFile
.FileIdentifierDesc
,
1860 &File
->FileIdentifierDesc
);
1861 goto Next_Path_Component
;
1864 // This Path Component identifies an object, either a file or a
1865 // directory or an alias.
1867 // Decode it from the compressed data in ComponentIdentifier and find
1870 CompressionId
= PathComp
->ComponentIdentifier
[0];
1871 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
1872 return EFI_VOLUME_CORRUPTED
;
1876 for (Index
= 1; Index
< PathCompLength
; Index
++) {
1877 if (CompressionId
== 16) {
1878 *C
= *(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+
1885 if (Index
< Length
) {
1886 *C
|= *(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+ Index
);
1897 // Find file from the read filename in symlink's file data.
1899 Status
= InternalFindFile (
1908 if (EFI_ERROR (Status
)) {
1909 goto Error_Find_File
;
1912 Next_Path_Component
:
1913 Data
+= sizeof (UDF_PATH_COMPONENT
) + PathCompLength
;
1914 if (Data
>= EndData
) {
1918 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1919 sizeof (UDF_FILE_INFO
)) != 0) {
1920 CleanupFileInformation (&PreviousFile
);
1923 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1927 // Unmap the symlink file.
1929 FreePool (ReadFileInfo
.FileData
);
1934 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1935 sizeof (UDF_FILE_INFO
)) != 0) {
1936 CleanupFileInformation (&PreviousFile
);
1939 FreePool (ReadFileInfo
.FileData
);
1945 Clean up in-memory UDF volume information.
1947 @param[in] Volume Volume information pointer.
1951 CleanupVolumeInformation (
1952 IN UDF_VOLUME_INFO
*Volume
1957 if (Volume
->LogicalVolDescs
!= NULL
) {
1958 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
1959 FreePool ((VOID
*)Volume
->LogicalVolDescs
[Index
]);
1961 FreePool ((VOID
*)Volume
->LogicalVolDescs
);
1964 if (Volume
->PartitionDescs
!= NULL
) {
1965 for (Index
= 0; Index
< Volume
->PartitionDescsNo
; Index
++) {
1966 FreePool ((VOID
*)Volume
->PartitionDescs
[Index
]);
1968 FreePool ((VOID
*)Volume
->PartitionDescs
);
1971 if (Volume
->FileSetDescs
!= NULL
) {
1972 for (Index
= 0; Index
< Volume
->FileSetDescsNo
; Index
++) {
1973 FreePool ((VOID
*)Volume
->FileSetDescs
[Index
]);
1975 FreePool ((VOID
*)Volume
->FileSetDescs
);
1978 ZeroMem ((VOID
*)Volume
, sizeof (UDF_VOLUME_INFO
));
1982 Clean up in-memory UDF file information.
1984 @param[in] File File information pointer.
1988 CleanupFileInformation (
1989 IN UDF_FILE_INFO
*File
1992 if (File
->FileEntry
!= NULL
) {
1993 FreePool (File
->FileEntry
);
1995 if (File
->FileIdentifierDesc
!= NULL
) {
1996 FreePool ((VOID
*)File
->FileIdentifierDesc
);
1999 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
2003 Find a file from its absolute path on an UDF volume.
2005 @param[in] BlockIo BlockIo interface.
2006 @param[in] DiskIo DiskIo interface.
2007 @param[in] Volume UDF volume information structure.
2008 @param[in] File File information structure.
2009 @param[out] Size Size of the file.
2011 @retval EFI_SUCCESS File size calculated and set in @p Size.
2012 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2013 @retval EFI_NO_MEDIA The device has no media.
2014 @retval EFI_DEVICE_ERROR The device reported an error.
2015 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2016 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2022 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2023 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2024 IN UDF_VOLUME_INFO
*Volume
,
2025 IN UDF_FILE_INFO
*File
,
2030 UDF_READ_FILE_INFO ReadFileInfo
;
2032 ReadFileInfo
.Flags
= READ_FILE_GET_FILESIZE
;
2038 &File
->FileIdentifierDesc
->Icb
,
2042 if (EFI_ERROR (Status
)) {
2046 *Size
= ReadFileInfo
.ReadLength
;
2052 Set information about a file on an UDF volume.
2054 @param[in] File File pointer.
2055 @param[in] FileSize Size of the file.
2056 @param[in] FileName Filename of the file.
2057 @param[in out] BufferSize Size of the returned file infomation.
2058 @param[out] Buffer Data of the returned file information.
2060 @retval EFI_SUCCESS File information set.
2061 @retval EFI_NO_MEDIA The device has no media.
2062 @retval EFI_DEVICE_ERROR The device reported an error.
2063 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2064 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2070 IN UDF_FILE_INFO
*File
,
2072 IN CHAR16
*FileName
,
2073 IN OUT UINTN
*BufferSize
,
2077 UINTN FileInfoLength
;
2078 EFI_FILE_INFO
*FileInfo
;
2079 UDF_FILE_ENTRY
*FileEntry
;
2080 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
2083 // Calculate the needed size for the EFI_FILE_INFO structure.
2085 FileInfoLength
= sizeof (EFI_FILE_INFO
) + (FileName
?
2086 StrSize (FileName
) :
2088 if (*BufferSize
< FileInfoLength
) {
2090 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2092 *BufferSize
= FileInfoLength
;
2093 return EFI_BUFFER_TOO_SMALL
;
2097 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2098 // Now, fill it in with all necessary information about the file.
2100 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
2101 FileInfo
->Size
= FileInfoLength
;
2102 FileInfo
->Attribute
&= ~EFI_FILE_VALID_ATTR
;
2103 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
2105 if (IS_FID_DIRECTORY_FILE (File
->FileIdentifierDesc
)) {
2106 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
2107 } else if (IS_FID_NORMAL_FILE (File
->FileIdentifierDesc
)) {
2108 FileInfo
->Attribute
|= EFI_FILE_ARCHIVE
;
2111 if (IS_FID_HIDDEN_FILE (File
->FileIdentifierDesc
)) {
2112 FileInfo
->Attribute
|= EFI_FILE_HIDDEN
;
2115 if (IS_FE (File
->FileEntry
)) {
2116 FileEntry
= (UDF_FILE_ENTRY
*)File
->FileEntry
;
2119 // Check if FE has the system attribute set.
2121 if (FileEntry
->IcbTag
.Flags
& (1 << 10)) {
2122 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2125 FileInfo
->FileSize
= FileSize
;
2126 FileInfo
->PhysicalSize
= FileSize
;
2128 FileInfo
->CreateTime
.Year
= FileEntry
->AccessTime
.Year
;
2129 FileInfo
->CreateTime
.Month
= FileEntry
->AccessTime
.Month
;
2130 FileInfo
->CreateTime
.Day
= FileEntry
->AccessTime
.Day
;
2131 FileInfo
->CreateTime
.Hour
= FileEntry
->AccessTime
.Hour
;
2132 FileInfo
->CreateTime
.Minute
= FileEntry
->AccessTime
.Second
;
2133 FileInfo
->CreateTime
.Second
= FileEntry
->AccessTime
.Second
;
2134 FileInfo
->CreateTime
.Nanosecond
=
2135 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2137 FileInfo
->LastAccessTime
.Year
=
2138 FileEntry
->AccessTime
.Year
;
2139 FileInfo
->LastAccessTime
.Month
=
2140 FileEntry
->AccessTime
.Month
;
2141 FileInfo
->LastAccessTime
.Day
=
2142 FileEntry
->AccessTime
.Day
;
2143 FileInfo
->LastAccessTime
.Hour
=
2144 FileEntry
->AccessTime
.Hour
;
2145 FileInfo
->LastAccessTime
.Minute
=
2146 FileEntry
->AccessTime
.Minute
;
2147 FileInfo
->LastAccessTime
.Second
=
2148 FileEntry
->AccessTime
.Second
;
2149 FileInfo
->LastAccessTime
.Nanosecond
=
2150 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2151 } else if (IS_EFE (File
->FileEntry
)) {
2152 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)File
->FileEntry
;
2155 // Check if EFE has the system attribute set.
2157 if (ExtendedFileEntry
->IcbTag
.Flags
& (1 << 10)) {
2158 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2161 FileInfo
->FileSize
= FileSize
;
2162 FileInfo
->PhysicalSize
= FileSize
;
2164 FileInfo
->CreateTime
.Year
= ExtendedFileEntry
->CreationTime
.Year
;
2165 FileInfo
->CreateTime
.Month
= ExtendedFileEntry
->CreationTime
.Month
;
2166 FileInfo
->CreateTime
.Day
= ExtendedFileEntry
->CreationTime
.Day
;
2167 FileInfo
->CreateTime
.Hour
= ExtendedFileEntry
->CreationTime
.Hour
;
2168 FileInfo
->CreateTime
.Minute
= ExtendedFileEntry
->CreationTime
.Second
;
2169 FileInfo
->CreateTime
.Second
= ExtendedFileEntry
->CreationTime
.Second
;
2170 FileInfo
->CreateTime
.Nanosecond
=
2171 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2173 FileInfo
->LastAccessTime
.Year
=
2174 ExtendedFileEntry
->AccessTime
.Year
;
2175 FileInfo
->LastAccessTime
.Month
=
2176 ExtendedFileEntry
->AccessTime
.Month
;
2177 FileInfo
->LastAccessTime
.Day
=
2178 ExtendedFileEntry
->AccessTime
.Day
;
2179 FileInfo
->LastAccessTime
.Hour
=
2180 ExtendedFileEntry
->AccessTime
.Hour
;
2181 FileInfo
->LastAccessTime
.Minute
=
2182 ExtendedFileEntry
->AccessTime
.Minute
;
2183 FileInfo
->LastAccessTime
.Second
=
2184 ExtendedFileEntry
->AccessTime
.Second
;
2185 FileInfo
->LastAccessTime
.Nanosecond
=
2186 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2189 FileInfo
->CreateTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2190 FileInfo
->CreateTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2191 FileInfo
->LastAccessTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2192 FileInfo
->LastAccessTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2194 CopyMem ((VOID
*)&FileInfo
->ModificationTime
,
2195 (VOID
*)&FileInfo
->LastAccessTime
,
2198 if (FileName
!= NULL
) {
2199 StrCpyS (FileInfo
->FileName
, StrLen (FileName
) + 1, FileName
);
2201 FileInfo
->FileName
[0] = '\0';
2204 *BufferSize
= FileInfoLength
;
2210 Get volume and free space size information of an UDF volume.
2212 @param[in] BlockIo BlockIo interface.
2213 @param[in] DiskIo DiskIo interface.
2214 @param[in] Volume UDF volume information structure.
2215 @param[out] VolumeSize Volume size.
2216 @param[out] FreeSpaceSize Free space size.
2218 @retval EFI_SUCCESS Volume and free space size calculated.
2219 @retval EFI_NO_MEDIA The device has no media.
2220 @retval EFI_DEVICE_ERROR The device reported an error.
2221 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2222 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
2223 calculated due to lack of resources.
2228 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2229 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2230 IN UDF_VOLUME_INFO
*Volume
,
2231 OUT UINT64
*VolumeSize
,
2232 OUT UINT64
*FreeSpaceSize
2235 UDF_EXTENT_AD ExtentAd
;
2236 UINT32 LogicalBlockSize
;
2239 UDF_LOGICAL_VOLUME_INTEGRITY
*LogicalVolInt
;
2247 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
2248 CopyMem ((VOID
*)&ExtentAd
,
2249 (VOID
*)&Volume
->LogicalVolDescs
[Index
]->IntegritySequenceExtent
,
2250 sizeof (UDF_EXTENT_AD
));
2251 if (ExtentAd
.ExtentLength
== 0) {
2255 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, Index
);
2258 LogicalVolInt
= (UDF_LOGICAL_VOLUME_INTEGRITY
*)
2259 AllocatePool (ExtentAd
.ExtentLength
);
2260 if (LogicalVolInt
== NULL
) {
2261 return EFI_OUT_OF_RESOURCES
;
2264 Lsn
= (UINT64
)ExtentAd
.ExtentLocation
;
2266 Status
= DiskIo
->ReadDisk (
2268 BlockIo
->Media
->MediaId
,
2269 MultU64x32 (Lsn
, LogicalBlockSize
),
2270 ExtentAd
.ExtentLength
,
2271 (VOID
*)LogicalVolInt
2273 if (EFI_ERROR (Status
)) {
2274 FreePool ((VOID
*)LogicalVolInt
);
2278 if (!IS_LVID (LogicalVolInt
)) {
2279 FreePool ((VOID
*)LogicalVolInt
);
2280 return EFI_VOLUME_CORRUPTED
;
2283 Length
= LogicalVolInt
->NumberOfPartitions
;
2284 for (Index
= 0; Index
< Length
; Index
+= sizeof (UINT32
)) {
2285 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2286 if (LsnsNo
== 0xFFFFFFFFUL
) {
2288 // Size not specified.
2293 *FreeSpaceSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2296 Length
= (LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
)) << 1;
2297 for (; Index
< Length
; Index
+= sizeof (UINT32
)) {
2298 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2299 if (LsnsNo
== 0xFFFFFFFFUL
) {
2301 // Size not specified.
2306 *VolumeSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2309 CopyMem ((VOID
*)&ExtentAd
,(VOID
*)&LogicalVolInt
->NextIntegrityExtent
,
2310 sizeof (UDF_EXTENT_AD
));
2311 if (ExtentAd
.ExtentLength
> 0) {
2312 FreePool ((VOID
*)LogicalVolInt
);
2313 goto Read_Next_Sequence
;
2316 FreePool ((VOID
*)LogicalVolInt
);
2323 Seek a file and read its data into memory on an UDF volume.
2325 @param[in] BlockIo BlockIo interface.
2326 @param[in] DiskIo DiskIo interface.
2327 @param[in] Volume UDF volume information structure.
2328 @param[in] File File information structure.
2329 @param[in] FileSize Size of the file.
2330 @param[in out] FilePosition File position.
2331 @param[in out] Buffer File data.
2332 @param[in out] BufferSize Read size.
2334 @retval EFI_SUCCESS File seeked and read.
2335 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2336 @retval EFI_NO_MEDIA The device has no media.
2337 @retval EFI_DEVICE_ERROR The device reported an error.
2338 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2339 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2345 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2346 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2347 IN UDF_VOLUME_INFO
*Volume
,
2348 IN UDF_FILE_INFO
*File
,
2350 IN OUT UINT64
*FilePosition
,
2351 IN OUT VOID
*Buffer
,
2352 IN OUT UINT64
*BufferSize
2356 UDF_READ_FILE_INFO ReadFileInfo
;
2358 ReadFileInfo
.Flags
= READ_FILE_SEEK_AND_READ
;
2359 ReadFileInfo
.FilePosition
= *FilePosition
;
2360 ReadFileInfo
.FileData
= Buffer
;
2361 ReadFileInfo
.FileDataSize
= *BufferSize
;
2362 ReadFileInfo
.FileSize
= FileSize
;
2368 &File
->FileIdentifierDesc
->Icb
,
2372 if (EFI_ERROR (Status
)) {
2376 *BufferSize
= ReadFileInfo
.FileDataSize
;
2377 *FilePosition
= ReadFileInfo
.FilePosition
;
2383 Check if ControllerHandle supports an UDF file system.
2385 @param[in] This Protocol instance pointer.
2386 @param[in] ControllerHandle Handle of device to test.
2388 @retval EFI_SUCCESS UDF file system found.
2389 @retval EFI_UNSUPPORTED UDF file system not found.
2393 SupportUdfFileSystem (
2394 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2395 IN EFI_HANDLE ControllerHandle
2399 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2400 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2401 EFI_DEVICE_PATH_PROTOCOL
*LastDevicePathNode
;
2402 EFI_GUID
*VendorDefinedGuid
;
2403 EFI_GUID UdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
2406 // Open Device Path protocol on ControllerHandle
2408 Status
= gBS
->OpenProtocol (
2410 &gEfiDevicePathProtocolGuid
,
2411 (VOID
**)&DevicePath
,
2412 This
->DriverBindingHandle
,
2414 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2416 if (EFI_ERROR (Status
)) {
2417 return EFI_UNSUPPORTED
;
2420 Status
= EFI_UNSUPPORTED
;
2423 // Get last Device Path node
2425 LastDevicePathNode
= NULL
;
2426 DevicePathNode
= DevicePath
;
2427 while (!IsDevicePathEnd (DevicePathNode
)) {
2428 LastDevicePathNode
= DevicePathNode
;
2429 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
2432 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2433 // of an UDF file system.
2435 if (LastDevicePathNode
!= NULL
&&
2436 DevicePathType (LastDevicePathNode
) == MEDIA_DEVICE_PATH
&&
2437 DevicePathSubType (LastDevicePathNode
) == MEDIA_VENDOR_DP
) {
2438 VendorDefinedGuid
= (EFI_GUID
*)((UINTN
)LastDevicePathNode
+
2439 OFFSET_OF (VENDOR_DEVICE_PATH
, Guid
));
2440 if (CompareGuid (VendorDefinedGuid
, &UdfDevPathGuid
)) {
2441 Status
= EFI_SUCCESS
;
2446 // Close Device Path protocol on ControllerHandle
2448 gBS
->CloseProtocol (
2450 &gEfiDevicePathProtocolGuid
,
2451 This
->DriverBindingHandle
,