MdeModulePkg/UDF: Fix creation of UDF logical partition
[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 if (RecordingFlags == LongAdsSequence) {
752 return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad);
753 } else if (RecordingFlags == ShortAdsSequence) {
754 return GetShortAdLsn (
755 Volume,
756 GetPdFromLongAd (Volume, ParentIcb),
757 (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad
758 );
759 }
760
761 return 0;
762 }
763
764 /**
765 Return offset + length of a given indirect Allocation Descriptor (AED).
766
767 @param[in] BlockIo BlockIo interface.
768 @param[in] DiskIo DiskIo interface.
769 @param[in] Volume Volume information pointer.
770 @param[in] ParentIcb Long Allocation Descriptor pointer.
771 @param[in] RecordingFlags Flag to indicate the type of descriptor.
772 @param[in] Ad Allocation Descriptor pointer.
773 @param[out] Offset Offset of a given indirect Allocation
774 Descriptor.
775 @param[out] Length Length of a given indirect Allocation
776 Descriptor.
777
778 @retval EFI_SUCCESS The offset and length were returned.
779 @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due
780 to lack of resources.
781 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
782 @retval other The offset and length were not returned.
783
784 **/
785 EFI_STATUS
786 GetAedAdsOffset (
787 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
788 IN EFI_DISK_IO_PROTOCOL *DiskIo,
789 IN UDF_VOLUME_INFO *Volume,
790 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
791 IN UDF_FE_RECORDING_FLAGS RecordingFlags,
792 IN VOID *Ad,
793 OUT UINT64 *Offset,
794 OUT UINT64 *Length
795 )
796 {
797 EFI_STATUS Status;
798 UINT32 ExtentLength;
799 UINT64 Lsn;
800 VOID *Data;
801 UINT32 LogicalBlockSize;
802 UDF_ALLOCATION_EXTENT_DESCRIPTOR *AllocExtDesc;
803 UDF_DESCRIPTOR_TAG *DescriptorTag;
804
805 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
806 Lsn = GetAllocationDescriptorLsn (RecordingFlags,
807 Volume,
808 ParentIcb,
809 Ad);
810
811 Data = AllocatePool (ExtentLength);
812 if (Data == NULL) {
813 return EFI_OUT_OF_RESOURCES;
814 }
815
816 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
817
818 //
819 // Read extent.
820 //
821 Status = DiskIo->ReadDisk (
822 DiskIo,
823 BlockIo->Media->MediaId,
824 MultU64x32 (Lsn, LogicalBlockSize),
825 ExtentLength,
826 Data
827 );
828 if (EFI_ERROR (Status)) {
829 goto Exit;
830 }
831
832 AllocExtDesc = (UDF_ALLOCATION_EXTENT_DESCRIPTOR *)Data;
833
834 DescriptorTag = &AllocExtDesc->DescriptorTag;
835
836 //
837 // Check if read extent contains a valid tag identifier for AED.
838 //
839 if (DescriptorTag->TagIdentifier != UdfAllocationExtentDescriptor) {
840 Status = EFI_VOLUME_CORRUPTED;
841 goto Exit;
842 }
843
844 //
845 // Get AED's block offset and its length.
846 //
847 *Offset = MultU64x32 (Lsn, LogicalBlockSize) +
848 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR);
849 *Length = AllocExtDesc->LengthOfAllocationDescriptors;
850
851 Exit:
852 FreePool (Data);
853
854 return Status;
855 }
856
857 /**
858 Read Allocation Extent Descriptor into memory.
859
860 @param[in] BlockIo BlockIo interface.
861 @param[in] DiskIo DiskIo interface.
862 @param[in] Volume Volume information pointer.
863 @param[in] ParentIcb Long Allocation Descriptor pointer.
864 @param[in] RecordingFlags Flag to indicate the type of descriptor.
865 @param[in] Ad Allocation Descriptor pointer.
866 @param[out] Data Buffer that contains the Allocation Extent
867 Descriptor.
868 @param[out] Length Length of Data.
869
870 @retval EFI_SUCCESS The Allocation Extent Descriptor was read.
871 @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read
872 due to lack of resources.
873 @retval other Fail to read the disk.
874
875 **/
876 EFI_STATUS
877 GetAedAdsData (
878 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
879 IN EFI_DISK_IO_PROTOCOL *DiskIo,
880 IN UDF_VOLUME_INFO *Volume,
881 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
882 IN UDF_FE_RECORDING_FLAGS RecordingFlags,
883 IN VOID *Ad,
884 OUT VOID **Data,
885 OUT UINT64 *Length
886 )
887 {
888 EFI_STATUS Status;
889 UINT64 Offset;
890
891 //
892 // Get AED's offset + length.
893 //
894 Status = GetAedAdsOffset (
895 BlockIo,
896 DiskIo,
897 Volume,
898 ParentIcb,
899 RecordingFlags,
900 Ad,
901 &Offset,
902 Length
903 );
904 if (EFI_ERROR (Status)) {
905 return Status;
906 }
907
908 //
909 // Allocate buffer to read in AED's data.
910 //
911 *Data = AllocatePool ((UINTN) (*Length));
912 if (*Data == NULL) {
913 return EFI_OUT_OF_RESOURCES;
914 }
915
916 return DiskIo->ReadDisk (
917 DiskIo,
918 BlockIo->Media->MediaId,
919 Offset,
920 (UINTN) (*Length),
921 *Data
922 );
923 }
924
925 /**
926 Function used to serialise reads of Allocation Descriptors.
927
928 @param[in] RecordingFlags Flag to indicate the type of descriptor.
929 @param[in] Ad Allocation Descriptor pointer.
930 @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.
931 @param[in] Length Length of Buffer.
932
933 @retval EFI_SUCCESS Buffer was grown to hold the next Allocation
934 Descriptor.
935 @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.
936
937 **/
938 EFI_STATUS
939 GrowUpBufferToNextAd (
940 IN UDF_FE_RECORDING_FLAGS RecordingFlags,
941 IN VOID *Ad,
942 IN OUT VOID **Buffer,
943 IN UINT64 Length
944 )
945 {
946 UINT32 ExtentLength;
947
948 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
949
950 if (*Buffer == NULL) {
951 *Buffer = AllocatePool (ExtentLength);
952 if (*Buffer == NULL) {
953 return EFI_OUT_OF_RESOURCES;
954 }
955 } else {
956 *Buffer = ReallocatePool ((UINTN) Length, (UINTN) (Length + ExtentLength), *Buffer);
957 if (*Buffer == NULL) {
958 return EFI_OUT_OF_RESOURCES;
959 }
960 }
961
962 return EFI_SUCCESS;
963 }
964
965 /**
966 Read data or size of either a File Entry or an Extended File Entry.
967
968 @param[in] BlockIo BlockIo interface.
969 @param[in] DiskIo DiskIo interface.
970 @param[in] Volume Volume information pointer.
971 @param[in] ParentIcb Long Allocation Descriptor pointer.
972 @param[in] FileEntryData FE/EFE structure pointer.
973 @param[in, out] ReadFileInfo Read file information pointer.
974
975 @retval EFI_SUCCESS Data or size of a FE/EFE was read.
976 @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to
977 lack of resources.
978 @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is
979 invalid.
980 @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData
981 is not supported.
982 @retval other Data or size of a FE/EFE was not read.
983
984 **/
985 EFI_STATUS
986 ReadFile (
987 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
988 IN EFI_DISK_IO_PROTOCOL *DiskIo,
989 IN UDF_VOLUME_INFO *Volume,
990 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
991 IN VOID *FileEntryData,
992 IN OUT UDF_READ_FILE_INFO *ReadFileInfo
993 )
994 {
995 EFI_STATUS Status;
996 UINT32 LogicalBlockSize;
997 VOID *Data;
998 UINT64 Length;
999 VOID *Ad;
1000 UINT64 AdOffset;
1001 UINT64 Lsn;
1002 BOOLEAN DoFreeAed;
1003 UINT64 FilePosition;
1004 UINT64 Offset;
1005 UINT64 DataOffset;
1006 UINT64 BytesLeft;
1007 UINT64 DataLength;
1008 BOOLEAN FinishedSeeking;
1009 UINT32 ExtentLength;
1010 UDF_FE_RECORDING_FLAGS RecordingFlags;
1011
1012 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
1013 DoFreeAed = FALSE;
1014
1015 //
1016 // set BytesLeft to suppress incorrect compiler/analyzer warnings
1017 //
1018 BytesLeft = 0;
1019 DataOffset = 0;
1020 FilePosition = 0;
1021 FinishedSeeking = FALSE;
1022 Data = NULL;
1023
1024 switch (ReadFileInfo->Flags) {
1025 case ReadFileGetFileSize:
1026 case ReadFileAllocateAndRead:
1027 //
1028 // Initialise ReadFileInfo structure for either getting file size, or
1029 // reading file's recorded data.
1030 //
1031 ReadFileInfo->ReadLength = 0;
1032 ReadFileInfo->FileData = NULL;
1033 break;
1034 case ReadFileSeekAndRead:
1035 //
1036 // About to seek a file and/or read its data.
1037 //
1038 Length = ReadFileInfo->FileSize - ReadFileInfo->FilePosition;
1039 if (ReadFileInfo->FileDataSize > Length) {
1040 //
1041 // About to read beyond the EOF -- truncate it.
1042 //
1043 ReadFileInfo->FileDataSize = Length;
1044 }
1045
1046 //
1047 // Initialise data to start seeking and/or reading a file.
1048 //
1049 BytesLeft = ReadFileInfo->FileDataSize;
1050 DataOffset = 0;
1051 FilePosition = 0;
1052 FinishedSeeking = FALSE;
1053
1054 break;
1055 }
1056
1057 RecordingFlags = GET_FE_RECORDING_FLAGS (FileEntryData);
1058 switch (RecordingFlags) {
1059 case InlineData:
1060 //
1061 // There are no extents for this FE/EFE. All data is inline.
1062 //
1063 GetFileEntryData (FileEntryData, &Data, &Length);
1064
1065 if (ReadFileInfo->Flags == ReadFileGetFileSize) {
1066 ReadFileInfo->ReadLength = Length;
1067 } else if (ReadFileInfo->Flags == ReadFileAllocateAndRead) {
1068 //
1069 // Allocate buffer for starting read data.
1070 //
1071 ReadFileInfo->FileData = AllocatePool ((UINTN) Length);
1072 if (ReadFileInfo->FileData == NULL) {
1073 return EFI_OUT_OF_RESOURCES;
1074 }
1075
1076 //
1077 // Read all inline data into ReadFileInfo->FileData
1078 //
1079 CopyMem (ReadFileInfo->FileData, Data, (UINTN) Length);
1080 ReadFileInfo->ReadLength = Length;
1081 } else if (ReadFileInfo->Flags == ReadFileSeekAndRead) {
1082 //
1083 // If FilePosition is non-zero, seek file to FilePosition, read
1084 // FileDataSize bytes and then updates FilePosition.
1085 //
1086 CopyMem (
1087 ReadFileInfo->FileData,
1088 (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition),
1089 (UINTN) ReadFileInfo->FileDataSize
1090 );
1091
1092 ReadFileInfo->FilePosition += ReadFileInfo->FileDataSize;
1093 } else {
1094 ASSERT (FALSE);
1095 return EFI_INVALID_PARAMETER;
1096 }
1097
1098 Status = EFI_SUCCESS;
1099 break;
1100
1101 case LongAdsSequence:
1102 case ShortAdsSequence:
1103 //
1104 // This FE/EFE contains a run of Allocation Descriptors. Get data + size
1105 // for start reading them out.
1106 //
1107 GetAdsInformation (FileEntryData, &Data, &Length);
1108 AdOffset = 0;
1109
1110 for (;;) {
1111 //
1112 // Read AD.
1113 //
1114 Status = GetAllocationDescriptor (
1115 RecordingFlags,
1116 Data,
1117 &AdOffset,
1118 Length,
1119 &Ad
1120 );
1121 if (Status == EFI_DEVICE_ERROR) {
1122 Status = EFI_SUCCESS;
1123 goto Done;
1124 }
1125
1126 //
1127 // Check if AD is an indirect AD. If so, read Allocation Extent
1128 // Descriptor and its extents (ADs).
1129 //
1130 if (GET_EXTENT_FLAGS (RecordingFlags, Ad) == ExtentIsNextExtent) {
1131 if (!DoFreeAed) {
1132 DoFreeAed = TRUE;
1133 } else {
1134 FreePool (Data);
1135 }
1136
1137 Status = GetAedAdsData (
1138 BlockIo,
1139 DiskIo,
1140 Volume,
1141 ParentIcb,
1142 RecordingFlags,
1143 Ad,
1144 &Data,
1145 &Length
1146 );
1147 if (EFI_ERROR (Status)) {
1148 goto Error_Get_Aed;
1149 }
1150 ASSERT (Data != NULL);
1151
1152 AdOffset = 0;
1153 continue;
1154 }
1155
1156 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
1157
1158 Lsn = GetAllocationDescriptorLsn (RecordingFlags,
1159 Volume,
1160 ParentIcb,
1161 Ad);
1162
1163 switch (ReadFileInfo->Flags) {
1164 case ReadFileGetFileSize:
1165 ReadFileInfo->ReadLength += ExtentLength;
1166 break;
1167 case ReadFileAllocateAndRead:
1168 //
1169 // Increase FileData (if necessary) to read next extent.
1170 //
1171 Status = GrowUpBufferToNextAd (
1172 RecordingFlags,
1173 Ad,
1174 &ReadFileInfo->FileData,
1175 ReadFileInfo->ReadLength
1176 );
1177 if (EFI_ERROR (Status)) {
1178 goto Error_Alloc_Buffer_To_Next_Ad;
1179 }
1180
1181 //
1182 // Read extent's data into FileData.
1183 //
1184 Status = DiskIo->ReadDisk (
1185 DiskIo,
1186 BlockIo->Media->MediaId,
1187 MultU64x32 (Lsn, LogicalBlockSize),
1188 ExtentLength,
1189 (VOID *)((UINT8 *)ReadFileInfo->FileData +
1190 ReadFileInfo->ReadLength)
1191 );
1192 if (EFI_ERROR (Status)) {
1193 goto Error_Read_Disk_Blk;
1194 }
1195
1196 ReadFileInfo->ReadLength += ExtentLength;
1197 break;
1198 case ReadFileSeekAndRead:
1199 //
1200 // Seek file first before reading in its data.
1201 //
1202 if (FinishedSeeking) {
1203 Offset = 0;
1204 goto Skip_File_Seek;
1205 }
1206
1207 if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) {
1208 FilePosition += ExtentLength;
1209 goto Skip_Ad;
1210 }
1211
1212 if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) {
1213 Offset = ReadFileInfo->FilePosition - FilePosition;
1214 } else {
1215 Offset = 0;
1216 }
1217
1218 //
1219 // Done with seeking file. Start reading its data.
1220 //
1221 FinishedSeeking = TRUE;
1222
1223 Skip_File_Seek:
1224 //
1225 // Make sure we don't read more data than really wanted.
1226 //
1227 if (ExtentLength - Offset > BytesLeft) {
1228 DataLength = BytesLeft;
1229 } else {
1230 DataLength = ExtentLength - Offset;
1231 }
1232
1233 //
1234 // Read extent's data into FileData.
1235 //
1236 Status = DiskIo->ReadDisk (
1237 DiskIo,
1238 BlockIo->Media->MediaId,
1239 Offset + MultU64x32 (Lsn, LogicalBlockSize),
1240 (UINTN) DataLength,
1241 (VOID *)((UINT8 *)ReadFileInfo->FileData +
1242 DataOffset)
1243 );
1244 if (EFI_ERROR (Status)) {
1245 goto Error_Read_Disk_Blk;
1246 }
1247
1248 //
1249 // Update current file's position.
1250 //
1251 DataOffset += DataLength;
1252 ReadFileInfo->FilePosition += DataLength;
1253
1254 BytesLeft -= DataLength;
1255 if (BytesLeft == 0) {
1256 //
1257 // There is no more file data to read.
1258 //
1259 Status = EFI_SUCCESS;
1260 goto Done;
1261 }
1262
1263 break;
1264 }
1265
1266 Skip_Ad:
1267 //
1268 // Point to the next AD (extent).
1269 //
1270 AdOffset += AD_LENGTH (RecordingFlags);
1271 }
1272
1273 break;
1274 case ExtendedAdsSequence:
1275 // FIXME: Not supported. Got no volume with it, yet.
1276 ASSERT (FALSE);
1277 Status = EFI_UNSUPPORTED;
1278 break;
1279
1280 default:
1281 //
1282 // A flag value reserved by the ECMA-167 standard (3rd Edition - June
1283 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
1284 //
1285 Status = EFI_UNSUPPORTED;
1286 break;
1287 }
1288
1289 Done:
1290 if (DoFreeAed) {
1291 FreePool (Data);
1292 }
1293
1294 return Status;
1295
1296 Error_Read_Disk_Blk:
1297 Error_Alloc_Buffer_To_Next_Ad:
1298 if (ReadFileInfo->Flags != ReadFileSeekAndRead) {
1299 FreePool (ReadFileInfo->FileData);
1300 }
1301
1302 if (DoFreeAed) {
1303 FreePool (Data);
1304 }
1305
1306 Error_Get_Aed:
1307 return Status;
1308 }
1309
1310 /**
1311 Find a file by its filename from a given Parent file.
1312
1313 @param[in] BlockIo BlockIo interface.
1314 @param[in] DiskIo DiskIo interface.
1315 @param[in] Volume Volume information pointer.
1316 @param[in] FileName File name string.
1317 @param[in] Parent Parent directory file.
1318 @param[in] Icb Long Allocation Descriptor pointer.
1319 @param[out] File Found file.
1320
1321 @retval EFI_SUCCESS The file was found.
1322 @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.
1323 @retval EFI_NOT_FOUND The file was not found.
1324
1325 **/
1326 EFI_STATUS
1327 InternalFindFile (
1328 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1329 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1330 IN UDF_VOLUME_INFO *Volume,
1331 IN CHAR16 *FileName,
1332 IN UDF_FILE_INFO *Parent,
1333 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
1334 OUT UDF_FILE_INFO *File
1335 )
1336 {
1337 EFI_STATUS Status;
1338 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
1339 UDF_READ_DIRECTORY_INFO ReadDirInfo;
1340 BOOLEAN Found;
1341 CHAR16 FoundFileName[UDF_FILENAME_LENGTH];
1342 VOID *CompareFileEntry;
1343
1344 //
1345 // Check if both Parent->FileIdentifierDesc and Icb are NULL.
1346 //
1347 if ((Parent->FileIdentifierDesc == NULL) && (Icb == NULL)) {
1348 return EFI_INVALID_PARAMETER;
1349 }
1350
1351 //
1352 // Check if parent file is really directory.
1353 //
1354 if (FE_ICB_FILE_TYPE (Parent->FileEntry) != UdfFileEntryDirectory) {
1355 return EFI_NOT_FOUND;
1356 }
1357
1358 //
1359 // If FileName is current file or working directory, just duplicate Parent's
1360 // FE/EFE and FID descriptors.
1361 //
1362 if (StrCmp (FileName, L".") == 0) {
1363 if (Parent->FileIdentifierDesc == NULL) {
1364 return EFI_INVALID_PARAMETER;
1365 }
1366
1367 DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);
1368 DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);
1369
1370 return EFI_SUCCESS;
1371 }
1372
1373 //
1374 // Start directory listing.
1375 //
1376 ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
1377 Found = FALSE;
1378
1379 for (;;) {
1380 Status = ReadDirectoryEntry (
1381 BlockIo,
1382 DiskIo,
1383 Volume,
1384 (Parent->FileIdentifierDesc != NULL) ?
1385 &Parent->FileIdentifierDesc->Icb :
1386 Icb,
1387 Parent->FileEntry,
1388 &ReadDirInfo,
1389 &FileIdentifierDesc
1390 );
1391 if (EFI_ERROR (Status)) {
1392 if (Status == EFI_DEVICE_ERROR) {
1393 Status = EFI_NOT_FOUND;
1394 }
1395
1396 break;
1397 }
1398
1399 if (FileIdentifierDesc->FileCharacteristics & PARENT_FILE) {
1400 //
1401 // This FID contains the location (FE/EFE) of the parent directory of this
1402 // directory (Parent), and if FileName is either ".." or "\\", then it's
1403 // the expected FID.
1404 //
1405 if (StrCmp (FileName, L"..") == 0 || StrCmp (FileName, L"\\") == 0) {
1406 Found = TRUE;
1407 break;
1408 }
1409 } else {
1410 Status = GetFileNameFromFid (FileIdentifierDesc, FoundFileName);
1411 if (EFI_ERROR (Status)) {
1412 break;
1413 }
1414
1415 if (StrCmp (FileName, FoundFileName) == 0) {
1416 //
1417 // FID has been found. Prepare to find its respective FE/EFE.
1418 //
1419 Found = TRUE;
1420 break;
1421 }
1422 }
1423
1424 FreePool ((VOID *)FileIdentifierDesc);
1425 }
1426
1427 if (ReadDirInfo.DirectoryData != NULL) {
1428 //
1429 // Free all allocated resources for the directory listing.
1430 //
1431 FreePool (ReadDirInfo.DirectoryData);
1432 }
1433
1434 if (Found) {
1435 Status = EFI_SUCCESS;
1436
1437 File->FileIdentifierDesc = FileIdentifierDesc;
1438
1439 //
1440 // If the requested file is root directory, then the FE/EFE was already
1441 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1442 //
1443 // Otherwise, find FE/EFE from the respective FID.
1444 //
1445 if (StrCmp (FileName, L"\\") != 0) {
1446 Status = FindFileEntry (
1447 BlockIo,
1448 DiskIo,
1449 Volume,
1450 &FileIdentifierDesc->Icb,
1451 &CompareFileEntry
1452 );
1453 if (EFI_ERROR (Status)) {
1454 goto Error_Find_Fe;
1455 }
1456
1457 //
1458 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1459 //
1460 if (CompareMem ((VOID *)Parent->FileEntry, (VOID *)CompareFileEntry,
1461 Volume->FileEntrySize) != 0) {
1462 File->FileEntry = CompareFileEntry;
1463 } else {
1464 FreePool ((VOID *)FileIdentifierDesc);
1465 FreePool ((VOID *)CompareFileEntry);
1466 Status = EFI_NOT_FOUND;
1467 }
1468 }
1469 }
1470
1471 return Status;
1472
1473 Error_Find_Fe:
1474 FreePool ((VOID *)FileIdentifierDesc);
1475
1476 return Status;
1477 }
1478
1479 /**
1480 Read volume information on a medium which contains a valid UDF file system.
1481
1482 @param[in] BlockIo BlockIo interface.
1483 @param[in] DiskIo DiskIo interface.
1484 @param[out] Volume UDF volume information structure.
1485
1486 @retval EFI_SUCCESS Volume information read.
1487 @retval EFI_NO_MEDIA The device has no media.
1488 @retval EFI_DEVICE_ERROR The device reported an error.
1489 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1490 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1491
1492 **/
1493 EFI_STATUS
1494 ReadUdfVolumeInformation (
1495 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1496 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1497 OUT UDF_VOLUME_INFO *Volume
1498 )
1499 {
1500 EFI_STATUS Status;
1501
1502 //
1503 // Read all necessary UDF volume information and keep it private to the driver
1504 //
1505 Status = ReadVolumeFileStructure (
1506 BlockIo,
1507 DiskIo,
1508 Volume
1509 );
1510 if (EFI_ERROR (Status)) {
1511 return Status;
1512 }
1513
1514 //
1515 // Find File Set Descriptor
1516 //
1517 Status = FindFileSetDescriptor (BlockIo, DiskIo, Volume);
1518 if (EFI_ERROR (Status)) {
1519 return Status;
1520 }
1521
1522 return Status;
1523 }
1524
1525 /**
1526 Find the root directory on an UDF volume.
1527
1528 @param[in] BlockIo BlockIo interface.
1529 @param[in] DiskIo DiskIo interface.
1530 @param[in] Volume UDF volume information structure.
1531 @param[out] File Root directory file.
1532
1533 @retval EFI_SUCCESS Root directory found.
1534 @retval EFI_NO_MEDIA The device has no media.
1535 @retval EFI_DEVICE_ERROR The device reported an error.
1536 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1537 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1538 resources.
1539
1540 **/
1541 EFI_STATUS
1542 FindRootDirectory (
1543 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1544 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1545 IN UDF_VOLUME_INFO *Volume,
1546 OUT UDF_FILE_INFO *File
1547 )
1548 {
1549 EFI_STATUS Status;
1550 UDF_FILE_INFO Parent;
1551
1552 Status = FindFileEntry (
1553 BlockIo,
1554 DiskIo,
1555 Volume,
1556 &Volume->FileSetDesc.RootDirectoryIcb,
1557 &File->FileEntry
1558 );
1559 if (EFI_ERROR (Status)) {
1560 return Status;
1561 }
1562
1563 Parent.FileEntry = File->FileEntry;
1564 Parent.FileIdentifierDesc = NULL;
1565
1566 Status = FindFile (
1567 BlockIo,
1568 DiskIo,
1569 Volume,
1570 L"\\",
1571 NULL,
1572 &Parent,
1573 &Volume->FileSetDesc.RootDirectoryIcb,
1574 File
1575 );
1576 if (EFI_ERROR (Status)) {
1577 FreePool (File->FileEntry);
1578 }
1579
1580 return Status;
1581 }
1582
1583 /**
1584 Find either a File Entry or a Extended File Entry from a given ICB.
1585
1586 @param[in] BlockIo BlockIo interface.
1587 @param[in] DiskIo DiskIo interface.
1588 @param[in] Volume UDF volume information structure.
1589 @param[in] Icb ICB of the FID.
1590 @param[out] FileEntry File Entry or Extended File Entry.
1591
1592 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1593 @retval EFI_NO_MEDIA The device has no media.
1594 @retval EFI_DEVICE_ERROR The device reported an error.
1595 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1596 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1597 resources.
1598
1599 **/
1600 EFI_STATUS
1601 FindFileEntry (
1602 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1603 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1604 IN UDF_VOLUME_INFO *Volume,
1605 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
1606 OUT VOID **FileEntry
1607 )
1608 {
1609 EFI_STATUS Status;
1610 UINT64 Lsn;
1611 UINT32 LogicalBlockSize;
1612 UDF_DESCRIPTOR_TAG *DescriptorTag;
1613
1614 Lsn = GetLongAdLsn (Volume, Icb);
1615 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
1616
1617 *FileEntry = AllocateZeroPool (Volume->FileEntrySize);
1618 if (*FileEntry == NULL) {
1619 return EFI_OUT_OF_RESOURCES;
1620 }
1621
1622 //
1623 // Read extent.
1624 //
1625 Status = DiskIo->ReadDisk (
1626 DiskIo,
1627 BlockIo->Media->MediaId,
1628 MultU64x32 (Lsn, LogicalBlockSize),
1629 Volume->FileEntrySize,
1630 *FileEntry
1631 );
1632 if (EFI_ERROR (Status)) {
1633 goto Error_Read_Disk_Blk;
1634 }
1635
1636 DescriptorTag = *FileEntry;
1637
1638 //
1639 // Check if the read extent contains a valid Tag Identifier for the expected
1640 // FE/EFE.
1641 //
1642 if (DescriptorTag->TagIdentifier != UdfFileEntry &&
1643 DescriptorTag->TagIdentifier != UdfExtendedFileEntry) {
1644 Status = EFI_VOLUME_CORRUPTED;
1645 goto Error_Invalid_Fe;
1646 }
1647
1648 return EFI_SUCCESS;
1649
1650 Error_Invalid_Fe:
1651 Error_Read_Disk_Blk:
1652 FreePool (*FileEntry);
1653
1654 return Status;
1655 }
1656
1657 /**
1658 Find a file given its absolute path on an UDF volume.
1659
1660 @param[in] BlockIo BlockIo interface.
1661 @param[in] DiskIo DiskIo interface.
1662 @param[in] Volume UDF volume information structure.
1663 @param[in] FilePath File's absolute path.
1664 @param[in] Root Root directory file.
1665 @param[in] Parent Parent directory file.
1666 @param[in] Icb ICB of Parent.
1667 @param[out] File Found file.
1668
1669 @retval EFI_SUCCESS FilePath was found.
1670 @retval EFI_NO_MEDIA The device has no media.
1671 @retval EFI_DEVICE_ERROR The device reported an error.
1672 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1673 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
1674 resources.
1675
1676 **/
1677 EFI_STATUS
1678 FindFile (
1679 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1680 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1681 IN UDF_VOLUME_INFO *Volume,
1682 IN CHAR16 *FilePath,
1683 IN UDF_FILE_INFO *Root,
1684 IN UDF_FILE_INFO *Parent,
1685 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
1686 OUT UDF_FILE_INFO *File
1687 )
1688 {
1689 EFI_STATUS Status;
1690 CHAR16 FileName[UDF_FILENAME_LENGTH];
1691 CHAR16 *FileNamePointer;
1692 UDF_FILE_INFO PreviousFile;
1693 VOID *FileEntry;
1694
1695 Status = EFI_NOT_FOUND;
1696
1697 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
1698 while (*FilePath != L'\0') {
1699 FileNamePointer = FileName;
1700 while (*FilePath != L'\0' && *FilePath != L'\\') {
1701 *FileNamePointer++ = *FilePath++;
1702 }
1703
1704 *FileNamePointer = L'\0';
1705 if (FileName[0] == L'\0') {
1706 //
1707 // Open root directory.
1708 //
1709 if (Root == NULL) {
1710 //
1711 // There is no file found for the root directory yet. So, find only its
1712 // FID by now.
1713 //
1714 // See UdfOpenVolume() function.
1715 //
1716 Status = InternalFindFile (BlockIo,
1717 DiskIo,
1718 Volume,
1719 L"\\",
1720 &PreviousFile,
1721 Icb,
1722 File);
1723 } else {
1724 //
1725 // We've already a file pointer (Root) for the root directory. Duplicate
1726 // its FE/EFE and FID descriptors.
1727 //
1728 DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);
1729 DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);
1730 Status = EFI_SUCCESS;
1731 }
1732 } else {
1733 //
1734 // No root directory. Find filename from the current directory.
1735 //
1736 Status = InternalFindFile (BlockIo,
1737 DiskIo,
1738 Volume,
1739 FileName,
1740 &PreviousFile,
1741 Icb,
1742 File);
1743 }
1744
1745 if (EFI_ERROR (Status)) {
1746 return Status;
1747 }
1748
1749 //
1750 // If the found file is a symlink, then find its respective FE/EFE and
1751 // FID descriptors.
1752 //
1753 if (FE_ICB_FILE_TYPE (File->FileEntry) == UdfFileEntrySymlink) {
1754 FreePool ((VOID *)File->FileIdentifierDesc);
1755
1756 FileEntry = File->FileEntry;
1757
1758 Status = ResolveSymlink (BlockIo,
1759 DiskIo,
1760 Volume,
1761 &PreviousFile,
1762 FileEntry,
1763 File);
1764
1765 FreePool (FileEntry);
1766
1767 if (EFI_ERROR (Status)) {
1768 return Status;
1769 }
1770 }
1771
1772 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
1773 sizeof (UDF_FILE_INFO)) != 0) {
1774 CleanupFileInformation (&PreviousFile);
1775 }
1776
1777 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
1778 if (*FilePath != L'\0' && *FilePath == L'\\') {
1779 FilePath++;
1780 }
1781 }
1782
1783 return Status;
1784 }
1785
1786 /**
1787 Read a directory entry at a time on an UDF volume.
1788
1789 @param[in] BlockIo BlockIo interface.
1790 @param[in] DiskIo DiskIo interface.
1791 @param[in] Volume UDF volume information structure.
1792 @param[in] ParentIcb ICB of the parent file.
1793 @param[in] FileEntryData FE/EFE of the parent file.
1794 @param[in, out] ReadDirInfo Next read directory listing structure
1795 information.
1796 @param[out] FoundFid File Identifier Descriptor pointer.
1797
1798 @retval EFI_SUCCESS Directory entry read.
1799 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1800 @retval EFI_NO_MEDIA The device has no media.
1801 @retval EFI_DEVICE_ERROR The device reported an error.
1802 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1803 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1804 resources.
1805
1806 **/
1807 EFI_STATUS
1808 ReadDirectoryEntry (
1809 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1810 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1811 IN UDF_VOLUME_INFO *Volume,
1812 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
1813 IN VOID *FileEntryData,
1814 IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,
1815 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid
1816 )
1817 {
1818 EFI_STATUS Status;
1819 UDF_READ_FILE_INFO ReadFileInfo;
1820 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
1821
1822 if (ReadDirInfo->DirectoryData == NULL) {
1823 //
1824 // The directory's recorded data has not been read yet. So let's cache it
1825 // into memory and the next calls won't need to read it again.
1826 //
1827 ReadFileInfo.Flags = ReadFileAllocateAndRead;
1828
1829 Status = ReadFile (
1830 BlockIo,
1831 DiskIo,
1832 Volume,
1833 ParentIcb,
1834 FileEntryData,
1835 &ReadFileInfo
1836 );
1837 if (EFI_ERROR (Status)) {
1838 return Status;
1839 }
1840
1841 //
1842 // Fill in ReadDirInfo structure with the read directory's data information.
1843 //
1844 ReadDirInfo->DirectoryData = ReadFileInfo.FileData;
1845 ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;
1846 }
1847
1848 do {
1849 if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {
1850 //
1851 // There are no longer FIDs for this directory. By returning
1852 // EFI_DEVICE_ERROR to the callee will indicate end of directory
1853 // listening.
1854 //
1855 return EFI_DEVICE_ERROR;
1856 }
1857
1858 //
1859 // Get FID for this entry.
1860 //
1861 FileIdentifierDesc = GET_FID_FROM_ADS (ReadDirInfo->DirectoryData,
1862 ReadDirInfo->FidOffset);
1863 //
1864 // Update FidOffset to point to next FID.
1865 //
1866 ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);
1867 } while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);
1868
1869 DuplicateFid (FileIdentifierDesc, FoundFid);
1870
1871 return EFI_SUCCESS;
1872 }
1873
1874 /**
1875 Get a filename (encoded in OSTA-compressed format) from a File Identifier
1876 Descriptor on an UDF volume.
1877
1878 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
1879 @param[out] FileName Decoded filename.
1880
1881 @retval EFI_SUCCESS Filename decoded and read.
1882 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1883 **/
1884 EFI_STATUS
1885 GetFileNameFromFid (
1886 IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
1887 OUT CHAR16 *FileName
1888 )
1889 {
1890 UINT8 *OstaCompressed;
1891 UINT8 CompressionId;
1892 UINT8 Length;
1893 UINTN Index;
1894
1895 OstaCompressed =
1896 (UINT8 *)(
1897 (UINT8 *)FileIdentifierDesc->Data +
1898 FileIdentifierDesc->LengthOfImplementationUse
1899 );
1900
1901 CompressionId = OstaCompressed[0];
1902 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
1903 return EFI_VOLUME_CORRUPTED;
1904 }
1905
1906 //
1907 // Decode filename.
1908 //
1909 Length = FileIdentifierDesc->LengthOfFileIdentifier;
1910 for (Index = 1; Index < Length; Index++) {
1911 if (CompressionId == 16) {
1912 *FileName = OstaCompressed[Index++] << 8;
1913 } else {
1914 *FileName = 0;
1915 }
1916
1917 if (Index < Length) {
1918 *FileName |= (CHAR16)(OstaCompressed[Index]);
1919 }
1920
1921 FileName++;
1922 }
1923
1924 *FileName = L'\0';
1925
1926 return EFI_SUCCESS;
1927 }
1928
1929 /**
1930 Resolve a symlink file on an UDF volume.
1931
1932 @param[in] BlockIo BlockIo interface.
1933 @param[in] DiskIo DiskIo interface.
1934 @param[in] Volume UDF volume information structure.
1935 @param[in] Parent Parent file.
1936 @param[in] FileEntryData FE/EFE structure pointer.
1937 @param[out] File Resolved file.
1938
1939 @retval EFI_SUCCESS Symlink file resolved.
1940 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1941 @retval EFI_NO_MEDIA The device has no media.
1942 @retval EFI_DEVICE_ERROR The device reported an error.
1943 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1944 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
1945 resources.
1946
1947 **/
1948 EFI_STATUS
1949 ResolveSymlink (
1950 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1951 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1952 IN UDF_VOLUME_INFO *Volume,
1953 IN UDF_FILE_INFO *Parent,
1954 IN VOID *FileEntryData,
1955 OUT UDF_FILE_INFO *File
1956 )
1957 {
1958 EFI_STATUS Status;
1959 UDF_READ_FILE_INFO ReadFileInfo;
1960 UINT8 *Data;
1961 UINT64 Length;
1962 UINT8 *EndData;
1963 UDF_PATH_COMPONENT *PathComp;
1964 UINT8 PathCompLength;
1965 CHAR16 FileName[UDF_FILENAME_LENGTH];
1966 CHAR16 *Char;
1967 UINTN Index;
1968 UINT8 CompressionId;
1969 UDF_FILE_INFO PreviousFile;
1970
1971 //
1972 // Symlink files on UDF volumes do not contain so much data other than
1973 // Path Components which resolves to real filenames, so it's OK to read in
1974 // all its data here -- usually the data will be inline with the FE/EFE for
1975 // lower filenames.
1976 //
1977 ReadFileInfo.Flags = ReadFileAllocateAndRead;
1978
1979 Status = ReadFile (
1980 BlockIo,
1981 DiskIo,
1982 Volume,
1983 &Parent->FileIdentifierDesc->Icb,
1984 FileEntryData,
1985 &ReadFileInfo
1986 );
1987 if (EFI_ERROR (Status)) {
1988 return Status;
1989 }
1990
1991 Length = ReadFileInfo.ReadLength;
1992
1993 Data = (UINT8 *)ReadFileInfo.FileData;
1994 EndData = Data + Length;
1995
1996 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
1997
1998 for (;;) {
1999 PathComp = (UDF_PATH_COMPONENT *)Data;
2000
2001 PathCompLength = PathComp->LengthOfComponentIdentifier;
2002
2003 switch (PathComp->ComponentType) {
2004 case 1:
2005 //
2006 // This Path Component specifies the root directory hierarchy subject to
2007 // agreement between the originator and recipient of the medium. Skip it.
2008 //
2009 // Fall through.
2010 //
2011 case 2:
2012 //
2013 // "\\." of the current directory. Read next Path Component.
2014 //
2015 goto Next_Path_Component;
2016 case 3:
2017 //
2018 // ".." (parent directory). Go to it.
2019 //
2020 CopyMem ((VOID *)FileName, L"..", 6);
2021 break;
2022 case 4:
2023 //
2024 // "." (current file). Duplicate both FE/EFE and FID of this file.
2025 //
2026 DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);
2027 DuplicateFid (PreviousFile.FileIdentifierDesc,
2028 &File->FileIdentifierDesc);
2029 goto Next_Path_Component;
2030 case 5:
2031 //
2032 // This Path Component identifies an object, either a file or a
2033 // directory or an alias.
2034 //
2035 // Decode it from the compressed data in ComponentIdentifier and find
2036 // respective path.
2037 //
2038 CompressionId = PathComp->ComponentIdentifier[0];
2039 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
2040 return EFI_VOLUME_CORRUPTED;
2041 }
2042
2043 Char = FileName;
2044 for (Index = 1; Index < PathCompLength; Index++) {
2045 if (CompressionId == 16) {
2046 *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +
2047 Index) << 8;
2048 Index++;
2049 } else {
2050 *Char = 0;
2051 }
2052
2053 if (Index < Length) {
2054 *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));
2055 }
2056
2057 Char++;
2058 }
2059
2060 *Char = L'\0';
2061 break;
2062 }
2063
2064 //
2065 // Find file from the read filename in symlink's file data.
2066 //
2067 Status = InternalFindFile (
2068 BlockIo,
2069 DiskIo,
2070 Volume,
2071 FileName,
2072 &PreviousFile,
2073 NULL,
2074 File
2075 );
2076 if (EFI_ERROR (Status)) {
2077 goto Error_Find_File;
2078 }
2079
2080 Next_Path_Component:
2081 Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;
2082 if (Data >= EndData) {
2083 break;
2084 }
2085
2086 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
2087 sizeof (UDF_FILE_INFO)) != 0) {
2088 CleanupFileInformation (&PreviousFile);
2089 }
2090
2091 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
2092 }
2093
2094 //
2095 // Unmap the symlink file.
2096 //
2097 FreePool (ReadFileInfo.FileData);
2098
2099 return EFI_SUCCESS;
2100
2101 Error_Find_File:
2102 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
2103 sizeof (UDF_FILE_INFO)) != 0) {
2104 CleanupFileInformation (&PreviousFile);
2105 }
2106
2107 FreePool (ReadFileInfo.FileData);
2108
2109 return Status;
2110 }
2111
2112 /**
2113 Clean up in-memory UDF file information.
2114
2115 @param[in] File File information pointer.
2116
2117 **/
2118 VOID
2119 CleanupFileInformation (
2120 IN UDF_FILE_INFO *File
2121 )
2122 {
2123 if (File->FileEntry != NULL) {
2124 FreePool (File->FileEntry);
2125 }
2126 if (File->FileIdentifierDesc != NULL) {
2127 FreePool ((VOID *)File->FileIdentifierDesc);
2128 }
2129
2130 ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));
2131 }
2132
2133 /**
2134 Find a file from its absolute path on an UDF volume.
2135
2136 @param[in] BlockIo BlockIo interface.
2137 @param[in] DiskIo DiskIo interface.
2138 @param[in] Volume UDF volume information structure.
2139 @param[in] File File information structure.
2140 @param[out] Size Size of the file.
2141
2142 @retval EFI_SUCCESS File size calculated and set in Size.
2143 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2144 @retval EFI_NO_MEDIA The device has no media.
2145 @retval EFI_DEVICE_ERROR The device reported an error.
2146 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2147 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2148 resources.
2149
2150 **/
2151 EFI_STATUS
2152 GetFileSize (
2153 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2154 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2155 IN UDF_VOLUME_INFO *Volume,
2156 IN UDF_FILE_INFO *File,
2157 OUT UINT64 *Size
2158 )
2159 {
2160 EFI_STATUS Status;
2161 UDF_READ_FILE_INFO ReadFileInfo;
2162
2163 ReadFileInfo.Flags = ReadFileGetFileSize;
2164
2165 Status = ReadFile (
2166 BlockIo,
2167 DiskIo,
2168 Volume,
2169 &File->FileIdentifierDesc->Icb,
2170 File->FileEntry,
2171 &ReadFileInfo
2172 );
2173 if (EFI_ERROR (Status)) {
2174 return Status;
2175 }
2176
2177 *Size = ReadFileInfo.ReadLength;
2178
2179 return EFI_SUCCESS;
2180 }
2181
2182 /**
2183 Set information about a file on an UDF volume.
2184
2185 @param[in] File File pointer.
2186 @param[in] FileSize Size of the file.
2187 @param[in] FileName Filename of the file.
2188 @param[in, out] BufferSize Size of the returned file infomation.
2189 @param[out] Buffer Data of the returned file information.
2190
2191 @retval EFI_SUCCESS File information set.
2192 @retval EFI_NO_MEDIA The device has no media.
2193 @retval EFI_DEVICE_ERROR The device reported an error.
2194 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2195 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2196 resources.
2197
2198 **/
2199 EFI_STATUS
2200 SetFileInfo (
2201 IN UDF_FILE_INFO *File,
2202 IN UINT64 FileSize,
2203 IN CHAR16 *FileName,
2204 IN OUT UINTN *BufferSize,
2205 OUT VOID *Buffer
2206 )
2207 {
2208 UINTN FileInfoLength;
2209 EFI_FILE_INFO *FileInfo;
2210 UDF_FILE_ENTRY *FileEntry;
2211 UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
2212 UDF_DESCRIPTOR_TAG *DescriptorTag;
2213
2214 //
2215 // Calculate the needed size for the EFI_FILE_INFO structure.
2216 //
2217 FileInfoLength = sizeof (EFI_FILE_INFO) + ((FileName != NULL) ?
2218 StrSize (FileName) :
2219 sizeof (CHAR16));
2220 if (*BufferSize < FileInfoLength) {
2221 //
2222 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2223 //
2224 *BufferSize = FileInfoLength;
2225 return EFI_BUFFER_TOO_SMALL;
2226 }
2227
2228 //
2229 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2230 // Now, fill it in with all necessary information about the file.
2231 //
2232 FileInfo = (EFI_FILE_INFO *)Buffer;
2233 FileInfo->Size = FileInfoLength;
2234 FileInfo->Attribute &= ~EFI_FILE_VALID_ATTR;
2235 FileInfo->Attribute |= EFI_FILE_READ_ONLY;
2236
2237 if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {
2238 FileInfo->Attribute |= EFI_FILE_DIRECTORY;
2239 } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {
2240 FileInfo->Attribute |= EFI_FILE_ARCHIVE;
2241 }
2242
2243 if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {
2244 FileInfo->Attribute |= EFI_FILE_HIDDEN;
2245 }
2246
2247 DescriptorTag = File->FileEntry;
2248
2249 if (DescriptorTag->TagIdentifier == UdfFileEntry) {
2250 FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;
2251
2252 //
2253 // Check if FE has the system attribute set.
2254 //
2255 if (FileEntry->IcbTag.Flags & (1 << 10)) {
2256 FileInfo->Attribute |= EFI_FILE_SYSTEM;
2257 }
2258
2259 FileInfo->FileSize = FileSize;
2260 FileInfo->PhysicalSize = FileSize;
2261
2262 FileInfo->CreateTime.Year = FileEntry->AccessTime.Year;
2263 FileInfo->CreateTime.Month = FileEntry->AccessTime.Month;
2264 FileInfo->CreateTime.Day = FileEntry->AccessTime.Day;
2265 FileInfo->CreateTime.Hour = FileEntry->AccessTime.Hour;
2266 FileInfo->CreateTime.Minute = FileEntry->AccessTime.Second;
2267 FileInfo->CreateTime.Second = FileEntry->AccessTime.Second;
2268 FileInfo->CreateTime.Nanosecond =
2269 FileEntry->AccessTime.HundredsOfMicroseconds;
2270
2271 FileInfo->LastAccessTime.Year =
2272 FileEntry->AccessTime.Year;
2273 FileInfo->LastAccessTime.Month =
2274 FileEntry->AccessTime.Month;
2275 FileInfo->LastAccessTime.Day =
2276 FileEntry->AccessTime.Day;
2277 FileInfo->LastAccessTime.Hour =
2278 FileEntry->AccessTime.Hour;
2279 FileInfo->LastAccessTime.Minute =
2280 FileEntry->AccessTime.Minute;
2281 FileInfo->LastAccessTime.Second =
2282 FileEntry->AccessTime.Second;
2283 FileInfo->LastAccessTime.Nanosecond =
2284 FileEntry->AccessTime.HundredsOfMicroseconds;
2285 } else if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
2286 ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;
2287
2288 //
2289 // Check if EFE has the system attribute set.
2290 //
2291 if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {
2292 FileInfo->Attribute |= EFI_FILE_SYSTEM;
2293 }
2294
2295 FileInfo->FileSize = FileSize;
2296 FileInfo->PhysicalSize = FileSize;
2297
2298 FileInfo->CreateTime.Year = ExtendedFileEntry->CreationTime.Year;
2299 FileInfo->CreateTime.Month = ExtendedFileEntry->CreationTime.Month;
2300 FileInfo->CreateTime.Day = ExtendedFileEntry->CreationTime.Day;
2301 FileInfo->CreateTime.Hour = ExtendedFileEntry->CreationTime.Hour;
2302 FileInfo->CreateTime.Minute = ExtendedFileEntry->CreationTime.Second;
2303 FileInfo->CreateTime.Second = ExtendedFileEntry->CreationTime.Second;
2304 FileInfo->CreateTime.Nanosecond =
2305 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
2306
2307 FileInfo->LastAccessTime.Year =
2308 ExtendedFileEntry->AccessTime.Year;
2309 FileInfo->LastAccessTime.Month =
2310 ExtendedFileEntry->AccessTime.Month;
2311 FileInfo->LastAccessTime.Day =
2312 ExtendedFileEntry->AccessTime.Day;
2313 FileInfo->LastAccessTime.Hour =
2314 ExtendedFileEntry->AccessTime.Hour;
2315 FileInfo->LastAccessTime.Minute =
2316 ExtendedFileEntry->AccessTime.Minute;
2317 FileInfo->LastAccessTime.Second =
2318 ExtendedFileEntry->AccessTime.Second;
2319 FileInfo->LastAccessTime.Nanosecond =
2320 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
2321 }
2322
2323 FileInfo->CreateTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
2324 FileInfo->CreateTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
2325 FileInfo->LastAccessTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
2326 FileInfo->LastAccessTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
2327
2328 CopyMem ((VOID *)&FileInfo->ModificationTime,
2329 (VOID *)&FileInfo->LastAccessTime,
2330 sizeof (EFI_TIME));
2331
2332 if (FileName != NULL) {
2333 StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);
2334 } else {
2335 FileInfo->FileName[0] = '\0';
2336 }
2337
2338 *BufferSize = FileInfoLength;
2339
2340 return EFI_SUCCESS;
2341 }
2342
2343 /**
2344 Get volume and free space size information of an UDF volume.
2345
2346 @param[in] BlockIo BlockIo interface.
2347 @param[in] DiskIo DiskIo interface.
2348 @param[in] Volume UDF volume information structure.
2349 @param[out] VolumeSize Volume size.
2350 @param[out] FreeSpaceSize Free space size.
2351
2352 @retval EFI_SUCCESS Volume and free space size calculated.
2353 @retval EFI_NO_MEDIA The device has no media.
2354 @retval EFI_DEVICE_ERROR The device reported an error.
2355 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2356 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
2357 calculated due to lack of resources.
2358
2359 **/
2360 EFI_STATUS
2361 GetVolumeSize (
2362 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2363 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2364 IN UDF_VOLUME_INFO *Volume,
2365 OUT UINT64 *VolumeSize,
2366 OUT UINT64 *FreeSpaceSize
2367 )
2368 {
2369 EFI_STATUS Status;
2370 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
2371 UDF_EXTENT_AD *ExtentAd;
2372 UINT64 Lsn;
2373 UINT32 LogicalBlockSize;
2374 UDF_LOGICAL_VOLUME_INTEGRITY *LogicalVolInt;
2375 UDF_DESCRIPTOR_TAG *DescriptorTag;
2376 UINTN Index;
2377 UINTN Length;
2378 UINT32 LsnsNo;
2379
2380 LogicalVolDesc = &Volume->LogicalVolDesc;
2381
2382 ExtentAd = &LogicalVolDesc->IntegritySequenceExtent;
2383
2384 if (ExtentAd->ExtentLength == 0) {
2385 return EFI_VOLUME_CORRUPTED;
2386 }
2387
2388 LogicalVolInt = AllocatePool (ExtentAd->ExtentLength);
2389 if (LogicalVolInt == NULL) {
2390 return EFI_OUT_OF_RESOURCES;
2391 }
2392
2393 //
2394 // Get location of Logical Volume Integrity Descriptor
2395 //
2396 Lsn = (UINT64)ExtentAd->ExtentLocation - Volume->MainVdsStartLocation;
2397
2398 LogicalBlockSize = LogicalVolDesc->LogicalBlockSize;
2399
2400 //
2401 // Read disk block
2402 //
2403 Status = DiskIo->ReadDisk (
2404 DiskIo,
2405 BlockIo->Media->MediaId,
2406 MultU64x32 (Lsn, LogicalBlockSize),
2407 ExtentAd->ExtentLength,
2408 LogicalVolInt
2409 );
2410 if (EFI_ERROR (Status)) {
2411 goto Out_Free;
2412 }
2413
2414 DescriptorTag = &LogicalVolInt->DescriptorTag;
2415
2416 //
2417 // Check if read block is a Logical Volume Integrity Descriptor
2418 //
2419 if (DescriptorTag->TagIdentifier != UdfLogicalVolumeIntegrityDescriptor) {
2420 Status = EFI_VOLUME_CORRUPTED;
2421 goto Out_Free;
2422 }
2423
2424 *VolumeSize = 0;
2425 *FreeSpaceSize = 0;
2426
2427 Length = LogicalVolInt->NumberOfPartitions;
2428 for (Index = 0; Index < Length; Index += sizeof (UINT32)) {
2429 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
2430 //
2431 // Check if size is not specified
2432 //
2433 if (LsnsNo == 0xFFFFFFFFUL) {
2434 continue;
2435 }
2436 //
2437 // Accumulate free space size
2438 //
2439 *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
2440 }
2441
2442 Length = LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2;
2443 for (; Index < Length; Index += sizeof (UINT32)) {
2444 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
2445 //
2446 // Check if size is not specified
2447 //
2448 if (LsnsNo == 0xFFFFFFFFUL) {
2449 continue;
2450 }
2451 //
2452 // Accumulate used volume space
2453 //
2454 *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
2455 }
2456
2457 Status = EFI_SUCCESS;
2458
2459 Out_Free:
2460 //
2461 // Free Logical Volume Integrity Descriptor
2462 //
2463 FreePool (LogicalVolInt);
2464
2465 return Status;
2466 }
2467
2468 /**
2469 Seek a file and read its data into memory on an UDF volume.
2470
2471 @param[in] BlockIo BlockIo interface.
2472 @param[in] DiskIo DiskIo interface.
2473 @param[in] Volume UDF volume information structure.
2474 @param[in] File File information structure.
2475 @param[in] FileSize Size of the file.
2476 @param[in, out] FilePosition File position.
2477 @param[in, out] Buffer File data.
2478 @param[in, out] BufferSize Read size.
2479
2480 @retval EFI_SUCCESS File seeked and read.
2481 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2482 @retval EFI_NO_MEDIA The device has no media.
2483 @retval EFI_DEVICE_ERROR The device reported an error.
2484 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2485 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2486 of resources.
2487
2488 **/
2489 EFI_STATUS
2490 ReadFileData (
2491 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2492 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2493 IN UDF_VOLUME_INFO *Volume,
2494 IN UDF_FILE_INFO *File,
2495 IN UINT64 FileSize,
2496 IN OUT UINT64 *FilePosition,
2497 IN OUT VOID *Buffer,
2498 IN OUT UINT64 *BufferSize
2499 )
2500 {
2501 EFI_STATUS Status;
2502 UDF_READ_FILE_INFO ReadFileInfo;
2503
2504 ReadFileInfo.Flags = ReadFileSeekAndRead;
2505 ReadFileInfo.FilePosition = *FilePosition;
2506 ReadFileInfo.FileData = Buffer;
2507 ReadFileInfo.FileDataSize = *BufferSize;
2508 ReadFileInfo.FileSize = FileSize;
2509
2510 Status = ReadFile (
2511 BlockIo,
2512 DiskIo,
2513 Volume,
2514 &File->FileIdentifierDesc->Icb,
2515 File->FileEntry,
2516 &ReadFileInfo
2517 );
2518 if (EFI_ERROR (Status)) {
2519 return Status;
2520 }
2521
2522 *BufferSize = ReadFileInfo.FileDataSize;
2523 *FilePosition = ReadFileInfo.FilePosition;
2524
2525 return EFI_SUCCESS;
2526 }
2527
2528 /**
2529 Check if ControllerHandle supports an UDF file system.
2530
2531 @param[in] This Protocol instance pointer.
2532 @param[in] ControllerHandle Handle of device to test.
2533
2534 @retval EFI_SUCCESS UDF file system found.
2535 @retval EFI_UNSUPPORTED UDF file system not found.
2536
2537 **/
2538 EFI_STATUS
2539 SupportUdfFileSystem (
2540 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2541 IN EFI_HANDLE ControllerHandle
2542 )
2543 {
2544 EFI_STATUS Status;
2545 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2546 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
2547 EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
2548 EFI_GUID *VendorDefinedGuid;
2549
2550 //
2551 // Open Device Path protocol on ControllerHandle
2552 //
2553 Status = gBS->OpenProtocol (
2554 ControllerHandle,
2555 &gEfiDevicePathProtocolGuid,
2556 (VOID **)&DevicePath,
2557 This->DriverBindingHandle,
2558 ControllerHandle,
2559 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2560 );
2561 if (EFI_ERROR (Status)) {
2562 return EFI_UNSUPPORTED;
2563 }
2564
2565 Status = EFI_UNSUPPORTED;
2566
2567 //
2568 // Get last Device Path node
2569 //
2570 LastDevicePathNode = NULL;
2571 DevicePathNode = DevicePath;
2572 while (!IsDevicePathEnd (DevicePathNode)) {
2573 LastDevicePathNode = DevicePathNode;
2574 DevicePathNode = NextDevicePathNode (DevicePathNode);
2575 }
2576 //
2577 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2578 // of an UDF file system.
2579 //
2580 if (LastDevicePathNode != NULL &&
2581 DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
2582 DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP) {
2583 VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +
2584 OFFSET_OF (VENDOR_DEVICE_PATH, Guid));
2585 if (CompareGuid (VendorDefinedGuid, &gUdfDevPathGuid)) {
2586 Status = EFI_SUCCESS;
2587 }
2588 }
2589
2590 //
2591 // Close Device Path protocol on ControllerHandle
2592 //
2593 gBS->CloseProtocol (
2594 ControllerHandle,
2595 &gEfiDevicePathProtocolGuid,
2596 This->DriverBindingHandle,
2597 ControllerHandle
2598 );
2599
2600 return Status;
2601 }