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 ASSERT (PartitionDesc
!= NULL
);
302 return (UINT64
)PartitionDesc
->PartitionStartingLocation
+
303 ShortAd
->ExtentPosition
;
307 // Find File Set Descriptor of a given Logical Volume Descriptor.
309 // The found FSD will contain the extent (LogicalVolumeContentsUse) where our
310 // root directory is.
313 FindFileSetDescriptor (
314 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
315 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
316 IN UDF_VOLUME_INFO
*Volume
,
317 IN UINTN LogicalVolDescNum
,
318 OUT UDF_FILE_SET_DESCRIPTOR
*FileSetDesc
323 UDF_LOGICAL_VOLUME_DESCRIPTOR
*LogicalVolDesc
;
325 LogicalVolDesc
= Volume
->LogicalVolDescs
[LogicalVolDescNum
];
326 Lsn
= GetLongAdLsn (Volume
, &LogicalVolDesc
->LogicalVolumeContentsUse
);
329 // Read extent (Long Ad).
331 Status
= DiskIo
->ReadDisk (
333 BlockIo
->Media
->MediaId
,
334 MultU64x32 (Lsn
, LogicalVolDesc
->LogicalBlockSize
),
335 sizeof (UDF_FILE_SET_DESCRIPTOR
),
338 if (EFI_ERROR (Status
)) {
343 // Check if the read extent contains a valid FSD's tag identifier.
345 if (!IS_FSD (FileSetDesc
)) {
346 return EFI_VOLUME_CORRUPTED
;
353 // Get all File Set Descriptors for each Logical Volume Descriptor.
356 GetFileSetDescriptors (
357 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
358 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
359 IN OUT UDF_VOLUME_INFO
*Volume
364 UDF_FILE_SET_DESCRIPTOR
*FileSetDesc
;
367 Volume
->FileSetDescs
=
368 (UDF_FILE_SET_DESCRIPTOR
**)AllocateZeroPool (
369 Volume
->LogicalVolDescsNo
* sizeof (UDF_FILE_SET_DESCRIPTOR
));
370 if (Volume
->FileSetDescs
== NULL
) {
371 return EFI_OUT_OF_RESOURCES
;
374 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
375 FileSetDesc
= AllocateZeroPool (sizeof (UDF_FILE_SET_DESCRIPTOR
));
376 if (FileSetDesc
== NULL
) {
377 Status
= EFI_OUT_OF_RESOURCES
;
378 goto Error_Alloc_Fsd
;
382 // Find a FSD for this LVD.
384 Status
= FindFileSetDescriptor (
391 if (EFI_ERROR (Status
)) {
398 Volume
->FileSetDescs
[Index
] = FileSetDesc
;
401 Volume
->FileSetDescsNo
= Volume
->LogicalVolDescsNo
;
406 for (Index
= 0; Index
< Count
; Index
++) {
407 FreePool ((VOID
*)Volume
->FileSetDescs
[Index
]);
410 FreePool ((VOID
*)Volume
->FileSetDescs
);
411 Volume
->FileSetDescs
= NULL
;
418 // Read Volume and File Structure on an UDF file system.
421 ReadVolumeFileStructure (
422 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
423 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
424 OUT UDF_VOLUME_INFO
*Volume
428 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint
;
433 Status
= FindAnchorVolumeDescriptorPointer (
438 if (EFI_ERROR (Status
)) {
443 // AVDP has been found. Start MVDS.
445 Status
= StartMainVolumeDescriptorSequence (
451 if (EFI_ERROR (Status
)) {
459 // Calculate length of a given File Identifier Descriptor.
462 GetFidDescriptorLength (
463 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
467 (INTN
)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR
, Data
[0]) + 3 +
468 FileIdentifierDesc
->LengthOfFileIdentifier
+
469 FileIdentifierDesc
->LengthOfImplementationUse
) >> 2) << 2
474 // Duplicate a given File Identifier Descriptor.
478 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
479 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**NewFileIdentifierDesc
482 *NewFileIdentifierDesc
=
483 (UDF_FILE_IDENTIFIER_DESCRIPTOR
*)AllocateCopyPool (
484 (UINTN
) GetFidDescriptorLength (FileIdentifierDesc
), FileIdentifierDesc
);
486 ASSERT (*NewFileIdentifierDesc
!= NULL
);
490 // Duplicate either a given File Entry or a given Extended File Entry.
494 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
495 IN UDF_VOLUME_INFO
*Volume
,
497 OUT VOID
**NewFileEntry
500 *NewFileEntry
= AllocateCopyPool (Volume
->FileEntrySize
, FileEntry
);
502 ASSERT (*NewFileEntry
!= NULL
);
506 // Get raw data + length of a given File Entry or Extended File Entry.
508 // The file's recorded data can contain either real file content (inline) or
509 // a sequence of extents (or Allocation Descriptors) which tells where file's
510 // content is stored in.
512 // NOTE: The FE/EFE can be thought it was an inode.
516 IN VOID
*FileEntryData
,
521 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
522 UDF_FILE_ENTRY
*FileEntry
;
524 if (IS_EFE (FileEntryData
)) {
525 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
527 *Length
= ExtendedFileEntry
->InformationLength
;
528 *Data
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
529 ExtendedFileEntry
->LengthOfExtendedAttributes
);
530 } else if (IS_FE (FileEntryData
)) {
531 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
533 *Length
= FileEntry
->InformationLength
;
534 *Data
= (VOID
*)((UINT8
*)FileEntry
->Data
+
535 FileEntry
->LengthOfExtendedAttributes
);
540 // Get Allocation Descriptors' data information from a given FE/EFE.
544 IN VOID
*FileEntryData
,
549 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
550 UDF_FILE_ENTRY
*FileEntry
;
552 if (IS_EFE (FileEntryData
)) {
553 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)FileEntryData
;
555 *Length
= ExtendedFileEntry
->LengthOfAllocationDescriptors
;
556 *AdsData
= (VOID
*)((UINT8
*)ExtendedFileEntry
->Data
+
557 ExtendedFileEntry
->LengthOfExtendedAttributes
);
558 } else if (IS_FE (FileEntryData
)) {
559 FileEntry
= (UDF_FILE_ENTRY
*)FileEntryData
;
561 *Length
= FileEntry
->LengthOfAllocationDescriptors
;
562 *AdsData
= (VOID
*)((UINT8
*)FileEntry
->Data
+
563 FileEntry
->LengthOfExtendedAttributes
);
568 // Read next Long Allocation Descriptor from a given file's data.
573 IN OUT UINT64
*Offset
,
575 OUT UDF_LONG_ALLOCATION_DESCRIPTOR
**FoundLongAd
578 UDF_LONG_ALLOCATION_DESCRIPTOR
*LongAd
;
579 UDF_EXTENT_FLAGS ExtentFlags
;
582 if (*Offset
>= Length
) {
584 // No more Long Allocation Descriptors.
586 return EFI_DEVICE_ERROR
;
590 (UDF_LONG_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
593 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
594 // allocated AD, then return it.
596 ExtentFlags
= GET_EXTENT_FLAGS (LONG_ADS_SEQUENCE
, LongAd
);
597 if (ExtentFlags
== EXTENT_IS_NEXT_EXTENT
||
598 ExtentFlags
== EXTENT_RECORDED_AND_ALLOCATED
) {
603 // This AD is either not recorded but allocated, or not recorded and not
604 // allocated. Skip it.
606 *Offset
+= AD_LENGTH (LONG_ADS_SEQUENCE
);
609 *FoundLongAd
= LongAd
;
615 // Read next Short Allocation Descriptor from a given file's data.
620 IN OUT UINT64
*Offset
,
622 OUT UDF_SHORT_ALLOCATION_DESCRIPTOR
**FoundShortAd
625 UDF_SHORT_ALLOCATION_DESCRIPTOR
*ShortAd
;
626 UDF_EXTENT_FLAGS ExtentFlags
;
629 if (*Offset
>= Length
) {
631 // No more Short Allocation Descriptors.
633 return EFI_DEVICE_ERROR
;
637 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)((UINT8
*)Data
+ *Offset
);
640 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
641 // allocated AD, then return it.
643 ExtentFlags
= GET_EXTENT_FLAGS (SHORT_ADS_SEQUENCE
, ShortAd
);
644 if (ExtentFlags
== EXTENT_IS_NEXT_EXTENT
||
645 ExtentFlags
== EXTENT_RECORDED_AND_ALLOCATED
) {
650 // This AD is either not recorded but allocated, or not recorded and not
651 // allocated. Skip it.
653 *Offset
+= AD_LENGTH (SHORT_ADS_SEQUENCE
);
656 *FoundShortAd
= ShortAd
;
662 // Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
666 GetAllocationDescriptor (
667 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
669 IN OUT UINT64
*Offset
,
674 if (RecordingFlags
== LONG_ADS_SEQUENCE
) {
675 return GetLongAdFromAds (
679 (UDF_LONG_ALLOCATION_DESCRIPTOR
**)FoundAd
681 } else if (RecordingFlags
== SHORT_ADS_SEQUENCE
) {
682 return GetShortAdFromAds (
686 (UDF_SHORT_ALLOCATION_DESCRIPTOR
**)FoundAd
690 return EFI_DEVICE_ERROR
;
694 // Return logical sector number of either Short or Long Allocation Descriptor.
697 GetAllocationDescriptorLsn (
698 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
699 IN UDF_VOLUME_INFO
*Volume
,
700 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
704 if (RecordingFlags
== LONG_ADS_SEQUENCE
) {
705 return GetLongAdLsn (Volume
, (UDF_LONG_ALLOCATION_DESCRIPTOR
*)Ad
);
706 } else if (RecordingFlags
== SHORT_ADS_SEQUENCE
) {
707 return GetShortAdLsn (
708 GetPdFromLongAd (Volume
, ParentIcb
),
709 (UDF_SHORT_ALLOCATION_DESCRIPTOR
*)Ad
717 // Return offset + length of a given indirect Allocation Descriptor (AED).
721 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
722 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
723 IN UDF_VOLUME_INFO
*Volume
,
724 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
725 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
735 UINT32 LogicalBlockSize
;
736 UDF_ALLOCATION_EXTENT_DESCRIPTOR
*AllocExtDesc
;
738 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
739 Lsn
= GetAllocationDescriptorLsn (RecordingFlags
,
744 Data
= AllocatePool (ExtentLength
);
746 return EFI_OUT_OF_RESOURCES
;
749 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
754 Status
= DiskIo
->ReadDisk (
756 BlockIo
->Media
->MediaId
,
757 MultU64x32 (Lsn
, LogicalBlockSize
),
761 if (EFI_ERROR (Status
)) {
766 // Check if read extent contains a valid tag identifier for AED.
768 AllocExtDesc
= (UDF_ALLOCATION_EXTENT_DESCRIPTOR
*)Data
;
769 if (!IS_AED (AllocExtDesc
)) {
770 Status
= EFI_VOLUME_CORRUPTED
;
775 // Get AED's block offset and its length.
777 *Offset
= MultU64x32 (Lsn
, LogicalBlockSize
) +
778 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR
);
779 *Length
= AllocExtDesc
->LengthOfAllocationDescriptors
;
788 // Read Allocation Extent Descriptor into memory.
792 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
793 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
794 IN UDF_VOLUME_INFO
*Volume
,
795 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
796 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
806 // Get AED's offset + length.
808 Status
= GetAedAdsOffset (
818 if (EFI_ERROR (Status
)) {
823 // Allocate buffer to read in AED's data.
825 *Data
= AllocatePool ((UINTN
) (*Length
));
827 return EFI_OUT_OF_RESOURCES
;
830 return DiskIo
->ReadDisk (
832 BlockIo
->Media
->MediaId
,
840 // Function used to serialise reads of Allocation Descriptors.
843 GrowUpBufferToNextAd (
844 IN UDF_FE_RECORDING_FLAGS RecordingFlags
,
846 IN OUT VOID
**Buffer
,
852 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
854 if (*Buffer
== NULL
) {
855 *Buffer
= AllocatePool (ExtentLength
);
856 if (*Buffer
== NULL
) {
857 return EFI_OUT_OF_RESOURCES
;
860 *Buffer
= ReallocatePool ((UINTN
) Length
, (UINTN
) (Length
+ ExtentLength
), *Buffer
);
861 if (*Buffer
== NULL
) {
862 return EFI_OUT_OF_RESOURCES
;
870 // Read data or size of either a File Entry or an Extended File Entry.
874 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
875 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
876 IN UDF_VOLUME_INFO
*Volume
,
877 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
878 IN VOID
*FileEntryData
,
879 IN OUT UDF_READ_FILE_INFO
*ReadFileInfo
883 UINT32 LogicalBlockSize
;
895 BOOLEAN FinishedSeeking
;
897 UDF_FE_RECORDING_FLAGS RecordingFlags
;
899 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
903 // set BytesLeft to suppress incorrect compiler/analyzer warnings
908 FinishedSeeking
= FALSE
;
911 switch (ReadFileInfo
->Flags
) {
912 case READ_FILE_GET_FILESIZE
:
913 case READ_FILE_ALLOCATE_AND_READ
:
915 // Initialise ReadFileInfo structure for either getting file size, or
916 // reading file's recorded data.
918 ReadFileInfo
->ReadLength
= 0;
919 ReadFileInfo
->FileData
= NULL
;
921 case READ_FILE_SEEK_AND_READ
:
923 // About to seek a file and/or read its data.
925 Length
= ReadFileInfo
->FileSize
- ReadFileInfo
->FilePosition
;
926 if (ReadFileInfo
->FileDataSize
> Length
) {
928 // About to read beyond the EOF -- truncate it.
930 ReadFileInfo
->FileDataSize
= Length
;
934 // Initialise data to start seeking and/or reading a file.
936 BytesLeft
= ReadFileInfo
->FileDataSize
;
939 FinishedSeeking
= FALSE
;
944 RecordingFlags
= GET_FE_RECORDING_FLAGS (FileEntryData
);
945 switch (RecordingFlags
) {
948 // There are no extents for this FE/EFE. All data is inline.
950 GetFileEntryData (FileEntryData
, &Data
, &Length
);
952 if (ReadFileInfo
->Flags
== READ_FILE_GET_FILESIZE
) {
953 ReadFileInfo
->ReadLength
= Length
;
954 } else if (ReadFileInfo
->Flags
== READ_FILE_ALLOCATE_AND_READ
) {
956 // Allocate buffer for starting read data.
958 ReadFileInfo
->FileData
= AllocatePool ((UINTN
) Length
);
959 if (ReadFileInfo
->FileData
== NULL
) {
960 return EFI_OUT_OF_RESOURCES
;
964 // Read all inline data into ReadFileInfo->FileData
966 CopyMem (ReadFileInfo
->FileData
, Data
, (UINTN
) Length
);
967 ReadFileInfo
->ReadLength
= Length
;
968 } else if (ReadFileInfo
->Flags
== READ_FILE_SEEK_AND_READ
) {
970 // If FilePosition is non-zero, seek file to FilePosition, read
971 // FileDataSize bytes and then updates FilePosition.
974 ReadFileInfo
->FileData
,
975 (VOID
*)((UINT8
*)Data
+ ReadFileInfo
->FilePosition
),
976 (UINTN
) ReadFileInfo
->FileDataSize
979 ReadFileInfo
->FilePosition
+= ReadFileInfo
->FileDataSize
;
982 return EFI_INVALID_PARAMETER
;
985 Status
= EFI_SUCCESS
;
988 case LONG_ADS_SEQUENCE
:
989 case SHORT_ADS_SEQUENCE
:
991 // This FE/EFE contains a run of Allocation Descriptors. Get data + size
992 // for start reading them out.
994 GetAdsInformation (FileEntryData
, &Data
, &Length
);
1001 Status
= GetAllocationDescriptor (
1008 if (Status
== EFI_DEVICE_ERROR
) {
1009 Status
= EFI_SUCCESS
;
1014 // Check if AD is an indirect AD. If so, read Allocation Extent
1015 // Descriptor and its extents (ADs).
1017 if (GET_EXTENT_FLAGS (RecordingFlags
, Ad
) == EXTENT_IS_NEXT_EXTENT
) {
1024 Status
= GetAedAdsData (
1034 if (EFI_ERROR (Status
)) {
1037 ASSERT (Data
!= NULL
);
1043 ExtentLength
= GET_EXTENT_LENGTH (RecordingFlags
, Ad
);
1045 Lsn
= GetAllocationDescriptorLsn (RecordingFlags
,
1050 switch (ReadFileInfo
->Flags
) {
1051 case READ_FILE_GET_FILESIZE
:
1052 ReadFileInfo
->ReadLength
+= ExtentLength
;
1054 case READ_FILE_ALLOCATE_AND_READ
:
1056 // Increase FileData (if necessary) to read next extent.
1058 Status
= GrowUpBufferToNextAd (
1061 &ReadFileInfo
->FileData
,
1062 ReadFileInfo
->ReadLength
1064 if (EFI_ERROR (Status
)) {
1065 goto Error_Alloc_Buffer_To_Next_Ad
;
1069 // Read extent's data into FileData.
1071 Status
= DiskIo
->ReadDisk (
1073 BlockIo
->Media
->MediaId
,
1074 MultU64x32 (Lsn
, LogicalBlockSize
),
1076 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1077 ReadFileInfo
->ReadLength
)
1079 if (EFI_ERROR (Status
)) {
1080 goto Error_Read_Disk_Blk
;
1083 ReadFileInfo
->ReadLength
+= ExtentLength
;
1085 case READ_FILE_SEEK_AND_READ
:
1087 // Seek file first before reading in its data.
1089 if (FinishedSeeking
) {
1091 goto Skip_File_Seek
;
1094 if (FilePosition
+ ExtentLength
< ReadFileInfo
->FilePosition
) {
1095 FilePosition
+= ExtentLength
;
1099 if (FilePosition
+ ExtentLength
> ReadFileInfo
->FilePosition
) {
1100 Offset
= ReadFileInfo
->FilePosition
- FilePosition
;
1106 // Done with seeking file. Start reading its data.
1108 FinishedSeeking
= TRUE
;
1112 // Make sure we don't read more data than really wanted.
1114 if (ExtentLength
- Offset
> BytesLeft
) {
1115 DataLength
= BytesLeft
;
1117 DataLength
= ExtentLength
- Offset
;
1121 // Read extent's data into FileData.
1123 Status
= DiskIo
->ReadDisk (
1125 BlockIo
->Media
->MediaId
,
1126 Offset
+ MultU64x32 (Lsn
, LogicalBlockSize
),
1128 (VOID
*)((UINT8
*)ReadFileInfo
->FileData
+
1131 if (EFI_ERROR (Status
)) {
1132 goto Error_Read_Disk_Blk
;
1136 // Update current file's position.
1138 DataOffset
+= DataLength
;
1139 ReadFileInfo
->FilePosition
+= DataLength
;
1141 BytesLeft
-= DataLength
;
1142 if (BytesLeft
== 0) {
1144 // There is no more file data to read.
1146 Status
= EFI_SUCCESS
;
1155 // Point to the next AD (extent).
1157 AdOffset
+= AD_LENGTH (RecordingFlags
);
1161 case EXTENDED_ADS_SEQUENCE
:
1162 // FIXME: Not supported. Got no volume with it, yet.
1164 Status
= EFI_UNSUPPORTED
;
1169 // A flag value reserved by the ECMA-167 standard (3rd Edition - June
1170 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
1172 Status
= EFI_UNSUPPORTED
;
1183 Error_Read_Disk_Blk
:
1184 Error_Alloc_Buffer_To_Next_Ad
:
1185 if (ReadFileInfo
->Flags
!= READ_FILE_SEEK_AND_READ
) {
1186 FreePool (ReadFileInfo
->FileData
);
1198 // Find a file by its filename from a given Parent file.
1202 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1203 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1204 IN UDF_VOLUME_INFO
*Volume
,
1205 IN CHAR16
*FileName
,
1206 IN UDF_FILE_INFO
*Parent
,
1207 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1208 OUT UDF_FILE_INFO
*File
1212 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1213 UDF_READ_DIRECTORY_INFO ReadDirInfo
;
1215 CHAR16 FoundFileName
[UDF_FILENAME_LENGTH
];
1216 VOID
*CompareFileEntry
;
1219 // Check if both Parent->FileIdentifierDesc and Icb are NULL.
1221 if ((Parent
->FileIdentifierDesc
== NULL
) && (Icb
== NULL
)) {
1222 return EFI_INVALID_PARAMETER
;
1226 // Check if parent file is really directory.
1228 if (!IS_FE_DIRECTORY (Parent
->FileEntry
)) {
1229 return EFI_NOT_FOUND
;
1233 // If FileName is current file or working directory, just duplicate Parent's
1234 // FE/EFE and FID descriptors.
1236 if (StrCmp (FileName
, L
".") == 0) {
1237 if (Parent
->FileIdentifierDesc
== NULL
) {
1238 return EFI_INVALID_PARAMETER
;
1241 DuplicateFe (BlockIo
, Volume
, Parent
->FileEntry
, &File
->FileEntry
);
1242 DuplicateFid (Parent
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1248 // Start directory listing.
1250 ZeroMem ((VOID
*)&ReadDirInfo
, sizeof (UDF_READ_DIRECTORY_INFO
));
1254 Status
= ReadDirectoryEntry (
1258 (Parent
->FileIdentifierDesc
!= NULL
) ?
1259 &Parent
->FileIdentifierDesc
->Icb
:
1265 if (EFI_ERROR (Status
)) {
1266 if (Status
== EFI_DEVICE_ERROR
) {
1267 Status
= EFI_NOT_FOUND
;
1273 if (IS_FID_PARENT_FILE (FileIdentifierDesc
)) {
1275 // This FID contains the location (FE/EFE) of the parent directory of this
1276 // directory (Parent), and if FileName is either ".." or "\\", then it's
1277 // the expected FID.
1279 if (StrCmp (FileName
, L
"..") == 0 || StrCmp (FileName
, L
"\\") == 0) {
1284 Status
= GetFileNameFromFid (FileIdentifierDesc
, FoundFileName
);
1285 if (EFI_ERROR (Status
)) {
1289 if (StrCmp (FileName
, FoundFileName
) == 0) {
1291 // FID has been found. Prepare to find its respective FE/EFE.
1298 FreePool ((VOID
*)FileIdentifierDesc
);
1301 if (ReadDirInfo
.DirectoryData
!= NULL
) {
1303 // Free all allocated resources for the directory listing.
1305 FreePool (ReadDirInfo
.DirectoryData
);
1309 Status
= EFI_SUCCESS
;
1311 File
->FileIdentifierDesc
= FileIdentifierDesc
;
1314 // If the requested file is root directory, then the FE/EFE was already
1315 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1317 // Otherwise, find FE/EFE from the respective FID.
1319 if (StrCmp (FileName
, L
"\\") != 0) {
1320 Status
= FindFileEntry (
1324 &FileIdentifierDesc
->Icb
,
1327 if (EFI_ERROR (Status
)) {
1332 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1334 if (CompareMem ((VOID
*)Parent
->FileEntry
, (VOID
*)CompareFileEntry
,
1335 Volume
->FileEntrySize
) != 0) {
1336 File
->FileEntry
= CompareFileEntry
;
1338 FreePool ((VOID
*)FileIdentifierDesc
);
1339 FreePool ((VOID
*)CompareFileEntry
);
1340 Status
= EFI_NOT_FOUND
;
1348 FreePool ((VOID
*)FileIdentifierDesc
);
1354 Read volume information on a medium which contains a valid UDF file system.
1356 @param[in] BlockIo BlockIo interface.
1357 @param[in] DiskIo DiskIo interface.
1358 @param[out] Volume UDF volume information structure.
1360 @retval EFI_SUCCESS Volume information read.
1361 @retval EFI_NO_MEDIA The device has no media.
1362 @retval EFI_DEVICE_ERROR The device reported an error.
1363 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1364 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1368 ReadUdfVolumeInformation (
1369 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1370 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1371 OUT UDF_VOLUME_INFO
*Volume
1376 Status
= ReadVolumeFileStructure (
1381 if (EFI_ERROR (Status
)) {
1385 Status
= GetFileSetDescriptors (
1390 if (EFI_ERROR (Status
)) {
1391 CleanupVolumeInformation (Volume
);
1398 Find the root directory on an UDF volume.
1400 @param[in] BlockIo BlockIo interface.
1401 @param[in] DiskIo DiskIo interface.
1402 @param[in] Volume UDF volume information structure.
1403 @param[out] File Root directory file.
1405 @retval EFI_SUCCESS Root directory found.
1406 @retval EFI_NO_MEDIA The device has no media.
1407 @retval EFI_DEVICE_ERROR The device reported an error.
1408 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1409 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1415 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1416 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1417 IN UDF_VOLUME_INFO
*Volume
,
1418 OUT UDF_FILE_INFO
*File
1422 UDF_FILE_INFO Parent
;
1424 Status
= FindFileEntry (
1428 &Volume
->FileSetDescs
[0]->RootDirectoryIcb
,
1431 if (EFI_ERROR (Status
)) {
1435 Parent
.FileEntry
= File
->FileEntry
;
1436 Parent
.FileIdentifierDesc
= NULL
;
1445 &Volume
->FileSetDescs
[0]->RootDirectoryIcb
,
1448 if (EFI_ERROR (Status
)) {
1449 FreePool (File
->FileEntry
);
1456 Find either a File Entry or a Extended File Entry from a given ICB.
1458 @param[in] BlockIo BlockIo interface.
1459 @param[in] DiskIo DiskIo interface.
1460 @param[in] Volume UDF volume information structure.
1461 @param[in] Icb ICB of the FID.
1462 @param[out] FileEntry File Entry or Extended File Entry.
1464 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1465 @retval EFI_NO_MEDIA The device has no media.
1466 @retval EFI_DEVICE_ERROR The device reported an error.
1467 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1468 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1474 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1475 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1476 IN UDF_VOLUME_INFO
*Volume
,
1477 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1478 OUT VOID
**FileEntry
1483 UINT32 LogicalBlockSize
;
1485 Lsn
= GetLongAdLsn (Volume
, Icb
);
1486 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, UDF_DEFAULT_LV_NUM
);
1488 *FileEntry
= AllocateZeroPool (Volume
->FileEntrySize
);
1489 if (*FileEntry
== NULL
) {
1490 return EFI_OUT_OF_RESOURCES
;
1496 Status
= DiskIo
->ReadDisk (
1498 BlockIo
->Media
->MediaId
,
1499 MultU64x32 (Lsn
, LogicalBlockSize
),
1500 Volume
->FileEntrySize
,
1503 if (EFI_ERROR (Status
)) {
1504 goto Error_Read_Disk_Blk
;
1508 // Check if the read extent contains a valid Tag Identifier for the expected
1511 if (!IS_FE (*FileEntry
) && !IS_EFE (*FileEntry
)) {
1512 Status
= EFI_VOLUME_CORRUPTED
;
1513 goto Error_Invalid_Fe
;
1519 Error_Read_Disk_Blk
:
1520 FreePool (*FileEntry
);
1526 Find a file given its absolute path on an UDF volume.
1528 @param[in] BlockIo BlockIo interface.
1529 @param[in] DiskIo DiskIo interface.
1530 @param[in] Volume UDF volume information structure.
1531 @param[in] FilePath File's absolute path.
1532 @param[in] Root Root directory file.
1533 @param[in] Parent Parent directory file.
1534 @param[out] File Found file.
1536 @retval EFI_SUCCESS @p FilePath was found.
1537 @retval EFI_NO_MEDIA The device has no media.
1538 @retval EFI_DEVICE_ERROR The device reported an error.
1539 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1540 @retval EFI_OUT_OF_RESOURCES The @p FilePath file was not found due to lack of
1546 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1547 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1548 IN UDF_VOLUME_INFO
*Volume
,
1549 IN CHAR16
*FilePath
,
1550 IN UDF_FILE_INFO
*Root
,
1551 IN UDF_FILE_INFO
*Parent
,
1552 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*Icb
,
1553 OUT UDF_FILE_INFO
*File
1557 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1558 CHAR16
*FileNamePointer
;
1559 UDF_FILE_INFO PreviousFile
;
1562 Status
= EFI_NOT_FOUND
;
1564 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1565 while (*FilePath
!= L
'\0') {
1566 FileNamePointer
= FileName
;
1567 while (*FilePath
!= L
'\0' && *FilePath
!= L
'\\') {
1568 *FileNamePointer
++ = *FilePath
++;
1571 *FileNamePointer
= L
'\0';
1572 if (FileName
[0] == L
'\0') {
1574 // Open root directory.
1578 // There is no file found for the root directory yet. So, find only its
1581 // See UdfOpenVolume() function.
1583 Status
= InternalFindFile (BlockIo
,
1592 // We've already a file pointer (Root) for the root directory. Duplicate
1593 // its FE/EFE and FID descriptors.
1595 DuplicateFe (BlockIo
, Volume
, Root
->FileEntry
, &File
->FileEntry
);
1596 DuplicateFid (Root
->FileIdentifierDesc
, &File
->FileIdentifierDesc
);
1597 Status
= EFI_SUCCESS
;
1601 // No root directory. Find filename from the current directory.
1603 Status
= InternalFindFile (BlockIo
,
1612 if (EFI_ERROR (Status
)) {
1617 // If the found file is a symlink, then find its respective FE/EFE and
1620 if (IS_FE_SYMLINK (File
->FileEntry
)) {
1621 FreePool ((VOID
*)File
->FileIdentifierDesc
);
1623 FileEntry
= File
->FileEntry
;
1625 Status
= ResolveSymlink (BlockIo
,
1632 FreePool (FileEntry
);
1634 if (EFI_ERROR (Status
)) {
1639 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1640 sizeof (UDF_FILE_INFO
)) != 0) {
1641 CleanupFileInformation (&PreviousFile
);
1644 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1645 if (*FilePath
!= L
'\0' && *FilePath
== L
'\\') {
1654 Read a directory entry at a time on an UDF volume.
1656 @param[in] BlockIo BlockIo interface.
1657 @param[in] DiskIo DiskIo interface.
1658 @param[in] Volume UDF volume information structure.
1659 @param[in] ParentIcb ICB of the parent file.
1660 @param[in] FileEntryData FE/EFE of the parent file.
1661 @param[in out] ReadDirInfo Next read directory listing structure
1663 @param[out] FoundFid File Identifier Descriptor pointer.
1665 @retval EFI_SUCCESS Directory entry read.
1666 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1667 @retval EFI_NO_MEDIA The device has no media.
1668 @retval EFI_DEVICE_ERROR The device reported an error.
1669 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1670 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1675 ReadDirectoryEntry (
1676 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1677 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1678 IN UDF_VOLUME_INFO
*Volume
,
1679 IN UDF_LONG_ALLOCATION_DESCRIPTOR
*ParentIcb
,
1680 IN VOID
*FileEntryData
,
1681 IN OUT UDF_READ_DIRECTORY_INFO
*ReadDirInfo
,
1682 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR
**FoundFid
1686 UDF_READ_FILE_INFO ReadFileInfo
;
1687 UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
;
1689 if (ReadDirInfo
->DirectoryData
== NULL
) {
1691 // The directory's recorded data has not been read yet. So let's cache it
1692 // into memory and the next calls won't need to read it again.
1694 ReadFileInfo
.Flags
= READ_FILE_ALLOCATE_AND_READ
;
1704 if (EFI_ERROR (Status
)) {
1709 // Fill in ReadDirInfo structure with the read directory's data information.
1711 ReadDirInfo
->DirectoryData
= ReadFileInfo
.FileData
;
1712 ReadDirInfo
->DirectoryLength
= ReadFileInfo
.ReadLength
;
1716 if (ReadDirInfo
->FidOffset
>= ReadDirInfo
->DirectoryLength
) {
1718 // There are no longer FIDs for this directory. By returning
1719 // EFI_DEVICE_ERROR to the callee will indicate end of directory
1722 return EFI_DEVICE_ERROR
;
1726 // Get FID for this entry.
1728 FileIdentifierDesc
= GET_FID_FROM_ADS (ReadDirInfo
->DirectoryData
,
1729 ReadDirInfo
->FidOffset
);
1731 // Update FidOffset to point to next FID.
1733 ReadDirInfo
->FidOffset
+= GetFidDescriptorLength (FileIdentifierDesc
);
1734 } while (IS_FID_DELETED_FILE (FileIdentifierDesc
));
1736 DuplicateFid (FileIdentifierDesc
, FoundFid
);
1742 Get a filename (encoded in OSTA-compressed format) from a File Identifier
1743 Descriptor on an UDF volume.
1745 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
1746 @param[out] FileName Decoded filename.
1748 @retval EFI_SUCCESS Filename decoded and read.
1749 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1752 GetFileNameFromFid (
1753 IN UDF_FILE_IDENTIFIER_DESCRIPTOR
*FileIdentifierDesc
,
1754 OUT CHAR16
*FileName
1757 UINT8
*OstaCompressed
;
1758 UINT8 CompressionId
;
1764 (UINT8
*)FileIdentifierDesc
->Data
+
1765 FileIdentifierDesc
->LengthOfImplementationUse
1768 CompressionId
= OstaCompressed
[0];
1769 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
1770 return EFI_VOLUME_CORRUPTED
;
1776 Length
= FileIdentifierDesc
->LengthOfFileIdentifier
;
1777 for (Index
= 1; Index
< Length
; Index
++) {
1778 if (CompressionId
== 16) {
1779 *FileName
= OstaCompressed
[Index
++] << 8;
1784 if (Index
< Length
) {
1785 *FileName
|= (CHAR16
)(OstaCompressed
[Index
]);
1797 Resolve a symlink file on an UDF volume.
1799 @param[in] BlockIo BlockIo interface.
1800 @param[in] DiskIo DiskIo interface.
1801 @param[in] Volume UDF volume information structure.
1802 @param[in] Parent Parent file.
1803 @param[in] FileEntryData FE/EFE structure pointer.
1804 @param[out] File Resolved file.
1806 @retval EFI_SUCCESS Symlink file resolved.
1807 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1808 @retval EFI_NO_MEDIA The device has no media.
1809 @retval EFI_DEVICE_ERROR The device reported an error.
1810 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1811 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
1817 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
1818 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
1819 IN UDF_VOLUME_INFO
*Volume
,
1820 IN UDF_FILE_INFO
*Parent
,
1821 IN VOID
*FileEntryData
,
1822 OUT UDF_FILE_INFO
*File
1826 UDF_READ_FILE_INFO ReadFileInfo
;
1830 UDF_PATH_COMPONENT
*PathComp
;
1831 UINT8 PathCompLength
;
1832 CHAR16 FileName
[UDF_FILENAME_LENGTH
];
1835 UINT8 CompressionId
;
1836 UDF_FILE_INFO PreviousFile
;
1839 // Symlink files on UDF volumes do not contain so much data other than
1840 // Path Components which resolves to real filenames, so it's OK to read in
1841 // all its data here -- usually the data will be inline with the FE/EFE for
1844 ReadFileInfo
.Flags
= READ_FILE_ALLOCATE_AND_READ
;
1850 &Parent
->FileIdentifierDesc
->Icb
,
1854 if (EFI_ERROR (Status
)) {
1858 Length
= ReadFileInfo
.ReadLength
;
1860 Data
= (UINT8
*)ReadFileInfo
.FileData
;
1861 EndData
= Data
+ Length
;
1863 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
, sizeof (UDF_FILE_INFO
));
1866 PathComp
= (UDF_PATH_COMPONENT
*)Data
;
1868 PathCompLength
= PathComp
->LengthOfComponentIdentifier
;
1870 switch (PathComp
->ComponentType
) {
1873 // This Path Component specifies the root directory hierarchy subject to
1874 // agreement between the originator and recipient of the medium. Skip it.
1880 // "\\." of the current directory. Read next Path Component.
1882 goto Next_Path_Component
;
1885 // ".." (parent directory). Go to it.
1887 CopyMem ((VOID
*)FileName
, L
"..", 6);
1891 // "." (current file). Duplicate both FE/EFE and FID of this file.
1893 DuplicateFe (BlockIo
, Volume
, PreviousFile
.FileEntry
, &File
->FileEntry
);
1894 DuplicateFid (PreviousFile
.FileIdentifierDesc
,
1895 &File
->FileIdentifierDesc
);
1896 goto Next_Path_Component
;
1899 // This Path Component identifies an object, either a file or a
1900 // directory or an alias.
1902 // Decode it from the compressed data in ComponentIdentifier and find
1905 CompressionId
= PathComp
->ComponentIdentifier
[0];
1906 if (!IS_VALID_COMPRESSION_ID (CompressionId
)) {
1907 return EFI_VOLUME_CORRUPTED
;
1911 for (Index
= 1; Index
< PathCompLength
; Index
++) {
1912 if (CompressionId
== 16) {
1913 *C
= *(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+
1920 if (Index
< Length
) {
1921 *C
|= (CHAR16
)(*(UINT8
*)((UINT8
*)PathComp
->ComponentIdentifier
+ Index
));
1932 // Find file from the read filename in symlink's file data.
1934 Status
= InternalFindFile (
1943 if (EFI_ERROR (Status
)) {
1944 goto Error_Find_File
;
1947 Next_Path_Component
:
1948 Data
+= sizeof (UDF_PATH_COMPONENT
) + PathCompLength
;
1949 if (Data
>= EndData
) {
1953 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1954 sizeof (UDF_FILE_INFO
)) != 0) {
1955 CleanupFileInformation (&PreviousFile
);
1958 CopyMem ((VOID
*)&PreviousFile
, (VOID
*)File
, sizeof (UDF_FILE_INFO
));
1962 // Unmap the symlink file.
1964 FreePool (ReadFileInfo
.FileData
);
1969 if (CompareMem ((VOID
*)&PreviousFile
, (VOID
*)Parent
,
1970 sizeof (UDF_FILE_INFO
)) != 0) {
1971 CleanupFileInformation (&PreviousFile
);
1974 FreePool (ReadFileInfo
.FileData
);
1980 Clean up in-memory UDF volume information.
1982 @param[in] Volume Volume information pointer.
1986 CleanupVolumeInformation (
1987 IN UDF_VOLUME_INFO
*Volume
1992 if (Volume
->LogicalVolDescs
!= NULL
) {
1993 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
1994 FreePool ((VOID
*)Volume
->LogicalVolDescs
[Index
]);
1996 FreePool ((VOID
*)Volume
->LogicalVolDescs
);
1999 if (Volume
->PartitionDescs
!= NULL
) {
2000 for (Index
= 0; Index
< Volume
->PartitionDescsNo
; Index
++) {
2001 FreePool ((VOID
*)Volume
->PartitionDescs
[Index
]);
2003 FreePool ((VOID
*)Volume
->PartitionDescs
);
2006 if (Volume
->FileSetDescs
!= NULL
) {
2007 for (Index
= 0; Index
< Volume
->FileSetDescsNo
; Index
++) {
2008 FreePool ((VOID
*)Volume
->FileSetDescs
[Index
]);
2010 FreePool ((VOID
*)Volume
->FileSetDescs
);
2013 ZeroMem ((VOID
*)Volume
, sizeof (UDF_VOLUME_INFO
));
2017 Clean up in-memory UDF file information.
2019 @param[in] File File information pointer.
2023 CleanupFileInformation (
2024 IN UDF_FILE_INFO
*File
2027 if (File
->FileEntry
!= NULL
) {
2028 FreePool (File
->FileEntry
);
2030 if (File
->FileIdentifierDesc
!= NULL
) {
2031 FreePool ((VOID
*)File
->FileIdentifierDesc
);
2034 ZeroMem ((VOID
*)File
, sizeof (UDF_FILE_INFO
));
2038 Find a file from its absolute path on an UDF volume.
2040 @param[in] BlockIo BlockIo interface.
2041 @param[in] DiskIo DiskIo interface.
2042 @param[in] Volume UDF volume information structure.
2043 @param[in] File File information structure.
2044 @param[out] Size Size of the file.
2046 @retval EFI_SUCCESS File size calculated and set in @p Size.
2047 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2048 @retval EFI_NO_MEDIA The device has no media.
2049 @retval EFI_DEVICE_ERROR The device reported an error.
2050 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2051 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2057 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2058 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2059 IN UDF_VOLUME_INFO
*Volume
,
2060 IN UDF_FILE_INFO
*File
,
2065 UDF_READ_FILE_INFO ReadFileInfo
;
2067 ReadFileInfo
.Flags
= READ_FILE_GET_FILESIZE
;
2073 &File
->FileIdentifierDesc
->Icb
,
2077 if (EFI_ERROR (Status
)) {
2081 *Size
= ReadFileInfo
.ReadLength
;
2087 Set information about a file on an UDF volume.
2089 @param[in] File File pointer.
2090 @param[in] FileSize Size of the file.
2091 @param[in] FileName Filename of the file.
2092 @param[in out] BufferSize Size of the returned file infomation.
2093 @param[out] Buffer Data of the returned file information.
2095 @retval EFI_SUCCESS File information set.
2096 @retval EFI_NO_MEDIA The device has no media.
2097 @retval EFI_DEVICE_ERROR The device reported an error.
2098 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2099 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2105 IN UDF_FILE_INFO
*File
,
2107 IN CHAR16
*FileName
,
2108 IN OUT UINTN
*BufferSize
,
2112 UINTN FileInfoLength
;
2113 EFI_FILE_INFO
*FileInfo
;
2114 UDF_FILE_ENTRY
*FileEntry
;
2115 UDF_EXTENDED_FILE_ENTRY
*ExtendedFileEntry
;
2118 // Calculate the needed size for the EFI_FILE_INFO structure.
2120 FileInfoLength
= sizeof (EFI_FILE_INFO
) + ((FileName
!= NULL
) ?
2121 StrSize (FileName
) :
2123 if (*BufferSize
< FileInfoLength
) {
2125 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2127 *BufferSize
= FileInfoLength
;
2128 return EFI_BUFFER_TOO_SMALL
;
2132 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2133 // Now, fill it in with all necessary information about the file.
2135 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
2136 FileInfo
->Size
= FileInfoLength
;
2137 FileInfo
->Attribute
&= ~EFI_FILE_VALID_ATTR
;
2138 FileInfo
->Attribute
|= EFI_FILE_READ_ONLY
;
2140 if (IS_FID_DIRECTORY_FILE (File
->FileIdentifierDesc
)) {
2141 FileInfo
->Attribute
|= EFI_FILE_DIRECTORY
;
2142 } else if (IS_FID_NORMAL_FILE (File
->FileIdentifierDesc
)) {
2143 FileInfo
->Attribute
|= EFI_FILE_ARCHIVE
;
2146 if (IS_FID_HIDDEN_FILE (File
->FileIdentifierDesc
)) {
2147 FileInfo
->Attribute
|= EFI_FILE_HIDDEN
;
2150 if (IS_FE (File
->FileEntry
)) {
2151 FileEntry
= (UDF_FILE_ENTRY
*)File
->FileEntry
;
2154 // Check if FE has the system attribute set.
2156 if (FileEntry
->IcbTag
.Flags
& (1 << 10)) {
2157 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2160 FileInfo
->FileSize
= FileSize
;
2161 FileInfo
->PhysicalSize
= FileSize
;
2163 FileInfo
->CreateTime
.Year
= FileEntry
->AccessTime
.Year
;
2164 FileInfo
->CreateTime
.Month
= FileEntry
->AccessTime
.Month
;
2165 FileInfo
->CreateTime
.Day
= FileEntry
->AccessTime
.Day
;
2166 FileInfo
->CreateTime
.Hour
= FileEntry
->AccessTime
.Hour
;
2167 FileInfo
->CreateTime
.Minute
= FileEntry
->AccessTime
.Second
;
2168 FileInfo
->CreateTime
.Second
= FileEntry
->AccessTime
.Second
;
2169 FileInfo
->CreateTime
.Nanosecond
=
2170 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2172 FileInfo
->LastAccessTime
.Year
=
2173 FileEntry
->AccessTime
.Year
;
2174 FileInfo
->LastAccessTime
.Month
=
2175 FileEntry
->AccessTime
.Month
;
2176 FileInfo
->LastAccessTime
.Day
=
2177 FileEntry
->AccessTime
.Day
;
2178 FileInfo
->LastAccessTime
.Hour
=
2179 FileEntry
->AccessTime
.Hour
;
2180 FileInfo
->LastAccessTime
.Minute
=
2181 FileEntry
->AccessTime
.Minute
;
2182 FileInfo
->LastAccessTime
.Second
=
2183 FileEntry
->AccessTime
.Second
;
2184 FileInfo
->LastAccessTime
.Nanosecond
=
2185 FileEntry
->AccessTime
.HundredsOfMicroseconds
;
2186 } else if (IS_EFE (File
->FileEntry
)) {
2187 ExtendedFileEntry
= (UDF_EXTENDED_FILE_ENTRY
*)File
->FileEntry
;
2190 // Check if EFE has the system attribute set.
2192 if (ExtendedFileEntry
->IcbTag
.Flags
& (1 << 10)) {
2193 FileInfo
->Attribute
|= EFI_FILE_SYSTEM
;
2196 FileInfo
->FileSize
= FileSize
;
2197 FileInfo
->PhysicalSize
= FileSize
;
2199 FileInfo
->CreateTime
.Year
= ExtendedFileEntry
->CreationTime
.Year
;
2200 FileInfo
->CreateTime
.Month
= ExtendedFileEntry
->CreationTime
.Month
;
2201 FileInfo
->CreateTime
.Day
= ExtendedFileEntry
->CreationTime
.Day
;
2202 FileInfo
->CreateTime
.Hour
= ExtendedFileEntry
->CreationTime
.Hour
;
2203 FileInfo
->CreateTime
.Minute
= ExtendedFileEntry
->CreationTime
.Second
;
2204 FileInfo
->CreateTime
.Second
= ExtendedFileEntry
->CreationTime
.Second
;
2205 FileInfo
->CreateTime
.Nanosecond
=
2206 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2208 FileInfo
->LastAccessTime
.Year
=
2209 ExtendedFileEntry
->AccessTime
.Year
;
2210 FileInfo
->LastAccessTime
.Month
=
2211 ExtendedFileEntry
->AccessTime
.Month
;
2212 FileInfo
->LastAccessTime
.Day
=
2213 ExtendedFileEntry
->AccessTime
.Day
;
2214 FileInfo
->LastAccessTime
.Hour
=
2215 ExtendedFileEntry
->AccessTime
.Hour
;
2216 FileInfo
->LastAccessTime
.Minute
=
2217 ExtendedFileEntry
->AccessTime
.Minute
;
2218 FileInfo
->LastAccessTime
.Second
=
2219 ExtendedFileEntry
->AccessTime
.Second
;
2220 FileInfo
->LastAccessTime
.Nanosecond
=
2221 ExtendedFileEntry
->AccessTime
.HundredsOfMicroseconds
;
2224 FileInfo
->CreateTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2225 FileInfo
->CreateTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2226 FileInfo
->LastAccessTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
2227 FileInfo
->LastAccessTime
.Daylight
= EFI_TIME_ADJUST_DAYLIGHT
;
2229 CopyMem ((VOID
*)&FileInfo
->ModificationTime
,
2230 (VOID
*)&FileInfo
->LastAccessTime
,
2233 if (FileName
!= NULL
) {
2234 StrCpyS (FileInfo
->FileName
, StrLen (FileName
) + 1, FileName
);
2236 FileInfo
->FileName
[0] = '\0';
2239 *BufferSize
= FileInfoLength
;
2245 Get volume and free space size information of an UDF volume.
2247 @param[in] BlockIo BlockIo interface.
2248 @param[in] DiskIo DiskIo interface.
2249 @param[in] Volume UDF volume information structure.
2250 @param[out] VolumeSize Volume size.
2251 @param[out] FreeSpaceSize Free space size.
2253 @retval EFI_SUCCESS Volume and free space size calculated.
2254 @retval EFI_NO_MEDIA The device has no media.
2255 @retval EFI_DEVICE_ERROR The device reported an error.
2256 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2257 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
2258 calculated due to lack of resources.
2263 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2264 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2265 IN UDF_VOLUME_INFO
*Volume
,
2266 OUT UINT64
*VolumeSize
,
2267 OUT UINT64
*FreeSpaceSize
2270 UDF_EXTENT_AD ExtentAd
;
2271 UINT32 LogicalBlockSize
;
2274 UDF_LOGICAL_VOLUME_INTEGRITY
*LogicalVolInt
;
2282 for (Index
= 0; Index
< Volume
->LogicalVolDescsNo
; Index
++) {
2283 CopyMem ((VOID
*)&ExtentAd
,
2284 (VOID
*)&Volume
->LogicalVolDescs
[Index
]->IntegritySequenceExtent
,
2285 sizeof (UDF_EXTENT_AD
));
2286 if (ExtentAd
.ExtentLength
== 0) {
2290 LogicalBlockSize
= LV_BLOCK_SIZE (Volume
, Index
);
2293 LogicalVolInt
= (UDF_LOGICAL_VOLUME_INTEGRITY
*)
2294 AllocatePool (ExtentAd
.ExtentLength
);
2295 if (LogicalVolInt
== NULL
) {
2296 return EFI_OUT_OF_RESOURCES
;
2299 Lsn
= (UINT64
)ExtentAd
.ExtentLocation
;
2301 Status
= DiskIo
->ReadDisk (
2303 BlockIo
->Media
->MediaId
,
2304 MultU64x32 (Lsn
, LogicalBlockSize
),
2305 ExtentAd
.ExtentLength
,
2306 (VOID
*)LogicalVolInt
2308 if (EFI_ERROR (Status
)) {
2309 FreePool ((VOID
*)LogicalVolInt
);
2313 if (!IS_LVID (LogicalVolInt
)) {
2314 FreePool ((VOID
*)LogicalVolInt
);
2315 return EFI_VOLUME_CORRUPTED
;
2318 Length
= LogicalVolInt
->NumberOfPartitions
;
2319 for (Index
= 0; Index
< Length
; Index
+= sizeof (UINT32
)) {
2320 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2321 if (LsnsNo
== 0xFFFFFFFFUL
) {
2323 // Size not specified.
2328 *FreeSpaceSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2331 Length
= (LogicalVolInt
->NumberOfPartitions
* sizeof (UINT32
)) << 1;
2332 for (; Index
< Length
; Index
+= sizeof (UINT32
)) {
2333 LsnsNo
= *(UINT32
*)((UINT8
*)LogicalVolInt
->Data
+ Index
);
2334 if (LsnsNo
== 0xFFFFFFFFUL
) {
2336 // Size not specified.
2341 *VolumeSize
+= MultU64x32 ((UINT64
)LsnsNo
, LogicalBlockSize
);
2344 CopyMem ((VOID
*)&ExtentAd
,(VOID
*)&LogicalVolInt
->NextIntegrityExtent
,
2345 sizeof (UDF_EXTENT_AD
));
2346 if (ExtentAd
.ExtentLength
> 0) {
2347 FreePool ((VOID
*)LogicalVolInt
);
2348 goto Read_Next_Sequence
;
2351 FreePool ((VOID
*)LogicalVolInt
);
2358 Seek a file and read its data into memory on an UDF volume.
2360 @param[in] BlockIo BlockIo interface.
2361 @param[in] DiskIo DiskIo interface.
2362 @param[in] Volume UDF volume information structure.
2363 @param[in] File File information structure.
2364 @param[in] FileSize Size of the file.
2365 @param[in out] FilePosition File position.
2366 @param[in out] Buffer File data.
2367 @param[in out] BufferSize Read size.
2369 @retval EFI_SUCCESS File seeked and read.
2370 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2371 @retval EFI_NO_MEDIA The device has no media.
2372 @retval EFI_DEVICE_ERROR The device reported an error.
2373 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2374 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2380 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
,
2381 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
2382 IN UDF_VOLUME_INFO
*Volume
,
2383 IN UDF_FILE_INFO
*File
,
2385 IN OUT UINT64
*FilePosition
,
2386 IN OUT VOID
*Buffer
,
2387 IN OUT UINT64
*BufferSize
2391 UDF_READ_FILE_INFO ReadFileInfo
;
2393 ReadFileInfo
.Flags
= READ_FILE_SEEK_AND_READ
;
2394 ReadFileInfo
.FilePosition
= *FilePosition
;
2395 ReadFileInfo
.FileData
= Buffer
;
2396 ReadFileInfo
.FileDataSize
= *BufferSize
;
2397 ReadFileInfo
.FileSize
= FileSize
;
2403 &File
->FileIdentifierDesc
->Icb
,
2407 if (EFI_ERROR (Status
)) {
2411 *BufferSize
= ReadFileInfo
.FileDataSize
;
2412 *FilePosition
= ReadFileInfo
.FilePosition
;
2418 Check if ControllerHandle supports an UDF file system.
2420 @param[in] This Protocol instance pointer.
2421 @param[in] ControllerHandle Handle of device to test.
2423 @retval EFI_SUCCESS UDF file system found.
2424 @retval EFI_UNSUPPORTED UDF file system not found.
2428 SupportUdfFileSystem (
2429 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
2430 IN EFI_HANDLE ControllerHandle
2434 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
2435 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
2436 EFI_DEVICE_PATH_PROTOCOL
*LastDevicePathNode
;
2437 EFI_GUID
*VendorDefinedGuid
;
2438 EFI_GUID UdfDevPathGuid
= EFI_UDF_DEVICE_PATH_GUID
;
2441 // Open Device Path protocol on ControllerHandle
2443 Status
= gBS
->OpenProtocol (
2445 &gEfiDevicePathProtocolGuid
,
2446 (VOID
**)&DevicePath
,
2447 This
->DriverBindingHandle
,
2449 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2451 if (EFI_ERROR (Status
)) {
2452 return EFI_UNSUPPORTED
;
2455 Status
= EFI_UNSUPPORTED
;
2458 // Get last Device Path node
2460 LastDevicePathNode
= NULL
;
2461 DevicePathNode
= DevicePath
;
2462 while (!IsDevicePathEnd (DevicePathNode
)) {
2463 LastDevicePathNode
= DevicePathNode
;
2464 DevicePathNode
= NextDevicePathNode (DevicePathNode
);
2467 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2468 // of an UDF file system.
2470 if (LastDevicePathNode
!= NULL
&&
2471 DevicePathType (LastDevicePathNode
) == MEDIA_DEVICE_PATH
&&
2472 DevicePathSubType (LastDevicePathNode
) == MEDIA_VENDOR_DP
) {
2473 VendorDefinedGuid
= (EFI_GUID
*)((UINTN
)LastDevicePathNode
+
2474 OFFSET_OF (VENDOR_DEVICE_PATH
, Guid
));
2475 if (CompareGuid (VendorDefinedGuid
, &UdfDevPathGuid
)) {
2476 Status
= EFI_SUCCESS
;
2481 // Close Device Path protocol on ControllerHandle
2483 gBS
->CloseProtocol (
2485 &gEfiDevicePathProtocolGuid
,
2486 This
->DriverBindingHandle
,