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