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