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