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