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