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