]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
MdeModulePkg/UdfDxe: Refine boundary checks for file/path name string
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / UdfDxe / FileSystemOperations.c
1 /** @file
2 Handle on-disk format and volume structures in UDF/ECMA-167 file systems.
3
4 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
5 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
6
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 **/
15
16 #include "Udf.h"
17
18 //
19 // Vendor-Defined Device Path GUID for UDF file system
20 //
21 EFI_GUID gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
22
23 /**
24 Find the anchor volume descriptor pointer.
25
26 @param[in] BlockIo BlockIo interface.
27 @param[in] DiskIo DiskIo interface.
28 @param[out] AnchorPoint Anchor volume descriptor pointer.
29
30 @retval EFI_SUCCESS Anchor volume descriptor pointer found.
31 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
32 @retval other Anchor volume descriptor pointer not found.
33
34 **/
35 EFI_STATUS
36 FindAnchorVolumeDescriptorPointer (
37 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
38 IN EFI_DISK_IO_PROTOCOL *DiskIo,
39 OUT UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint
40 )
41 {
42 EFI_STATUS Status;
43 UINT32 BlockSize;
44 EFI_LBA EndLBA;
45 EFI_LBA DescriptorLBAs[4];
46 UINTN Index;
47 UDF_DESCRIPTOR_TAG *DescriptorTag;
48
49 BlockSize = BlockIo->Media->BlockSize;
50 EndLBA = BlockIo->Media->LastBlock;
51 DescriptorLBAs[0] = 256;
52 DescriptorLBAs[1] = EndLBA - 256;
53 DescriptorLBAs[2] = EndLBA;
54 DescriptorLBAs[3] = 512;
55
56 for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {
57 Status = DiskIo->ReadDisk (
58 DiskIo,
59 BlockIo->Media->MediaId,
60 MultU64x32 (DescriptorLBAs[Index], BlockSize),
61 sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),
62 (VOID *)AnchorPoint
63 );
64 if (EFI_ERROR (Status)) {
65 return Status;
66 }
67
68 DescriptorTag = &AnchorPoint->DescriptorTag;
69
70 //
71 // Check if read LBA has a valid AVDP descriptor.
72 //
73 if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
74 return EFI_SUCCESS;
75 }
76 }
77 //
78 // No AVDP found.
79 //
80 return EFI_VOLUME_CORRUPTED;
81 }
82
83 /**
84 Save the content of Logical Volume Descriptors and Partitions Descriptors in
85 memory.
86
87 @param[in] BlockIo BlockIo interface.
88 @param[in] DiskIo DiskIo interface.
89 @param[in] AnchorPoint Anchor volume descriptor pointer.
90 @param[out] Volume UDF volume information structure.
91
92 @retval EFI_SUCCESS The descriptors were saved.
93 @retval EFI_OUT_OF_RESOURCES The descriptors were not saved due to lack of
94 resources.
95 @retval other The descriptors were not saved due to
96 ReadDisk error.
97
98 **/
99 EFI_STATUS
100 StartMainVolumeDescriptorSequence (
101 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
102 IN EFI_DISK_IO_PROTOCOL *DiskIo,
103 IN UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER *AnchorPoint,
104 OUT UDF_VOLUME_INFO *Volume
105 )
106 {
107 EFI_STATUS Status;
108 UINT32 BlockSize;
109 UDF_EXTENT_AD *ExtentAd;
110 EFI_LBA SeqStartBlock;
111 EFI_LBA SeqEndBlock;
112 BOOLEAN StopSequence;
113 VOID *Buffer;
114 UDF_DESCRIPTOR_TAG *DescriptorTag;
115 UINT32 LogicalBlockSize;
116
117 BlockSize = BlockIo->Media->BlockSize;
118 ExtentAd = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
119
120 //
121 // Allocate buffer for reading disk blocks
122 //
123 Buffer = AllocateZeroPool ((UINTN)BlockSize);
124 if (Buffer == NULL) {
125 return EFI_OUT_OF_RESOURCES;
126 }
127
128 //
129 // The logical partition created by Partition driver is relative to the main
130 // VDS extent location, so we start the Main Volume Descriptor Sequence at
131 // LBA 0.
132 //
133 // We don't need to check again if we have valid Volume Descriptors here since
134 // Partition driver already did.
135 //
136 SeqStartBlock = 0;
137 SeqEndBlock = SeqStartBlock + DivU64x32 ((UINT64)ExtentAd->ExtentLength,
138 BlockSize);
139 StopSequence = FALSE;
140 for (; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
141 //
142 // Read disk block
143 //
144 Status = BlockIo->ReadBlocks (
145 BlockIo,
146 BlockIo->Media->MediaId,
147 SeqStartBlock,
148 BlockSize,
149 Buffer
150 );
151 if (EFI_ERROR (Status)) {
152 goto Out_Free;
153 }
154
155 DescriptorTag = Buffer;
156
157 switch (DescriptorTag->TagIdentifier) {
158 case UdfPartitionDescriptor:
159 //
160 // Save Partition Descriptor
161 //
162 CopyMem (&Volume->PartitionDesc, Buffer, sizeof (Volume->PartitionDesc));
163 break;
164
165 case UdfLogicalVolumeDescriptor:
166 //
167 // Save Logical Volume Descriptor
168 //
169 CopyMem (&Volume->LogicalVolDesc, Buffer, sizeof (Volume->LogicalVolDesc));
170 break;
171
172 case UdfTerminatingDescriptor:
173 StopSequence = TRUE;
174 break;
175
176 default:
177 ;
178 }
179 }
180
181 //
182 // Determine FE (File Entry) size
183 //
184 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
185 if (LogicalBlockSize >= UDF_LOGICAL_SECTOR_SIZE) {
186 Volume->FileEntrySize = (UINTN)LogicalBlockSize;
187 } else {
188 Volume->FileEntrySize = UDF_LOGICAL_SECTOR_SIZE;
189 }
190
191 Status = EFI_SUCCESS;
192
193 Out_Free:
194 //
195 // Free block read buffer
196 //
197 FreePool (Buffer);
198
199 return Status;
200 }
201
202 /**
203 Return a Partition Descriptor given a Long Allocation Descriptor. This is
204 necessary to calculate the right extent (LongAd) offset which is added up
205 with partition's starting location.
206
207 @param[in] Volume Volume information pointer.
208 @param[in] LongAd Long Allocation Descriptor pointer.
209
210 @return A pointer to a Partition Descriptor.
211
212 **/
213 UDF_PARTITION_DESCRIPTOR *
214 GetPdFromLongAd (
215 IN UDF_VOLUME_INFO *Volume,
216 IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd
217 )
218 {
219 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
220 UINT16 PartitionNum;
221
222 LogicalVolDesc = &Volume->LogicalVolDesc;
223
224 switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
225 case 0x0102:
226 case 0x0150:
227 case 0x0200:
228 case 0x0201:
229 case 0x0250:
230 case 0x0260:
231 //
232 // UDF 1.02 specification:
233 //
234 // There shall be exactly one prevailing Logical Volume Descriptor recorded
235 // per Volume Set. The Partition Maps field shall contain only Type 1
236 // Partition Maps.
237 //
238 // UDF 1.50 through 2.60 specs say:
239 //
240 // For the purpose of interchange partition maps shall be limited to
241 // Partition Map type 1, except type 2 maps as described in the document.
242 //
243 // NOTE: Only one Type 1 (Physical) Partition is supported. It has been
244 // checked already in Partition driver for existence of a single Type 1
245 // Partition map, so we don't have to double check here.
246 //
247 // Partition reference number can also be retrieved from
248 // LongAd->ExtentLocation.PartitionReferenceNumber, however the spec says
249 // it may be 0, so let's not rely on it.
250 //
251 PartitionNum = *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]);
252 break;
253
254 default:
255 //
256 // Unsupported UDF revision
257 //
258 return NULL;
259 }
260
261 //
262 // Check if partition number matches Partition Descriptor found in Main Volume
263 // Descriptor Sequence.
264 //
265 if (Volume->PartitionDesc.PartitionNumber == PartitionNum) {
266 return &Volume->PartitionDesc;
267 }
268
269 return NULL;
270 }
271
272 /**
273 Return logical sector number of a given Long Allocation Descriptor.
274
275 @param[in] Volume Volume information pointer.
276 @param[in] LongAd Long Allocation Descriptor pointer.
277 @param[out] Lsn Logical sector number pointer.
278
279 @retval EFI_SUCCESS Logical sector number successfully returned.
280 @retval EFI_UNSUPPORTED Logical sector number is not returned due to
281 unrecognized format.
282
283 **/
284 EFI_STATUS
285 GetLongAdLsn (
286 IN UDF_VOLUME_INFO *Volume,
287 IN UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd,
288 OUT UINT64 *Lsn
289 )
290 {
291 UDF_PARTITION_DESCRIPTOR *PartitionDesc;
292
293 PartitionDesc = GetPdFromLongAd (Volume, LongAd);
294 if (PartitionDesc == NULL) {
295 DEBUG ((
296 DEBUG_ERROR,
297 "%a: Fail to get the Partition Descriptor from the given Long Allocation Descriptor.\n",
298 __FUNCTION__
299 ));
300 return EFI_UNSUPPORTED;
301 }
302
303 *Lsn = (UINT64)PartitionDesc->PartitionStartingLocation -
304 Volume->MainVdsStartLocation +
305 LongAd->ExtentLocation.LogicalBlockNumber;
306
307 return EFI_SUCCESS;
308 }
309
310 /**
311 Return logical sector number of a given Short Allocation Descriptor.
312
313 @param[in] Volume Volume pointer.
314 @param[in] PartitionDesc Partition Descriptor pointer.
315 @param[in] ShortAd Short Allocation Descriptor pointer.
316
317 @return The logical sector number of a given Short Allocation Descriptor.
318
319 **/
320 UINT64
321 GetShortAdLsn (
322 IN UDF_VOLUME_INFO *Volume,
323 IN UDF_PARTITION_DESCRIPTOR *PartitionDesc,
324 IN UDF_SHORT_ALLOCATION_DESCRIPTOR *ShortAd
325 )
326 {
327 return (UINT64)PartitionDesc->PartitionStartingLocation -
328 Volume->MainVdsStartLocation + ShortAd->ExtentPosition;
329 }
330
331 /**
332 Find File Set Descriptor of a given Logical Volume Descriptor.
333
334 The found FSD will contain the extent (LogicalVolumeContentsUse) where our
335 root directory is.
336
337 @param[in] BlockIo BlockIo interface.
338 @param[in] DiskIo DiskIo interface.
339 @param[in] Volume Volume information pointer.
340
341 @retval EFI_SUCCESS File Set Descriptor pointer found.
342 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
343 @retval other File Set Descriptor pointer not found.
344
345 **/
346 EFI_STATUS
347 FindFileSetDescriptor (
348 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
349 IN EFI_DISK_IO_PROTOCOL *DiskIo,
350 IN UDF_VOLUME_INFO *Volume
351 )
352 {
353 EFI_STATUS Status;
354 UINT64 Lsn;
355 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
356 UDF_DESCRIPTOR_TAG *DescriptorTag;
357
358 LogicalVolDesc = &Volume->LogicalVolDesc;
359 Status = GetLongAdLsn (Volume, &LogicalVolDesc->LogicalVolumeContentsUse, &Lsn);
360 if (EFI_ERROR (Status)) {
361 return Status;
362 }
363
364 //
365 // As per UDF 2.60 specification:
366 //
367 // There shall be exactly one File Set Descriptor recorded per Logical
368 // Volume.
369 //
370 // Read disk block
371 //
372 Status = DiskIo->ReadDisk (
373 DiskIo,
374 BlockIo->Media->MediaId,
375 MultU64x32 (Lsn, LogicalVolDesc->LogicalBlockSize),
376 sizeof (Volume->FileSetDesc),
377 &Volume->FileSetDesc
378 );
379 if (EFI_ERROR (Status)) {
380 return Status;
381 }
382
383 DescriptorTag = &Volume->FileSetDesc.DescriptorTag;
384
385 //
386 // Check if read block is a File Set Descriptor
387 //
388 if (DescriptorTag->TagIdentifier != UdfFileSetDescriptor) {
389 return EFI_VOLUME_CORRUPTED;
390 }
391
392 return EFI_SUCCESS;
393 }
394
395 /**
396 Read Volume and File Structure on an UDF file system.
397
398 @param[in] BlockIo BlockIo interface.
399 @param[in] DiskIo DiskIo interface.
400 @param[out] Volume Volume information pointer.
401
402 @retval EFI_SUCCESS Volume and File Structure were read.
403 @retval other Volume and File Structure were not read.
404
405 **/
406 EFI_STATUS
407 ReadVolumeFileStructure (
408 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
409 IN EFI_DISK_IO_PROTOCOL *DiskIo,
410 OUT UDF_VOLUME_INFO *Volume
411 )
412 {
413 EFI_STATUS Status;
414 UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER AnchorPoint;
415 UDF_EXTENT_AD *ExtentAd;
416
417 //
418 // Find Anchor Volume Descriptor Pointer
419 //
420 Status = FindAnchorVolumeDescriptorPointer (
421 BlockIo,
422 DiskIo,
423 &AnchorPoint
424 );
425 if (EFI_ERROR (Status)) {
426 return Status;
427 }
428
429 //
430 // Save Main VDS start block number
431 //
432 ExtentAd = &AnchorPoint.MainVolumeDescriptorSequenceExtent;
433
434 Volume->MainVdsStartLocation = (UINT64)ExtentAd->ExtentLocation;
435
436 //
437 // Start Main Volume Descriptor Sequence.
438 //
439 Status = StartMainVolumeDescriptorSequence (
440 BlockIo,
441 DiskIo,
442 &AnchorPoint,
443 Volume
444 );
445 if (EFI_ERROR (Status)) {
446 return Status;
447 }
448
449 return Status;
450 }
451
452 /**
453 Calculate length of a given File Identifier Descriptor.
454
455 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
456
457 @return The length of a given File Identifier Descriptor.
458
459 **/
460 UINT64
461 GetFidDescriptorLength (
462 IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc
463 )
464 {
465 return (UINT64)(
466 (INTN)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR, Data[0]) + 3 +
467 FileIdentifierDesc->LengthOfFileIdentifier +
468 FileIdentifierDesc->LengthOfImplementationUse) >> 2) << 2
469 );
470 }
471
472 /**
473 Duplicate a given File Identifier Descriptor.
474
475 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
476 @param[out] NewFileIdentifierDesc The duplicated File Identifier Descriptor.
477
478 **/
479 VOID
480 DuplicateFid (
481 IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
482 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **NewFileIdentifierDesc
483 )
484 {
485 *NewFileIdentifierDesc =
486 (UDF_FILE_IDENTIFIER_DESCRIPTOR *)AllocateCopyPool (
487 (UINTN) GetFidDescriptorLength (FileIdentifierDesc), FileIdentifierDesc);
488 }
489
490 /**
491 Duplicate either a given File Entry or a given Extended File Entry.
492
493 @param[in] BlockIo BlockIo interface.
494 @param[in] Volume Volume information pointer.
495 @param[in] FileEntry (Extended) File Entry pointer.
496 @param[out] NewFileEntry The duplicated (Extended) File Entry.
497
498 **/
499 VOID
500 DuplicateFe (
501 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
502 IN UDF_VOLUME_INFO *Volume,
503 IN VOID *FileEntry,
504 OUT VOID **NewFileEntry
505 )
506 {
507 *NewFileEntry = AllocateCopyPool (Volume->FileEntrySize, FileEntry);
508 }
509
510 /**
511 Get raw data + length of a given File Entry or Extended File Entry.
512
513 The file's recorded data can contain either real file content (inline) or
514 a sequence of extents (or Allocation Descriptors) which tells where file's
515 content is stored in.
516
517 NOTE: The FE/EFE can be thought it was an inode.
518
519 @param[in] FileEntryData (Extended) File Entry pointer.
520 @param[out] Data Buffer contains the raw data of a given
521 (Extended) File Entry.
522 @param[out] Length Length of the data in Buffer.
523
524 **/
525 VOID
526 GetFileEntryData (
527 IN VOID *FileEntryData,
528 OUT VOID **Data,
529 OUT UINT64 *Length
530 )
531 {
532 UDF_DESCRIPTOR_TAG *DescriptorTag;
533 UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
534 UDF_FILE_ENTRY *FileEntry;
535
536 DescriptorTag = FileEntryData;
537
538 if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
539 ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;
540
541 *Length = ExtendedFileEntry->InformationLength;
542 *Data = (VOID *)((UINT8 *)ExtendedFileEntry->Data +
543 ExtendedFileEntry->LengthOfExtendedAttributes);
544 } else if (DescriptorTag->TagIdentifier == UdfFileEntry) {
545 FileEntry = (UDF_FILE_ENTRY *)FileEntryData;
546
547 *Length = FileEntry->InformationLength;
548 *Data = (VOID *)((UINT8 *)FileEntry->Data +
549 FileEntry->LengthOfExtendedAttributes);
550 }
551 }
552
553 /**
554 Get Allocation Descriptors' data information from a given FE/EFE.
555
556 @param[in] FileEntryData (Extended) File Entry pointer.
557 @param[out] AdsData Buffer contains the Allocation Descriptors'
558 data from a given FE/EFE.
559 @param[out] Length Length of the data in AdsData.
560
561 **/
562 VOID
563 GetAdsInformation (
564 IN VOID *FileEntryData,
565 OUT VOID **AdsData,
566 OUT UINT64 *Length
567 )
568 {
569 UDF_DESCRIPTOR_TAG *DescriptorTag;
570 UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
571 UDF_FILE_ENTRY *FileEntry;
572
573 DescriptorTag = FileEntryData;
574
575 if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
576 ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;
577
578 *Length = ExtendedFileEntry->LengthOfAllocationDescriptors;
579 *AdsData = (VOID *)((UINT8 *)ExtendedFileEntry->Data +
580 ExtendedFileEntry->LengthOfExtendedAttributes);
581 } else if (DescriptorTag->TagIdentifier == UdfFileEntry) {
582 FileEntry = (UDF_FILE_ENTRY *)FileEntryData;
583
584 *Length = FileEntry->LengthOfAllocationDescriptors;
585 *AdsData = (VOID *)((UINT8 *)FileEntry->Data +
586 FileEntry->LengthOfExtendedAttributes);
587 }
588 }
589
590 /**
591 Read next Long Allocation Descriptor from a given file's data.
592
593 @param[in] Data File's data pointer.
594 @param[in,out] Offset Starting offset of the File's data to read.
595 @param[in] Length Length of the data to read.
596 @param[out] FoundLongAd Long Allocation Descriptor pointer.
597
598 @retval EFI_SUCCESS A Long Allocation Descriptor was found.
599 @retval EFI_DEVICE_ERROR No more Long Allocation Descriptors.
600
601 **/
602 EFI_STATUS
603 GetLongAdFromAds (
604 IN VOID *Data,
605 IN OUT UINT64 *Offset,
606 IN UINT64 Length,
607 OUT UDF_LONG_ALLOCATION_DESCRIPTOR **FoundLongAd
608 )
609 {
610 UDF_LONG_ALLOCATION_DESCRIPTOR *LongAd;
611 UDF_EXTENT_FLAGS ExtentFlags;
612
613 for (;;) {
614 if (*Offset >= Length) {
615 //
616 // No more Long Allocation Descriptors.
617 //
618 return EFI_DEVICE_ERROR;
619 }
620
621 LongAd =
622 (UDF_LONG_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);
623
624 //
625 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
626 // allocated AD, then return it.
627 //
628 ExtentFlags = GET_EXTENT_FLAGS (LongAdsSequence, LongAd);
629 if (ExtentFlags == ExtentIsNextExtent ||
630 ExtentFlags == ExtentRecordedAndAllocated) {
631 break;
632 }
633
634 //
635 // This AD is either not recorded but allocated, or not recorded and not
636 // allocated. Skip it.
637 //
638 *Offset += AD_LENGTH (LongAdsSequence);
639 }
640
641 *FoundLongAd = LongAd;
642
643 return EFI_SUCCESS;
644 }
645
646 /**
647 Read next Short Allocation Descriptor from a given file's data.
648
649 @param[in] Data File's data pointer.
650 @param[in,out] Offset Starting offset of the File's data to read.
651 @param[in] Length Length of the data to read.
652 @param[out] FoundShortAd Short Allocation Descriptor pointer.
653
654 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
655 @retval EFI_DEVICE_ERROR No more Short Allocation Descriptors.
656
657 **/
658 EFI_STATUS
659 GetShortAdFromAds (
660 IN VOID *Data,
661 IN OUT UINT64 *Offset,
662 IN UINT64 Length,
663 OUT UDF_SHORT_ALLOCATION_DESCRIPTOR **FoundShortAd
664 )
665 {
666 UDF_SHORT_ALLOCATION_DESCRIPTOR *ShortAd;
667 UDF_EXTENT_FLAGS ExtentFlags;
668
669 for (;;) {
670 if (*Offset >= Length) {
671 //
672 // No more Short Allocation Descriptors.
673 //
674 return EFI_DEVICE_ERROR;
675 }
676
677 ShortAd =
678 (UDF_SHORT_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);
679
680 //
681 // If it's either an indirect AD (Extended Alllocation Descriptor) or an
682 // allocated AD, then return it.
683 //
684 ExtentFlags = GET_EXTENT_FLAGS (ShortAdsSequence, ShortAd);
685 if (ExtentFlags == ExtentIsNextExtent ||
686 ExtentFlags == ExtentRecordedAndAllocated) {
687 break;
688 }
689
690 //
691 // This AD is either not recorded but allocated, or not recorded and not
692 // allocated. Skip it.
693 //
694 *Offset += AD_LENGTH (ShortAdsSequence);
695 }
696
697 *FoundShortAd = ShortAd;
698
699 return EFI_SUCCESS;
700 }
701
702 /**
703 Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
704 file's data.
705
706 @param[in] RecordingFlags Flag to indicate the type of descriptor.
707 @param[in] Data File's data pointer.
708 @param[in,out] Offset Starting offset of the File's data to read.
709 @param[in] Length Length of the data to read.
710 @param[out] FoundAd Allocation Descriptor pointer.
711
712 @retval EFI_SUCCESS A Short Allocation Descriptor was found.
713 @retval EFI_DEVICE_ERROR No more Allocation Descriptors.
714 Invalid type of descriptor was given.
715
716 **/
717 EFI_STATUS
718 GetAllocationDescriptor (
719 IN UDF_FE_RECORDING_FLAGS RecordingFlags,
720 IN VOID *Data,
721 IN OUT UINT64 *Offset,
722 IN UINT64 Length,
723 OUT VOID **FoundAd
724 )
725 {
726 if (RecordingFlags == LongAdsSequence) {
727 return GetLongAdFromAds (
728 Data,
729 Offset,
730 Length,
731 (UDF_LONG_ALLOCATION_DESCRIPTOR **)FoundAd
732 );
733 } else if (RecordingFlags == ShortAdsSequence) {
734 return GetShortAdFromAds (
735 Data,
736 Offset,
737 Length,
738 (UDF_SHORT_ALLOCATION_DESCRIPTOR **)FoundAd
739 );
740 }
741
742 //
743 // Code should never reach here.
744 //
745 ASSERT (FALSE);
746 return EFI_DEVICE_ERROR;
747 }
748
749 /**
750 Return logical sector number of either Short or Long Allocation Descriptor.
751
752 @param[in] RecordingFlags Flag to indicate the type of descriptor.
753 @param[in] Volume Volume information pointer.
754 @param[in] ParentIcb Long Allocation Descriptor pointer.
755 @param[in] Ad Allocation Descriptor pointer.
756 @param[out] Lsn Logical sector number pointer.
757
758 @retval EFI_SUCCESS Logical sector number of the given Allocation
759 Descriptor successfully returned.
760 @retval EFI_UNSUPPORTED Logical sector number of the given Allocation
761 Descriptor is not returned due to unrecognized
762 format.
763
764 **/
765 EFI_STATUS
766 GetAllocationDescriptorLsn (
767 IN UDF_FE_RECORDING_FLAGS RecordingFlags,
768 IN UDF_VOLUME_INFO *Volume,
769 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
770 IN VOID *Ad,
771 OUT UINT64 *Lsn
772 )
773 {
774 UDF_PARTITION_DESCRIPTOR *PartitionDesc;
775
776 if (RecordingFlags == LongAdsSequence) {
777 return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad, Lsn);
778 } else if (RecordingFlags == ShortAdsSequence) {
779 PartitionDesc = GetPdFromLongAd (Volume, ParentIcb);
780 if (PartitionDesc == NULL) {
781 return EFI_UNSUPPORTED;
782 }
783
784 *Lsn = GetShortAdLsn (
785 Volume,
786 PartitionDesc,
787 (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad
788 );
789 return EFI_SUCCESS;
790 }
791
792 //
793 // Code should never reach here.
794 //
795 ASSERT (FALSE);
796 return EFI_UNSUPPORTED;
797 }
798
799 /**
800 Return offset + length of a given indirect Allocation Descriptor (AED).
801
802 @param[in] BlockIo BlockIo interface.
803 @param[in] DiskIo DiskIo interface.
804 @param[in] Volume Volume information pointer.
805 @param[in] ParentIcb Long Allocation Descriptor pointer.
806 @param[in] RecordingFlags Flag to indicate the type of descriptor.
807 @param[in] Ad Allocation Descriptor pointer.
808 @param[out] Offset Offset of a given indirect Allocation
809 Descriptor.
810 @param[out] Length Length of a given indirect Allocation
811 Descriptor.
812
813 @retval EFI_SUCCESS The offset and length were returned.
814 @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due
815 to lack of resources.
816 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
817 @retval other The offset and length were not returned.
818
819 **/
820 EFI_STATUS
821 GetAedAdsOffset (
822 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
823 IN EFI_DISK_IO_PROTOCOL *DiskIo,
824 IN UDF_VOLUME_INFO *Volume,
825 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
826 IN UDF_FE_RECORDING_FLAGS RecordingFlags,
827 IN VOID *Ad,
828 OUT UINT64 *Offset,
829 OUT UINT64 *Length
830 )
831 {
832 EFI_STATUS Status;
833 UINT32 ExtentLength;
834 UINT64 Lsn;
835 VOID *Data;
836 UINT32 LogicalBlockSize;
837 UDF_ALLOCATION_EXTENT_DESCRIPTOR *AllocExtDesc;
838 UDF_DESCRIPTOR_TAG *DescriptorTag;
839
840 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
841 Status = GetAllocationDescriptorLsn (RecordingFlags,
842 Volume,
843 ParentIcb,
844 Ad,
845 &Lsn);
846 if (EFI_ERROR (Status)) {
847 return Status;
848 }
849
850 Data = AllocatePool (ExtentLength);
851 if (Data == NULL) {
852 return EFI_OUT_OF_RESOURCES;
853 }
854
855 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
856
857 //
858 // Read extent.
859 //
860 Status = DiskIo->ReadDisk (
861 DiskIo,
862 BlockIo->Media->MediaId,
863 MultU64x32 (Lsn, LogicalBlockSize),
864 ExtentLength,
865 Data
866 );
867 if (EFI_ERROR (Status)) {
868 goto Exit;
869 }
870
871 AllocExtDesc = (UDF_ALLOCATION_EXTENT_DESCRIPTOR *)Data;
872
873 DescriptorTag = &AllocExtDesc->DescriptorTag;
874
875 //
876 // Check if read extent contains a valid tag identifier for AED.
877 //
878 if (DescriptorTag->TagIdentifier != UdfAllocationExtentDescriptor) {
879 Status = EFI_VOLUME_CORRUPTED;
880 goto Exit;
881 }
882
883 //
884 // Get AED's block offset and its length.
885 //
886 *Offset = MultU64x32 (Lsn, LogicalBlockSize) +
887 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR);
888 *Length = AllocExtDesc->LengthOfAllocationDescriptors;
889
890 Exit:
891 FreePool (Data);
892
893 return Status;
894 }
895
896 /**
897 Read Allocation Extent Descriptor into memory.
898
899 @param[in] BlockIo BlockIo interface.
900 @param[in] DiskIo DiskIo interface.
901 @param[in] Volume Volume information pointer.
902 @param[in] ParentIcb Long Allocation Descriptor pointer.
903 @param[in] RecordingFlags Flag to indicate the type of descriptor.
904 @param[in] Ad Allocation Descriptor pointer.
905 @param[out] Data Buffer that contains the Allocation Extent
906 Descriptor.
907 @param[out] Length Length of Data.
908
909 @retval EFI_SUCCESS The Allocation Extent Descriptor was read.
910 @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read
911 due to lack of resources.
912 @retval other Fail to read the disk.
913
914 **/
915 EFI_STATUS
916 GetAedAdsData (
917 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
918 IN EFI_DISK_IO_PROTOCOL *DiskIo,
919 IN UDF_VOLUME_INFO *Volume,
920 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
921 IN UDF_FE_RECORDING_FLAGS RecordingFlags,
922 IN VOID *Ad,
923 OUT VOID **Data,
924 OUT UINT64 *Length
925 )
926 {
927 EFI_STATUS Status;
928 UINT64 Offset;
929
930 //
931 // Get AED's offset + length.
932 //
933 Status = GetAedAdsOffset (
934 BlockIo,
935 DiskIo,
936 Volume,
937 ParentIcb,
938 RecordingFlags,
939 Ad,
940 &Offset,
941 Length
942 );
943 if (EFI_ERROR (Status)) {
944 return Status;
945 }
946
947 //
948 // Allocate buffer to read in AED's data.
949 //
950 *Data = AllocatePool ((UINTN) (*Length));
951 if (*Data == NULL) {
952 return EFI_OUT_OF_RESOURCES;
953 }
954
955 return DiskIo->ReadDisk (
956 DiskIo,
957 BlockIo->Media->MediaId,
958 Offset,
959 (UINTN) (*Length),
960 *Data
961 );
962 }
963
964 /**
965 Function used to serialise reads of Allocation Descriptors.
966
967 @param[in] RecordingFlags Flag to indicate the type of descriptor.
968 @param[in] Ad Allocation Descriptor pointer.
969 @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.
970 @param[in] Length Length of Buffer.
971
972 @retval EFI_SUCCESS Buffer was grown to hold the next Allocation
973 Descriptor.
974 @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.
975
976 **/
977 EFI_STATUS
978 GrowUpBufferToNextAd (
979 IN UDF_FE_RECORDING_FLAGS RecordingFlags,
980 IN VOID *Ad,
981 IN OUT VOID **Buffer,
982 IN UINT64 Length
983 )
984 {
985 UINT32 ExtentLength;
986
987 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
988
989 if (*Buffer == NULL) {
990 *Buffer = AllocatePool (ExtentLength);
991 if (*Buffer == NULL) {
992 return EFI_OUT_OF_RESOURCES;
993 }
994 } else {
995 *Buffer = ReallocatePool ((UINTN) Length, (UINTN) (Length + ExtentLength), *Buffer);
996 if (*Buffer == NULL) {
997 return EFI_OUT_OF_RESOURCES;
998 }
999 }
1000
1001 return EFI_SUCCESS;
1002 }
1003
1004 /**
1005 Read data or size of either a File Entry or an Extended File Entry.
1006
1007 @param[in] BlockIo BlockIo interface.
1008 @param[in] DiskIo DiskIo interface.
1009 @param[in] Volume Volume information pointer.
1010 @param[in] ParentIcb Long Allocation Descriptor pointer.
1011 @param[in] FileEntryData FE/EFE structure pointer.
1012 @param[in, out] ReadFileInfo Read file information pointer.
1013
1014 @retval EFI_SUCCESS Data or size of a FE/EFE was read.
1015 @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to
1016 lack of resources.
1017 @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is
1018 invalid.
1019 @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData
1020 is not supported.
1021 @retval other Data or size of a FE/EFE was not read.
1022
1023 **/
1024 EFI_STATUS
1025 ReadFile (
1026 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1027 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1028 IN UDF_VOLUME_INFO *Volume,
1029 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
1030 IN VOID *FileEntryData,
1031 IN OUT UDF_READ_FILE_INFO *ReadFileInfo
1032 )
1033 {
1034 EFI_STATUS Status;
1035 UINT32 LogicalBlockSize;
1036 VOID *Data;
1037 UINT64 Length;
1038 VOID *Ad;
1039 UINT64 AdOffset;
1040 UINT64 Lsn;
1041 BOOLEAN DoFreeAed;
1042 UINT64 FilePosition;
1043 UINT64 Offset;
1044 UINT64 DataOffset;
1045 UINT64 BytesLeft;
1046 UINT64 DataLength;
1047 BOOLEAN FinishedSeeking;
1048 UINT32 ExtentLength;
1049 UDF_FE_RECORDING_FLAGS RecordingFlags;
1050
1051 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
1052 DoFreeAed = FALSE;
1053
1054 //
1055 // set BytesLeft to suppress incorrect compiler/analyzer warnings
1056 //
1057 BytesLeft = 0;
1058 DataOffset = 0;
1059 FilePosition = 0;
1060 FinishedSeeking = FALSE;
1061 Data = NULL;
1062
1063 switch (ReadFileInfo->Flags) {
1064 case ReadFileGetFileSize:
1065 case ReadFileAllocateAndRead:
1066 //
1067 // Initialise ReadFileInfo structure for either getting file size, or
1068 // reading file's recorded data.
1069 //
1070 ReadFileInfo->ReadLength = 0;
1071 ReadFileInfo->FileData = NULL;
1072 break;
1073 case ReadFileSeekAndRead:
1074 //
1075 // About to seek a file and/or read its data.
1076 //
1077 Length = ReadFileInfo->FileSize - ReadFileInfo->FilePosition;
1078 if (ReadFileInfo->FileDataSize > Length) {
1079 //
1080 // About to read beyond the EOF -- truncate it.
1081 //
1082 ReadFileInfo->FileDataSize = Length;
1083 }
1084
1085 //
1086 // Initialise data to start seeking and/or reading a file.
1087 //
1088 BytesLeft = ReadFileInfo->FileDataSize;
1089 DataOffset = 0;
1090 FilePosition = 0;
1091 FinishedSeeking = FALSE;
1092
1093 break;
1094 }
1095
1096 RecordingFlags = GET_FE_RECORDING_FLAGS (FileEntryData);
1097 switch (RecordingFlags) {
1098 case InlineData:
1099 //
1100 // There are no extents for this FE/EFE. All data is inline.
1101 //
1102 GetFileEntryData (FileEntryData, &Data, &Length);
1103
1104 if (ReadFileInfo->Flags == ReadFileGetFileSize) {
1105 ReadFileInfo->ReadLength = Length;
1106 } else if (ReadFileInfo->Flags == ReadFileAllocateAndRead) {
1107 //
1108 // Allocate buffer for starting read data.
1109 //
1110 ReadFileInfo->FileData = AllocatePool ((UINTN) Length);
1111 if (ReadFileInfo->FileData == NULL) {
1112 return EFI_OUT_OF_RESOURCES;
1113 }
1114
1115 //
1116 // Read all inline data into ReadFileInfo->FileData
1117 //
1118 CopyMem (ReadFileInfo->FileData, Data, (UINTN) Length);
1119 ReadFileInfo->ReadLength = Length;
1120 } else if (ReadFileInfo->Flags == ReadFileSeekAndRead) {
1121 //
1122 // If FilePosition is non-zero, seek file to FilePosition, read
1123 // FileDataSize bytes and then updates FilePosition.
1124 //
1125 CopyMem (
1126 ReadFileInfo->FileData,
1127 (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition),
1128 (UINTN) ReadFileInfo->FileDataSize
1129 );
1130
1131 ReadFileInfo->FilePosition += ReadFileInfo->FileDataSize;
1132 } else {
1133 ASSERT (FALSE);
1134 return EFI_INVALID_PARAMETER;
1135 }
1136
1137 Status = EFI_SUCCESS;
1138 break;
1139
1140 case LongAdsSequence:
1141 case ShortAdsSequence:
1142 //
1143 // This FE/EFE contains a run of Allocation Descriptors. Get data + size
1144 // for start reading them out.
1145 //
1146 GetAdsInformation (FileEntryData, &Data, &Length);
1147 AdOffset = 0;
1148
1149 for (;;) {
1150 //
1151 // Read AD.
1152 //
1153 Status = GetAllocationDescriptor (
1154 RecordingFlags,
1155 Data,
1156 &AdOffset,
1157 Length,
1158 &Ad
1159 );
1160 if (Status == EFI_DEVICE_ERROR) {
1161 Status = EFI_SUCCESS;
1162 goto Done;
1163 }
1164
1165 //
1166 // Check if AD is an indirect AD. If so, read Allocation Extent
1167 // Descriptor and its extents (ADs).
1168 //
1169 if (GET_EXTENT_FLAGS (RecordingFlags, Ad) == ExtentIsNextExtent) {
1170 if (!DoFreeAed) {
1171 DoFreeAed = TRUE;
1172 } else {
1173 FreePool (Data);
1174 }
1175
1176 Status = GetAedAdsData (
1177 BlockIo,
1178 DiskIo,
1179 Volume,
1180 ParentIcb,
1181 RecordingFlags,
1182 Ad,
1183 &Data,
1184 &Length
1185 );
1186 if (EFI_ERROR (Status)) {
1187 goto Error_Get_Aed;
1188 }
1189 ASSERT (Data != NULL);
1190
1191 AdOffset = 0;
1192 continue;
1193 }
1194
1195 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
1196
1197 Status = GetAllocationDescriptorLsn (RecordingFlags,
1198 Volume,
1199 ParentIcb,
1200 Ad,
1201 &Lsn);
1202 if (EFI_ERROR (Status)) {
1203 goto Done;
1204 }
1205
1206 switch (ReadFileInfo->Flags) {
1207 case ReadFileGetFileSize:
1208 ReadFileInfo->ReadLength += ExtentLength;
1209 break;
1210 case ReadFileAllocateAndRead:
1211 //
1212 // Increase FileData (if necessary) to read next extent.
1213 //
1214 Status = GrowUpBufferToNextAd (
1215 RecordingFlags,
1216 Ad,
1217 &ReadFileInfo->FileData,
1218 ReadFileInfo->ReadLength
1219 );
1220 if (EFI_ERROR (Status)) {
1221 goto Error_Alloc_Buffer_To_Next_Ad;
1222 }
1223
1224 //
1225 // Read extent's data into FileData.
1226 //
1227 Status = DiskIo->ReadDisk (
1228 DiskIo,
1229 BlockIo->Media->MediaId,
1230 MultU64x32 (Lsn, LogicalBlockSize),
1231 ExtentLength,
1232 (VOID *)((UINT8 *)ReadFileInfo->FileData +
1233 ReadFileInfo->ReadLength)
1234 );
1235 if (EFI_ERROR (Status)) {
1236 goto Error_Read_Disk_Blk;
1237 }
1238
1239 ReadFileInfo->ReadLength += ExtentLength;
1240 break;
1241 case ReadFileSeekAndRead:
1242 //
1243 // Seek file first before reading in its data.
1244 //
1245 if (FinishedSeeking) {
1246 Offset = 0;
1247 goto Skip_File_Seek;
1248 }
1249
1250 if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) {
1251 FilePosition += ExtentLength;
1252 goto Skip_Ad;
1253 }
1254
1255 if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) {
1256 Offset = ReadFileInfo->FilePosition - FilePosition;
1257 } else {
1258 Offset = 0;
1259 }
1260
1261 //
1262 // Done with seeking file. Start reading its data.
1263 //
1264 FinishedSeeking = TRUE;
1265
1266 Skip_File_Seek:
1267 //
1268 // Make sure we don't read more data than really wanted.
1269 //
1270 if (ExtentLength - Offset > BytesLeft) {
1271 DataLength = BytesLeft;
1272 } else {
1273 DataLength = ExtentLength - Offset;
1274 }
1275
1276 //
1277 // Read extent's data into FileData.
1278 //
1279 Status = DiskIo->ReadDisk (
1280 DiskIo,
1281 BlockIo->Media->MediaId,
1282 Offset + MultU64x32 (Lsn, LogicalBlockSize),
1283 (UINTN) DataLength,
1284 (VOID *)((UINT8 *)ReadFileInfo->FileData +
1285 DataOffset)
1286 );
1287 if (EFI_ERROR (Status)) {
1288 goto Error_Read_Disk_Blk;
1289 }
1290
1291 //
1292 // Update current file's position.
1293 //
1294 DataOffset += DataLength;
1295 ReadFileInfo->FilePosition += DataLength;
1296
1297 BytesLeft -= DataLength;
1298 if (BytesLeft == 0) {
1299 //
1300 // There is no more file data to read.
1301 //
1302 Status = EFI_SUCCESS;
1303 goto Done;
1304 }
1305
1306 break;
1307 }
1308
1309 Skip_Ad:
1310 //
1311 // Point to the next AD (extent).
1312 //
1313 AdOffset += AD_LENGTH (RecordingFlags);
1314 }
1315
1316 break;
1317 case ExtendedAdsSequence:
1318 // FIXME: Not supported. Got no volume with it, yet.
1319 ASSERT (FALSE);
1320 Status = EFI_UNSUPPORTED;
1321 break;
1322
1323 default:
1324 //
1325 // A flag value reserved by the ECMA-167 standard (3rd Edition - June
1326 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
1327 //
1328 Status = EFI_UNSUPPORTED;
1329 break;
1330 }
1331
1332 Done:
1333 if (DoFreeAed) {
1334 FreePool (Data);
1335 }
1336
1337 return Status;
1338
1339 Error_Read_Disk_Blk:
1340 Error_Alloc_Buffer_To_Next_Ad:
1341 if (ReadFileInfo->Flags != ReadFileSeekAndRead) {
1342 FreePool (ReadFileInfo->FileData);
1343 }
1344
1345 if (DoFreeAed) {
1346 FreePool (Data);
1347 }
1348
1349 Error_Get_Aed:
1350 return Status;
1351 }
1352
1353 /**
1354 Find a file by its filename from a given Parent file.
1355
1356 @param[in] BlockIo BlockIo interface.
1357 @param[in] DiskIo DiskIo interface.
1358 @param[in] Volume Volume information pointer.
1359 @param[in] FileName File name string.
1360 @param[in] Parent Parent directory file.
1361 @param[in] Icb Long Allocation Descriptor pointer.
1362 @param[out] File Found file.
1363
1364 @retval EFI_SUCCESS The file was found.
1365 @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.
1366 @retval EFI_NOT_FOUND The file was not found.
1367
1368 **/
1369 EFI_STATUS
1370 InternalFindFile (
1371 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1372 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1373 IN UDF_VOLUME_INFO *Volume,
1374 IN CHAR16 *FileName,
1375 IN UDF_FILE_INFO *Parent,
1376 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
1377 OUT UDF_FILE_INFO *File
1378 )
1379 {
1380 EFI_STATUS Status;
1381 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
1382 UDF_READ_DIRECTORY_INFO ReadDirInfo;
1383 BOOLEAN Found;
1384 CHAR16 FoundFileName[UDF_FILENAME_LENGTH];
1385 VOID *CompareFileEntry;
1386
1387 //
1388 // Check if both Parent->FileIdentifierDesc and Icb are NULL.
1389 //
1390 if ((Parent->FileIdentifierDesc == NULL) && (Icb == NULL)) {
1391 return EFI_INVALID_PARAMETER;
1392 }
1393
1394 //
1395 // Check if parent file is really directory.
1396 //
1397 if (FE_ICB_FILE_TYPE (Parent->FileEntry) != UdfFileEntryDirectory) {
1398 return EFI_NOT_FOUND;
1399 }
1400
1401 //
1402 // If FileName is current file or working directory, just duplicate Parent's
1403 // FE/EFE and FID descriptors.
1404 //
1405 if (StrCmp (FileName, L".") == 0) {
1406 if (Parent->FileIdentifierDesc == NULL) {
1407 return EFI_INVALID_PARAMETER;
1408 }
1409
1410 DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);
1411 if (File->FileEntry == NULL) {
1412 return EFI_OUT_OF_RESOURCES;
1413 }
1414
1415 DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);
1416 if (File->FileIdentifierDesc == NULL) {
1417 FreePool (File->FileEntry);
1418 return EFI_OUT_OF_RESOURCES;
1419 }
1420
1421 return EFI_SUCCESS;
1422 }
1423
1424 //
1425 // Start directory listing.
1426 //
1427 ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
1428 Found = FALSE;
1429
1430 for (;;) {
1431 Status = ReadDirectoryEntry (
1432 BlockIo,
1433 DiskIo,
1434 Volume,
1435 (Parent->FileIdentifierDesc != NULL) ?
1436 &Parent->FileIdentifierDesc->Icb :
1437 Icb,
1438 Parent->FileEntry,
1439 &ReadDirInfo,
1440 &FileIdentifierDesc
1441 );
1442 if (EFI_ERROR (Status)) {
1443 if (Status == EFI_DEVICE_ERROR) {
1444 Status = EFI_NOT_FOUND;
1445 }
1446
1447 break;
1448 }
1449 //
1450 // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is
1451 // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code
1452 // reaches here, 'FileIdentifierDesc' must be not NULL.
1453 //
1454 // The ASSERT here is for addressing a false positive NULL pointer
1455 // dereference issue raised from static analysis.
1456 //
1457 ASSERT (FileIdentifierDesc != NULL);
1458
1459 if (FileIdentifierDesc->FileCharacteristics & PARENT_FILE) {
1460 //
1461 // This FID contains the location (FE/EFE) of the parent directory of this
1462 // directory (Parent), and if FileName is either ".." or "\\", then it's
1463 // the expected FID.
1464 //
1465 if (StrCmp (FileName, L"..") == 0 || StrCmp (FileName, L"\\") == 0) {
1466 Found = TRUE;
1467 break;
1468 }
1469 } else {
1470 Status = GetFileNameFromFid (FileIdentifierDesc, ARRAY_SIZE (FoundFileName), FoundFileName);
1471 if (EFI_ERROR (Status)) {
1472 break;
1473 }
1474
1475 if (StrCmp (FileName, FoundFileName) == 0) {
1476 //
1477 // FID has been found. Prepare to find its respective FE/EFE.
1478 //
1479 Found = TRUE;
1480 break;
1481 }
1482 }
1483
1484 FreePool ((VOID *)FileIdentifierDesc);
1485 }
1486
1487 if (ReadDirInfo.DirectoryData != NULL) {
1488 //
1489 // Free all allocated resources for the directory listing.
1490 //
1491 FreePool (ReadDirInfo.DirectoryData);
1492 }
1493
1494 if (Found) {
1495 Status = EFI_SUCCESS;
1496
1497 File->FileIdentifierDesc = FileIdentifierDesc;
1498
1499 //
1500 // If the requested file is root directory, then the FE/EFE was already
1501 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1502 //
1503 // Otherwise, find FE/EFE from the respective FID.
1504 //
1505 if (StrCmp (FileName, L"\\") != 0) {
1506 Status = FindFileEntry (
1507 BlockIo,
1508 DiskIo,
1509 Volume,
1510 &FileIdentifierDesc->Icb,
1511 &CompareFileEntry
1512 );
1513 if (EFI_ERROR (Status)) {
1514 goto Error_Find_Fe;
1515 }
1516
1517 //
1518 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1519 //
1520 if (CompareMem ((VOID *)Parent->FileEntry, (VOID *)CompareFileEntry,
1521 Volume->FileEntrySize) != 0) {
1522 File->FileEntry = CompareFileEntry;
1523 } else {
1524 FreePool ((VOID *)FileIdentifierDesc);
1525 FreePool ((VOID *)CompareFileEntry);
1526 Status = EFI_NOT_FOUND;
1527 }
1528 }
1529 }
1530
1531 return Status;
1532
1533 Error_Find_Fe:
1534 FreePool ((VOID *)FileIdentifierDesc);
1535
1536 return Status;
1537 }
1538
1539 /**
1540 Read volume information on a medium which contains a valid UDF file system.
1541
1542 @param[in] BlockIo BlockIo interface.
1543 @param[in] DiskIo DiskIo interface.
1544 @param[out] Volume UDF volume information structure.
1545
1546 @retval EFI_SUCCESS Volume information read.
1547 @retval EFI_NO_MEDIA The device has no media.
1548 @retval EFI_DEVICE_ERROR The device reported an error.
1549 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1550 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1551
1552 **/
1553 EFI_STATUS
1554 ReadUdfVolumeInformation (
1555 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1556 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1557 OUT UDF_VOLUME_INFO *Volume
1558 )
1559 {
1560 EFI_STATUS Status;
1561
1562 //
1563 // Read all necessary UDF volume information and keep it private to the driver
1564 //
1565 Status = ReadVolumeFileStructure (
1566 BlockIo,
1567 DiskIo,
1568 Volume
1569 );
1570 if (EFI_ERROR (Status)) {
1571 return Status;
1572 }
1573
1574 //
1575 // Find File Set Descriptor
1576 //
1577 Status = FindFileSetDescriptor (BlockIo, DiskIo, Volume);
1578 if (EFI_ERROR (Status)) {
1579 return Status;
1580 }
1581
1582 return Status;
1583 }
1584
1585 /**
1586 Find the root directory on an UDF volume.
1587
1588 @param[in] BlockIo BlockIo interface.
1589 @param[in] DiskIo DiskIo interface.
1590 @param[in] Volume UDF volume information structure.
1591 @param[out] File Root directory file.
1592
1593 @retval EFI_SUCCESS Root directory found.
1594 @retval EFI_NO_MEDIA The device has no media.
1595 @retval EFI_DEVICE_ERROR The device reported an error.
1596 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1597 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1598 resources.
1599
1600 **/
1601 EFI_STATUS
1602 FindRootDirectory (
1603 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1604 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1605 IN UDF_VOLUME_INFO *Volume,
1606 OUT UDF_FILE_INFO *File
1607 )
1608 {
1609 EFI_STATUS Status;
1610 UDF_FILE_INFO Parent;
1611
1612 Status = FindFileEntry (
1613 BlockIo,
1614 DiskIo,
1615 Volume,
1616 &Volume->FileSetDesc.RootDirectoryIcb,
1617 &File->FileEntry
1618 );
1619 if (EFI_ERROR (Status)) {
1620 return Status;
1621 }
1622
1623 Parent.FileEntry = File->FileEntry;
1624 Parent.FileIdentifierDesc = NULL;
1625
1626 Status = FindFile (
1627 BlockIo,
1628 DiskIo,
1629 Volume,
1630 L"\\",
1631 NULL,
1632 &Parent,
1633 &Volume->FileSetDesc.RootDirectoryIcb,
1634 File
1635 );
1636 if (EFI_ERROR (Status)) {
1637 FreePool (File->FileEntry);
1638 }
1639
1640 return Status;
1641 }
1642
1643 /**
1644 Find either a File Entry or a Extended File Entry from a given ICB.
1645
1646 @param[in] BlockIo BlockIo interface.
1647 @param[in] DiskIo DiskIo interface.
1648 @param[in] Volume UDF volume information structure.
1649 @param[in] Icb ICB of the FID.
1650 @param[out] FileEntry File Entry or Extended File Entry.
1651
1652 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1653 @retval EFI_NO_MEDIA The device has no media.
1654 @retval EFI_DEVICE_ERROR The device reported an error.
1655 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1656 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1657 resources.
1658
1659 **/
1660 EFI_STATUS
1661 FindFileEntry (
1662 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1663 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1664 IN UDF_VOLUME_INFO *Volume,
1665 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
1666 OUT VOID **FileEntry
1667 )
1668 {
1669 EFI_STATUS Status;
1670 UINT64 Lsn;
1671 UINT32 LogicalBlockSize;
1672 UDF_DESCRIPTOR_TAG *DescriptorTag;
1673 VOID *ReadBuffer;
1674
1675 Status = GetLongAdLsn (Volume, Icb, &Lsn);
1676 if (EFI_ERROR (Status)) {
1677 return Status;
1678 }
1679
1680 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
1681
1682 ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);
1683 if (ReadBuffer == NULL) {
1684 return EFI_OUT_OF_RESOURCES;
1685 }
1686
1687 //
1688 // Read extent.
1689 //
1690 Status = DiskIo->ReadDisk (
1691 DiskIo,
1692 BlockIo->Media->MediaId,
1693 MultU64x32 (Lsn, LogicalBlockSize),
1694 Volume->FileEntrySize,
1695 ReadBuffer
1696 );
1697 if (EFI_ERROR (Status)) {
1698 goto Error_Read_Disk_Blk;
1699 }
1700
1701 DescriptorTag = ReadBuffer;
1702
1703 //
1704 // Check if the read extent contains a valid Tag Identifier for the expected
1705 // FE/EFE.
1706 //
1707 if (DescriptorTag->TagIdentifier != UdfFileEntry &&
1708 DescriptorTag->TagIdentifier != UdfExtendedFileEntry) {
1709 Status = EFI_VOLUME_CORRUPTED;
1710 goto Error_Invalid_Fe;
1711 }
1712
1713 *FileEntry = ReadBuffer;
1714 return EFI_SUCCESS;
1715
1716 Error_Invalid_Fe:
1717 Error_Read_Disk_Blk:
1718 FreePool (ReadBuffer);
1719
1720 return Status;
1721 }
1722
1723 /**
1724 Find a file given its absolute path on an UDF volume.
1725
1726 @param[in] BlockIo BlockIo interface.
1727 @param[in] DiskIo DiskIo interface.
1728 @param[in] Volume UDF volume information structure.
1729 @param[in] FilePath File's absolute path.
1730 @param[in] Root Root directory file.
1731 @param[in] Parent Parent directory file.
1732 @param[in] Icb ICB of Parent.
1733 @param[out] File Found file.
1734
1735 @retval EFI_SUCCESS FilePath was found.
1736 @retval EFI_NO_MEDIA The device has no media.
1737 @retval EFI_DEVICE_ERROR The device reported an error.
1738 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1739 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
1740 resources.
1741
1742 **/
1743 EFI_STATUS
1744 FindFile (
1745 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1746 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1747 IN UDF_VOLUME_INFO *Volume,
1748 IN CHAR16 *FilePath,
1749 IN UDF_FILE_INFO *Root,
1750 IN UDF_FILE_INFO *Parent,
1751 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
1752 OUT UDF_FILE_INFO *File
1753 )
1754 {
1755 EFI_STATUS Status;
1756 CHAR16 FileName[UDF_FILENAME_LENGTH];
1757 CHAR16 *FileNamePointer;
1758 UDF_FILE_INFO PreviousFile;
1759 VOID *FileEntry;
1760
1761 Status = EFI_NOT_FOUND;
1762
1763 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
1764 while (*FilePath != L'\0') {
1765 FileNamePointer = FileName;
1766 while (*FilePath != L'\0' && *FilePath != L'\\') {
1767 if ((((UINTN)FileNamePointer - (UINTN)FileName) / sizeof (CHAR16)) >=
1768 (ARRAY_SIZE (FileName) - 1)) {
1769 return EFI_NOT_FOUND;
1770 }
1771
1772 *FileNamePointer++ = *FilePath++;
1773 }
1774
1775 *FileNamePointer = L'\0';
1776 if (FileName[0] == L'\0') {
1777 //
1778 // Open root directory.
1779 //
1780 if (Root == NULL) {
1781 //
1782 // There is no file found for the root directory yet. So, find only its
1783 // FID by now.
1784 //
1785 // See UdfOpenVolume() function.
1786 //
1787 Status = InternalFindFile (BlockIo,
1788 DiskIo,
1789 Volume,
1790 L"\\",
1791 &PreviousFile,
1792 Icb,
1793 File);
1794 } else {
1795 //
1796 // We've already a file pointer (Root) for the root directory. Duplicate
1797 // its FE/EFE and FID descriptors.
1798 //
1799 Status = EFI_SUCCESS;
1800 DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);
1801 if (File->FileEntry == NULL) {
1802 Status = EFI_OUT_OF_RESOURCES;
1803 } else {
1804 //
1805 // File->FileEntry is not NULL.
1806 //
1807 DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);
1808 if (File->FileIdentifierDesc == NULL) {
1809 FreePool (File->FileEntry);
1810 Status = EFI_OUT_OF_RESOURCES;
1811 }
1812 }
1813 }
1814 } else {
1815 //
1816 // No root directory. Find filename from the current directory.
1817 //
1818 Status = InternalFindFile (BlockIo,
1819 DiskIo,
1820 Volume,
1821 FileName,
1822 &PreviousFile,
1823 Icb,
1824 File);
1825 }
1826
1827 if (EFI_ERROR (Status)) {
1828 return Status;
1829 }
1830
1831 //
1832 // If the found file is a symlink, then find its respective FE/EFE and
1833 // FID descriptors.
1834 //
1835 if (FE_ICB_FILE_TYPE (File->FileEntry) == UdfFileEntrySymlink) {
1836 FreePool ((VOID *)File->FileIdentifierDesc);
1837
1838 FileEntry = File->FileEntry;
1839
1840 Status = ResolveSymlink (BlockIo,
1841 DiskIo,
1842 Volume,
1843 &PreviousFile,
1844 FileEntry,
1845 File);
1846
1847 FreePool (FileEntry);
1848
1849 if (EFI_ERROR (Status)) {
1850 return Status;
1851 }
1852 }
1853
1854 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
1855 sizeof (UDF_FILE_INFO)) != 0) {
1856 CleanupFileInformation (&PreviousFile);
1857 }
1858
1859 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
1860 if (*FilePath != L'\0' && *FilePath == L'\\') {
1861 FilePath++;
1862 }
1863 }
1864
1865 return Status;
1866 }
1867
1868 /**
1869 Read a directory entry at a time on an UDF volume.
1870
1871 @param[in] BlockIo BlockIo interface.
1872 @param[in] DiskIo DiskIo interface.
1873 @param[in] Volume UDF volume information structure.
1874 @param[in] ParentIcb ICB of the parent file.
1875 @param[in] FileEntryData FE/EFE of the parent file.
1876 @param[in, out] ReadDirInfo Next read directory listing structure
1877 information.
1878 @param[out] FoundFid File Identifier Descriptor pointer.
1879
1880 @retval EFI_SUCCESS Directory entry read.
1881 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1882 @retval EFI_NO_MEDIA The device has no media.
1883 @retval EFI_DEVICE_ERROR The device reported an error.
1884 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1885 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1886 resources.
1887
1888 **/
1889 EFI_STATUS
1890 ReadDirectoryEntry (
1891 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1892 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1893 IN UDF_VOLUME_INFO *Volume,
1894 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
1895 IN VOID *FileEntryData,
1896 IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,
1897 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid
1898 )
1899 {
1900 EFI_STATUS Status;
1901 UDF_READ_FILE_INFO ReadFileInfo;
1902 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
1903
1904 if (ReadDirInfo->DirectoryData == NULL) {
1905 //
1906 // The directory's recorded data has not been read yet. So let's cache it
1907 // into memory and the next calls won't need to read it again.
1908 //
1909 ReadFileInfo.Flags = ReadFileAllocateAndRead;
1910
1911 Status = ReadFile (
1912 BlockIo,
1913 DiskIo,
1914 Volume,
1915 ParentIcb,
1916 FileEntryData,
1917 &ReadFileInfo
1918 );
1919 if (EFI_ERROR (Status)) {
1920 return Status;
1921 }
1922
1923 //
1924 // Fill in ReadDirInfo structure with the read directory's data information.
1925 //
1926 ReadDirInfo->DirectoryData = ReadFileInfo.FileData;
1927 ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;
1928 }
1929
1930 do {
1931 if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {
1932 //
1933 // There are no longer FIDs for this directory. By returning
1934 // EFI_DEVICE_ERROR to the callee will indicate end of directory
1935 // listening.
1936 //
1937 return EFI_DEVICE_ERROR;
1938 }
1939
1940 //
1941 // Get FID for this entry.
1942 //
1943 FileIdentifierDesc = GET_FID_FROM_ADS (ReadDirInfo->DirectoryData,
1944 ReadDirInfo->FidOffset);
1945 //
1946 // Update FidOffset to point to next FID.
1947 //
1948 ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);
1949 } while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);
1950
1951 DuplicateFid (FileIdentifierDesc, FoundFid);
1952 if (*FoundFid == NULL) {
1953 return EFI_OUT_OF_RESOURCES;
1954 }
1955
1956 return EFI_SUCCESS;
1957 }
1958
1959 /**
1960 Get a filename (encoded in OSTA-compressed format) from a File Identifier
1961 Descriptor on an UDF volume.
1962
1963 @attention This is boundary function that may receive untrusted input.
1964 @attention The input is from FileSystem.
1965
1966 The File Identifier Descriptor is external input, so this routine will do
1967 basic validation for File Identifier Descriptor and report status.
1968
1969 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
1970 @param[in] CharMax The maximum number of FileName Unicode char,
1971 including terminating null char.
1972 @param[out] FileName Decoded filename.
1973
1974 @retval EFI_SUCCESS Filename decoded and read.
1975 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1976 @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
1977 decoded filename.
1978 **/
1979 EFI_STATUS
1980 GetFileNameFromFid (
1981 IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
1982 IN UINTN CharMax,
1983 OUT CHAR16 *FileName
1984 )
1985 {
1986 UINT8 *OstaCompressed;
1987 UINT8 CompressionId;
1988 UINT8 Length;
1989 UINTN Index;
1990 CHAR16 *FileNameBak;
1991
1992 if (CharMax == 0) {
1993 return EFI_BUFFER_TOO_SMALL;
1994 }
1995
1996 OstaCompressed =
1997 (UINT8 *)(
1998 (UINT8 *)FileIdentifierDesc->Data +
1999 FileIdentifierDesc->LengthOfImplementationUse
2000 );
2001
2002 CompressionId = OstaCompressed[0];
2003 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
2004 return EFI_VOLUME_CORRUPTED;
2005 }
2006
2007 FileNameBak = FileName;
2008
2009 //
2010 // Decode filename.
2011 //
2012 Length = FileIdentifierDesc->LengthOfFileIdentifier;
2013 if (CompressionId == 16) {
2014 if (((UINTN)Length >> 1) > CharMax) {
2015 return EFI_BUFFER_TOO_SMALL;
2016 }
2017 } else {
2018 if ((Length != 0) && ((UINTN)Length - 1 > CharMax)) {
2019 return EFI_BUFFER_TOO_SMALL;
2020 }
2021 }
2022
2023 for (Index = 1; Index < Length; Index++) {
2024 if (CompressionId == 16) {
2025 *FileName = OstaCompressed[Index++] << 8;
2026 } else {
2027 *FileName = 0;
2028 }
2029
2030 if (Index < Length) {
2031 *FileName |= (CHAR16)(OstaCompressed[Index]);
2032 }
2033
2034 FileName++;
2035 }
2036
2037 Index = ((UINTN)FileName - (UINTN)FileNameBak) / sizeof (CHAR16);
2038 if (Index > CharMax - 1) {
2039 Index = CharMax - 1;
2040 }
2041 FileNameBak[Index] = L'\0';
2042
2043 return EFI_SUCCESS;
2044 }
2045
2046 /**
2047 Resolve a symlink file on an UDF volume.
2048
2049 @attention This is boundary function that may receive untrusted input.
2050 @attention The input is from FileSystem.
2051
2052 The Path Component is external input, so this routine will do basic
2053 validation for Path Component and report status.
2054
2055 @param[in] BlockIo BlockIo interface.
2056 @param[in] DiskIo DiskIo interface.
2057 @param[in] Volume UDF volume information structure.
2058 @param[in] Parent Parent file.
2059 @param[in] FileEntryData FE/EFE structure pointer.
2060 @param[out] File Resolved file.
2061
2062 @retval EFI_SUCCESS Symlink file resolved.
2063 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2064 @retval EFI_NO_MEDIA The device has no media.
2065 @retval EFI_DEVICE_ERROR The device reported an error.
2066 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2067 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
2068 resources.
2069
2070 **/
2071 EFI_STATUS
2072 ResolveSymlink (
2073 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2074 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2075 IN UDF_VOLUME_INFO *Volume,
2076 IN UDF_FILE_INFO *Parent,
2077 IN VOID *FileEntryData,
2078 OUT UDF_FILE_INFO *File
2079 )
2080 {
2081 EFI_STATUS Status;
2082 UDF_READ_FILE_INFO ReadFileInfo;
2083 UINT8 *Data;
2084 UINT64 Length;
2085 UINT8 *EndData;
2086 UDF_PATH_COMPONENT *PathComp;
2087 UINT8 PathCompLength;
2088 CHAR16 FileName[UDF_FILENAME_LENGTH];
2089 CHAR16 *Char;
2090 UINTN Index;
2091 UINT8 CompressionId;
2092 UDF_FILE_INFO PreviousFile;
2093
2094 //
2095 // Symlink files on UDF volumes do not contain so much data other than
2096 // Path Components which resolves to real filenames, so it's OK to read in
2097 // all its data here -- usually the data will be inline with the FE/EFE for
2098 // lower filenames.
2099 //
2100 ReadFileInfo.Flags = ReadFileAllocateAndRead;
2101
2102 Status = ReadFile (
2103 BlockIo,
2104 DiskIo,
2105 Volume,
2106 &Parent->FileIdentifierDesc->Icb,
2107 FileEntryData,
2108 &ReadFileInfo
2109 );
2110 if (EFI_ERROR (Status)) {
2111 return Status;
2112 }
2113
2114 Length = ReadFileInfo.ReadLength;
2115
2116 Data = (UINT8 *)ReadFileInfo.FileData;
2117 EndData = Data + Length;
2118
2119 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
2120
2121 for (;;) {
2122 PathComp = (UDF_PATH_COMPONENT *)Data;
2123
2124 PathCompLength = PathComp->LengthOfComponentIdentifier;
2125
2126 switch (PathComp->ComponentType) {
2127 case 1:
2128 //
2129 // This Path Component specifies the root directory hierarchy subject to
2130 // agreement between the originator and recipient of the medium. Skip it.
2131 //
2132 // Fall through.
2133 //
2134 case 2:
2135 //
2136 // "\\." of the current directory. Read next Path Component.
2137 //
2138 goto Next_Path_Component;
2139 case 3:
2140 //
2141 // ".." (parent directory). Go to it.
2142 //
2143 CopyMem ((VOID *)FileName, L"..", 6);
2144 break;
2145 case 4:
2146 //
2147 // "." (current file). Duplicate both FE/EFE and FID of this file.
2148 //
2149 DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);
2150 if (File->FileEntry == NULL) {
2151 Status = EFI_OUT_OF_RESOURCES;
2152 goto Error_Find_File;
2153 }
2154
2155 DuplicateFid (PreviousFile.FileIdentifierDesc,
2156 &File->FileIdentifierDesc);
2157 if (File->FileIdentifierDesc == NULL) {
2158 FreePool (File->FileEntry);
2159 Status = EFI_OUT_OF_RESOURCES;
2160 goto Error_Find_File;
2161 }
2162 goto Next_Path_Component;
2163 case 5:
2164 //
2165 // This Path Component identifies an object, either a file or a
2166 // directory or an alias.
2167 //
2168 // Decode it from the compressed data in ComponentIdentifier and find
2169 // respective path.
2170 //
2171 CompressionId = PathComp->ComponentIdentifier[0];
2172 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
2173 return EFI_VOLUME_CORRUPTED;
2174 }
2175
2176 Char = FileName;
2177 for (Index = 1; Index < PathCompLength; Index++) {
2178 if (CompressionId == 16) {
2179 *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +
2180 Index) << 8;
2181 Index++;
2182 } else {
2183 if (Index > ARRAY_SIZE (FileName)) {
2184 return EFI_UNSUPPORTED;
2185 }
2186 *Char = 0;
2187 }
2188
2189 if (Index < Length) {
2190 *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));
2191 }
2192
2193 Char++;
2194 }
2195
2196 Index = ((UINTN)Char - (UINTN)FileName) / sizeof (CHAR16);
2197 if (Index > ARRAY_SIZE (FileName) - 1) {
2198 Index = ARRAY_SIZE (FileName) - 1;
2199 }
2200 FileName[Index] = L'\0';
2201 break;
2202 }
2203
2204 //
2205 // Find file from the read filename in symlink's file data.
2206 //
2207 Status = InternalFindFile (
2208 BlockIo,
2209 DiskIo,
2210 Volume,
2211 FileName,
2212 &PreviousFile,
2213 NULL,
2214 File
2215 );
2216 if (EFI_ERROR (Status)) {
2217 goto Error_Find_File;
2218 }
2219
2220 Next_Path_Component:
2221 Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;
2222 if (Data >= EndData) {
2223 break;
2224 }
2225
2226 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
2227 sizeof (UDF_FILE_INFO)) != 0) {
2228 CleanupFileInformation (&PreviousFile);
2229 }
2230
2231 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
2232 }
2233
2234 //
2235 // Unmap the symlink file.
2236 //
2237 FreePool (ReadFileInfo.FileData);
2238
2239 return EFI_SUCCESS;
2240
2241 Error_Find_File:
2242 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
2243 sizeof (UDF_FILE_INFO)) != 0) {
2244 CleanupFileInformation (&PreviousFile);
2245 }
2246
2247 FreePool (ReadFileInfo.FileData);
2248
2249 return Status;
2250 }
2251
2252 /**
2253 Clean up in-memory UDF file information.
2254
2255 @param[in] File File information pointer.
2256
2257 **/
2258 VOID
2259 CleanupFileInformation (
2260 IN UDF_FILE_INFO *File
2261 )
2262 {
2263 if (File->FileEntry != NULL) {
2264 FreePool (File->FileEntry);
2265 }
2266 if (File->FileIdentifierDesc != NULL) {
2267 FreePool ((VOID *)File->FileIdentifierDesc);
2268 }
2269
2270 ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));
2271 }
2272
2273 /**
2274 Find a file from its absolute path on an UDF volume.
2275
2276 @param[in] BlockIo BlockIo interface.
2277 @param[in] DiskIo DiskIo interface.
2278 @param[in] Volume UDF volume information structure.
2279 @param[in] File File information structure.
2280 @param[out] Size Size of the file.
2281
2282 @retval EFI_SUCCESS File size calculated and set in Size.
2283 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2284 @retval EFI_NO_MEDIA The device has no media.
2285 @retval EFI_DEVICE_ERROR The device reported an error.
2286 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2287 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2288 resources.
2289
2290 **/
2291 EFI_STATUS
2292 GetFileSize (
2293 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2294 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2295 IN UDF_VOLUME_INFO *Volume,
2296 IN UDF_FILE_INFO *File,
2297 OUT UINT64 *Size
2298 )
2299 {
2300 EFI_STATUS Status;
2301 UDF_READ_FILE_INFO ReadFileInfo;
2302
2303 ReadFileInfo.Flags = ReadFileGetFileSize;
2304
2305 Status = ReadFile (
2306 BlockIo,
2307 DiskIo,
2308 Volume,
2309 &File->FileIdentifierDesc->Icb,
2310 File->FileEntry,
2311 &ReadFileInfo
2312 );
2313 if (EFI_ERROR (Status)) {
2314 return Status;
2315 }
2316
2317 *Size = ReadFileInfo.ReadLength;
2318
2319 return EFI_SUCCESS;
2320 }
2321
2322 /**
2323 Set information about a file on an UDF volume.
2324
2325 @param[in] File File pointer.
2326 @param[in] FileSize Size of the file.
2327 @param[in] FileName Filename of the file.
2328 @param[in, out] BufferSize Size of the returned file infomation.
2329 @param[out] Buffer Data of the returned file information.
2330
2331 @retval EFI_SUCCESS File information set.
2332 @retval EFI_NO_MEDIA The device has no media.
2333 @retval EFI_DEVICE_ERROR The device reported an error.
2334 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2335 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2336 resources.
2337
2338 **/
2339 EFI_STATUS
2340 SetFileInfo (
2341 IN UDF_FILE_INFO *File,
2342 IN UINT64 FileSize,
2343 IN CHAR16 *FileName,
2344 IN OUT UINTN *BufferSize,
2345 OUT VOID *Buffer
2346 )
2347 {
2348 UINTN FileInfoLength;
2349 EFI_FILE_INFO *FileInfo;
2350 UDF_FILE_ENTRY *FileEntry;
2351 UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
2352 UDF_DESCRIPTOR_TAG *DescriptorTag;
2353
2354 //
2355 // Calculate the needed size for the EFI_FILE_INFO structure.
2356 //
2357 FileInfoLength = sizeof (EFI_FILE_INFO) + ((FileName != NULL) ?
2358 StrSize (FileName) :
2359 sizeof (CHAR16));
2360 if (*BufferSize < FileInfoLength) {
2361 //
2362 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2363 //
2364 *BufferSize = FileInfoLength;
2365 return EFI_BUFFER_TOO_SMALL;
2366 }
2367
2368 //
2369 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2370 // Now, fill it in with all necessary information about the file.
2371 //
2372 FileInfo = (EFI_FILE_INFO *)Buffer;
2373 FileInfo->Size = FileInfoLength;
2374 FileInfo->Attribute &= ~EFI_FILE_VALID_ATTR;
2375 FileInfo->Attribute |= EFI_FILE_READ_ONLY;
2376
2377 if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {
2378 FileInfo->Attribute |= EFI_FILE_DIRECTORY;
2379 } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {
2380 FileInfo->Attribute |= EFI_FILE_ARCHIVE;
2381 }
2382
2383 if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {
2384 FileInfo->Attribute |= EFI_FILE_HIDDEN;
2385 }
2386
2387 DescriptorTag = File->FileEntry;
2388
2389 if (DescriptorTag->TagIdentifier == UdfFileEntry) {
2390 FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;
2391
2392 //
2393 // Check if FE has the system attribute set.
2394 //
2395 if (FileEntry->IcbTag.Flags & (1 << 10)) {
2396 FileInfo->Attribute |= EFI_FILE_SYSTEM;
2397 }
2398
2399 FileInfo->FileSize = FileSize;
2400 FileInfo->PhysicalSize = FileSize;
2401
2402 FileInfo->CreateTime.Year = FileEntry->AccessTime.Year;
2403 FileInfo->CreateTime.Month = FileEntry->AccessTime.Month;
2404 FileInfo->CreateTime.Day = FileEntry->AccessTime.Day;
2405 FileInfo->CreateTime.Hour = FileEntry->AccessTime.Hour;
2406 FileInfo->CreateTime.Minute = FileEntry->AccessTime.Second;
2407 FileInfo->CreateTime.Second = FileEntry->AccessTime.Second;
2408 FileInfo->CreateTime.Nanosecond =
2409 FileEntry->AccessTime.HundredsOfMicroseconds;
2410
2411 FileInfo->LastAccessTime.Year =
2412 FileEntry->AccessTime.Year;
2413 FileInfo->LastAccessTime.Month =
2414 FileEntry->AccessTime.Month;
2415 FileInfo->LastAccessTime.Day =
2416 FileEntry->AccessTime.Day;
2417 FileInfo->LastAccessTime.Hour =
2418 FileEntry->AccessTime.Hour;
2419 FileInfo->LastAccessTime.Minute =
2420 FileEntry->AccessTime.Minute;
2421 FileInfo->LastAccessTime.Second =
2422 FileEntry->AccessTime.Second;
2423 FileInfo->LastAccessTime.Nanosecond =
2424 FileEntry->AccessTime.HundredsOfMicroseconds;
2425 } else if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
2426 ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;
2427
2428 //
2429 // Check if EFE has the system attribute set.
2430 //
2431 if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {
2432 FileInfo->Attribute |= EFI_FILE_SYSTEM;
2433 }
2434
2435 FileInfo->FileSize = FileSize;
2436 FileInfo->PhysicalSize = FileSize;
2437
2438 FileInfo->CreateTime.Year = ExtendedFileEntry->CreationTime.Year;
2439 FileInfo->CreateTime.Month = ExtendedFileEntry->CreationTime.Month;
2440 FileInfo->CreateTime.Day = ExtendedFileEntry->CreationTime.Day;
2441 FileInfo->CreateTime.Hour = ExtendedFileEntry->CreationTime.Hour;
2442 FileInfo->CreateTime.Minute = ExtendedFileEntry->CreationTime.Second;
2443 FileInfo->CreateTime.Second = ExtendedFileEntry->CreationTime.Second;
2444 FileInfo->CreateTime.Nanosecond =
2445 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
2446
2447 FileInfo->LastAccessTime.Year =
2448 ExtendedFileEntry->AccessTime.Year;
2449 FileInfo->LastAccessTime.Month =
2450 ExtendedFileEntry->AccessTime.Month;
2451 FileInfo->LastAccessTime.Day =
2452 ExtendedFileEntry->AccessTime.Day;
2453 FileInfo->LastAccessTime.Hour =
2454 ExtendedFileEntry->AccessTime.Hour;
2455 FileInfo->LastAccessTime.Minute =
2456 ExtendedFileEntry->AccessTime.Minute;
2457 FileInfo->LastAccessTime.Second =
2458 ExtendedFileEntry->AccessTime.Second;
2459 FileInfo->LastAccessTime.Nanosecond =
2460 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
2461 }
2462
2463 FileInfo->CreateTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
2464 FileInfo->CreateTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
2465 FileInfo->LastAccessTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
2466 FileInfo->LastAccessTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
2467
2468 CopyMem ((VOID *)&FileInfo->ModificationTime,
2469 (VOID *)&FileInfo->LastAccessTime,
2470 sizeof (EFI_TIME));
2471
2472 if (FileName != NULL) {
2473 StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);
2474 } else {
2475 FileInfo->FileName[0] = '\0';
2476 }
2477
2478 *BufferSize = FileInfoLength;
2479
2480 return EFI_SUCCESS;
2481 }
2482
2483 /**
2484 Get volume and free space size information of an UDF volume.
2485
2486 @param[in] BlockIo BlockIo interface.
2487 @param[in] DiskIo DiskIo interface.
2488 @param[in] Volume UDF volume information structure.
2489 @param[out] VolumeSize Volume size.
2490 @param[out] FreeSpaceSize Free space size.
2491
2492 @retval EFI_SUCCESS Volume and free space size calculated.
2493 @retval EFI_NO_MEDIA The device has no media.
2494 @retval EFI_DEVICE_ERROR The device reported an error.
2495 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2496 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
2497 calculated due to lack of resources.
2498
2499 **/
2500 EFI_STATUS
2501 GetVolumeSize (
2502 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2503 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2504 IN UDF_VOLUME_INFO *Volume,
2505 OUT UINT64 *VolumeSize,
2506 OUT UINT64 *FreeSpaceSize
2507 )
2508 {
2509 EFI_STATUS Status;
2510 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
2511 UDF_EXTENT_AD *ExtentAd;
2512 UINT64 Lsn;
2513 UINT32 LogicalBlockSize;
2514 UDF_LOGICAL_VOLUME_INTEGRITY *LogicalVolInt;
2515 UDF_DESCRIPTOR_TAG *DescriptorTag;
2516 UINTN Index;
2517 UINTN Length;
2518 UINT32 LsnsNo;
2519
2520 LogicalVolDesc = &Volume->LogicalVolDesc;
2521
2522 ExtentAd = &LogicalVolDesc->IntegritySequenceExtent;
2523
2524 if (ExtentAd->ExtentLength == 0) {
2525 return EFI_VOLUME_CORRUPTED;
2526 }
2527
2528 LogicalVolInt = AllocatePool (ExtentAd->ExtentLength);
2529 if (LogicalVolInt == NULL) {
2530 return EFI_OUT_OF_RESOURCES;
2531 }
2532
2533 //
2534 // Get location of Logical Volume Integrity Descriptor
2535 //
2536 Lsn = (UINT64)ExtentAd->ExtentLocation - Volume->MainVdsStartLocation;
2537
2538 LogicalBlockSize = LogicalVolDesc->LogicalBlockSize;
2539
2540 //
2541 // Read disk block
2542 //
2543 Status = DiskIo->ReadDisk (
2544 DiskIo,
2545 BlockIo->Media->MediaId,
2546 MultU64x32 (Lsn, LogicalBlockSize),
2547 ExtentAd->ExtentLength,
2548 LogicalVolInt
2549 );
2550 if (EFI_ERROR (Status)) {
2551 goto Out_Free;
2552 }
2553
2554 DescriptorTag = &LogicalVolInt->DescriptorTag;
2555
2556 //
2557 // Check if read block is a Logical Volume Integrity Descriptor
2558 //
2559 if (DescriptorTag->TagIdentifier != UdfLogicalVolumeIntegrityDescriptor) {
2560 Status = EFI_VOLUME_CORRUPTED;
2561 goto Out_Free;
2562 }
2563
2564 *VolumeSize = 0;
2565 *FreeSpaceSize = 0;
2566
2567 Length = LogicalVolInt->NumberOfPartitions;
2568 for (Index = 0; Index < Length; Index += sizeof (UINT32)) {
2569 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
2570 //
2571 // Check if size is not specified
2572 //
2573 if (LsnsNo == 0xFFFFFFFFUL) {
2574 continue;
2575 }
2576 //
2577 // Accumulate free space size
2578 //
2579 *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
2580 }
2581
2582 Length = LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2;
2583 for (; Index < Length; Index += sizeof (UINT32)) {
2584 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
2585 //
2586 // Check if size is not specified
2587 //
2588 if (LsnsNo == 0xFFFFFFFFUL) {
2589 continue;
2590 }
2591 //
2592 // Accumulate used volume space
2593 //
2594 *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
2595 }
2596
2597 Status = EFI_SUCCESS;
2598
2599 Out_Free:
2600 //
2601 // Free Logical Volume Integrity Descriptor
2602 //
2603 FreePool (LogicalVolInt);
2604
2605 return Status;
2606 }
2607
2608 /**
2609 Seek a file and read its data into memory on an UDF volume.
2610
2611 @param[in] BlockIo BlockIo interface.
2612 @param[in] DiskIo DiskIo interface.
2613 @param[in] Volume UDF volume information structure.
2614 @param[in] File File information structure.
2615 @param[in] FileSize Size of the file.
2616 @param[in, out] FilePosition File position.
2617 @param[in, out] Buffer File data.
2618 @param[in, out] BufferSize Read size.
2619
2620 @retval EFI_SUCCESS File seeked and read.
2621 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2622 @retval EFI_NO_MEDIA The device has no media.
2623 @retval EFI_DEVICE_ERROR The device reported an error.
2624 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2625 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2626 of resources.
2627
2628 **/
2629 EFI_STATUS
2630 ReadFileData (
2631 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2632 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2633 IN UDF_VOLUME_INFO *Volume,
2634 IN UDF_FILE_INFO *File,
2635 IN UINT64 FileSize,
2636 IN OUT UINT64 *FilePosition,
2637 IN OUT VOID *Buffer,
2638 IN OUT UINT64 *BufferSize
2639 )
2640 {
2641 EFI_STATUS Status;
2642 UDF_READ_FILE_INFO ReadFileInfo;
2643
2644 ReadFileInfo.Flags = ReadFileSeekAndRead;
2645 ReadFileInfo.FilePosition = *FilePosition;
2646 ReadFileInfo.FileData = Buffer;
2647 ReadFileInfo.FileDataSize = *BufferSize;
2648 ReadFileInfo.FileSize = FileSize;
2649
2650 Status = ReadFile (
2651 BlockIo,
2652 DiskIo,
2653 Volume,
2654 &File->FileIdentifierDesc->Icb,
2655 File->FileEntry,
2656 &ReadFileInfo
2657 );
2658 if (EFI_ERROR (Status)) {
2659 return Status;
2660 }
2661
2662 *BufferSize = ReadFileInfo.FileDataSize;
2663 *FilePosition = ReadFileInfo.FilePosition;
2664
2665 return EFI_SUCCESS;
2666 }
2667
2668 /**
2669 Check if ControllerHandle supports an UDF file system.
2670
2671 @param[in] This Protocol instance pointer.
2672 @param[in] ControllerHandle Handle of device to test.
2673
2674 @retval EFI_SUCCESS UDF file system found.
2675 @retval EFI_UNSUPPORTED UDF file system not found.
2676
2677 **/
2678 EFI_STATUS
2679 SupportUdfFileSystem (
2680 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2681 IN EFI_HANDLE ControllerHandle
2682 )
2683 {
2684 EFI_STATUS Status;
2685 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2686 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
2687 EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
2688 EFI_GUID *VendorDefinedGuid;
2689
2690 //
2691 // Open Device Path protocol on ControllerHandle
2692 //
2693 Status = gBS->OpenProtocol (
2694 ControllerHandle,
2695 &gEfiDevicePathProtocolGuid,
2696 (VOID **)&DevicePath,
2697 This->DriverBindingHandle,
2698 ControllerHandle,
2699 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2700 );
2701 if (EFI_ERROR (Status)) {
2702 return EFI_UNSUPPORTED;
2703 }
2704
2705 Status = EFI_UNSUPPORTED;
2706
2707 //
2708 // Get last Device Path node
2709 //
2710 LastDevicePathNode = NULL;
2711 DevicePathNode = DevicePath;
2712 while (!IsDevicePathEnd (DevicePathNode)) {
2713 LastDevicePathNode = DevicePathNode;
2714 DevicePathNode = NextDevicePathNode (DevicePathNode);
2715 }
2716 //
2717 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2718 // of an UDF file system.
2719 //
2720 if (LastDevicePathNode != NULL &&
2721 DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
2722 DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP) {
2723 VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +
2724 OFFSET_OF (VENDOR_DEVICE_PATH, Guid));
2725 if (CompareGuid (VendorDefinedGuid, &gUdfDevPathGuid)) {
2726 Status = EFI_SUCCESS;
2727 }
2728 }
2729
2730 //
2731 // Close Device Path protocol on ControllerHandle
2732 //
2733 gBS->CloseProtocol (
2734 ControllerHandle,
2735 &gEfiDevicePathProtocolGuid,
2736 This->DriverBindingHandle,
2737 ControllerHandle
2738 );
2739
2740 return Status;
2741 }