]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
MdeModulePkg/UdfDxe: Avoid possible use of already-freed data
[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 VOID *DataBak;
1082 UINT64 Length;
1083 VOID *Ad;
1084 UINT64 AdOffset;
1085 UINT64 Lsn;
1086 BOOLEAN DoFreeAed;
1087 UINT64 FilePosition;
1088 UINT64 Offset;
1089 UINT64 DataOffset;
1090 UINT64 BytesLeft;
1091 UINT64 DataLength;
1092 BOOLEAN FinishedSeeking;
1093 UINT32 ExtentLength;
1094 UDF_FE_RECORDING_FLAGS RecordingFlags;
1095
1096 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
1097 DoFreeAed = FALSE;
1098
1099 //
1100 // set BytesLeft to suppress incorrect compiler/analyzer warnings
1101 //
1102 BytesLeft = 0;
1103 DataOffset = 0;
1104 FilePosition = 0;
1105 FinishedSeeking = FALSE;
1106 Data = NULL;
1107
1108 switch (ReadFileInfo->Flags) {
1109 case ReadFileGetFileSize:
1110 case ReadFileAllocateAndRead:
1111 //
1112 // Initialise ReadFileInfo structure for either getting file size, or
1113 // reading file's recorded data.
1114 //
1115 ReadFileInfo->ReadLength = 0;
1116 ReadFileInfo->FileData = NULL;
1117 break;
1118 case ReadFileSeekAndRead:
1119 //
1120 // About to seek a file and/or read its data.
1121 //
1122 Length = ReadFileInfo->FileSize - ReadFileInfo->FilePosition;
1123 if (ReadFileInfo->FileDataSize > Length) {
1124 //
1125 // About to read beyond the EOF -- truncate it.
1126 //
1127 ReadFileInfo->FileDataSize = Length;
1128 }
1129
1130 //
1131 // Initialise data to start seeking and/or reading a file.
1132 //
1133 BytesLeft = ReadFileInfo->FileDataSize;
1134 DataOffset = 0;
1135 FilePosition = 0;
1136 FinishedSeeking = FALSE;
1137
1138 break;
1139 }
1140
1141 RecordingFlags = GET_FE_RECORDING_FLAGS (FileEntryData);
1142 switch (RecordingFlags) {
1143 case InlineData:
1144 //
1145 // There are no extents for this FE/EFE. All data is inline.
1146 //
1147 Status = GetFileEntryData (FileEntryData, Volume->FileEntrySize, &Data, &Length);
1148 if (EFI_ERROR (Status)) {
1149 return Status;
1150 }
1151
1152 if (ReadFileInfo->Flags == ReadFileGetFileSize) {
1153 ReadFileInfo->ReadLength = Length;
1154 } else if (ReadFileInfo->Flags == ReadFileAllocateAndRead) {
1155 //
1156 // Allocate buffer for starting read data.
1157 //
1158 ReadFileInfo->FileData = AllocatePool ((UINTN) Length);
1159 if (ReadFileInfo->FileData == NULL) {
1160 return EFI_OUT_OF_RESOURCES;
1161 }
1162
1163 //
1164 // Read all inline data into ReadFileInfo->FileData
1165 //
1166 CopyMem (ReadFileInfo->FileData, Data, (UINTN) Length);
1167 ReadFileInfo->ReadLength = Length;
1168 } else if (ReadFileInfo->Flags == ReadFileSeekAndRead) {
1169 //
1170 // If FilePosition is non-zero, seek file to FilePosition, read
1171 // FileDataSize bytes and then updates FilePosition.
1172 //
1173 CopyMem (
1174 ReadFileInfo->FileData,
1175 (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition),
1176 (UINTN) ReadFileInfo->FileDataSize
1177 );
1178
1179 ReadFileInfo->FilePosition += ReadFileInfo->FileDataSize;
1180 } else {
1181 ASSERT (FALSE);
1182 return EFI_INVALID_PARAMETER;
1183 }
1184
1185 Status = EFI_SUCCESS;
1186 break;
1187
1188 case LongAdsSequence:
1189 case ShortAdsSequence:
1190 //
1191 // This FE/EFE contains a run of Allocation Descriptors. Get data + size
1192 // for start reading them out.
1193 //
1194 Status = GetAdsInformation (FileEntryData, Volume->FileEntrySize, &Data, &Length);
1195 if (EFI_ERROR (Status)) {
1196 return Status;
1197 }
1198
1199 AdOffset = 0;
1200
1201 for (;;) {
1202 //
1203 // Read AD.
1204 //
1205 Status = GetAllocationDescriptor (
1206 RecordingFlags,
1207 Data,
1208 &AdOffset,
1209 Length,
1210 &Ad
1211 );
1212 if (Status == EFI_DEVICE_ERROR) {
1213 Status = EFI_SUCCESS;
1214 goto Done;
1215 }
1216
1217 //
1218 // Check if AD is an indirect AD. If so, read Allocation Extent
1219 // Descriptor and its extents (ADs).
1220 //
1221 if (GET_EXTENT_FLAGS (RecordingFlags, Ad) == ExtentIsNextExtent) {
1222 DataBak = Data;
1223 Status = GetAedAdsData (
1224 BlockIo,
1225 DiskIo,
1226 Volume,
1227 ParentIcb,
1228 RecordingFlags,
1229 Ad,
1230 &Data,
1231 &Length
1232 );
1233
1234 if (!DoFreeAed) {
1235 DoFreeAed = TRUE;
1236 } else {
1237 FreePool (DataBak);
1238 }
1239
1240 if (EFI_ERROR (Status)) {
1241 goto Error_Get_Aed;
1242 }
1243 ASSERT (Data != NULL);
1244
1245 AdOffset = 0;
1246 continue;
1247 }
1248
1249 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
1250
1251 Status = GetAllocationDescriptorLsn (RecordingFlags,
1252 Volume,
1253 ParentIcb,
1254 Ad,
1255 &Lsn);
1256 if (EFI_ERROR (Status)) {
1257 goto Done;
1258 }
1259
1260 switch (ReadFileInfo->Flags) {
1261 case ReadFileGetFileSize:
1262 ReadFileInfo->ReadLength += ExtentLength;
1263 break;
1264 case ReadFileAllocateAndRead:
1265 //
1266 // Increase FileData (if necessary) to read next extent.
1267 //
1268 Status = GrowUpBufferToNextAd (
1269 RecordingFlags,
1270 Ad,
1271 &ReadFileInfo->FileData,
1272 ReadFileInfo->ReadLength
1273 );
1274 if (EFI_ERROR (Status)) {
1275 goto Error_Alloc_Buffer_To_Next_Ad;
1276 }
1277
1278 //
1279 // Read extent's data into FileData.
1280 //
1281 Status = DiskIo->ReadDisk (
1282 DiskIo,
1283 BlockIo->Media->MediaId,
1284 MultU64x32 (Lsn, LogicalBlockSize),
1285 ExtentLength,
1286 (VOID *)((UINT8 *)ReadFileInfo->FileData +
1287 ReadFileInfo->ReadLength)
1288 );
1289 if (EFI_ERROR (Status)) {
1290 goto Error_Read_Disk_Blk;
1291 }
1292
1293 ReadFileInfo->ReadLength += ExtentLength;
1294 break;
1295 case ReadFileSeekAndRead:
1296 //
1297 // Seek file first before reading in its data.
1298 //
1299 if (FinishedSeeking) {
1300 Offset = 0;
1301 goto Skip_File_Seek;
1302 }
1303
1304 if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) {
1305 FilePosition += ExtentLength;
1306 goto Skip_Ad;
1307 }
1308
1309 if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) {
1310 Offset = ReadFileInfo->FilePosition - FilePosition;
1311 } else {
1312 Offset = 0;
1313 }
1314
1315 //
1316 // Done with seeking file. Start reading its data.
1317 //
1318 FinishedSeeking = TRUE;
1319
1320 Skip_File_Seek:
1321 //
1322 // Make sure we don't read more data than really wanted.
1323 //
1324 if (ExtentLength - Offset > BytesLeft) {
1325 DataLength = BytesLeft;
1326 } else {
1327 DataLength = ExtentLength - Offset;
1328 }
1329
1330 //
1331 // Read extent's data into FileData.
1332 //
1333 Status = DiskIo->ReadDisk (
1334 DiskIo,
1335 BlockIo->Media->MediaId,
1336 Offset + MultU64x32 (Lsn, LogicalBlockSize),
1337 (UINTN) DataLength,
1338 (VOID *)((UINT8 *)ReadFileInfo->FileData +
1339 DataOffset)
1340 );
1341 if (EFI_ERROR (Status)) {
1342 goto Error_Read_Disk_Blk;
1343 }
1344
1345 //
1346 // Update current file's position.
1347 //
1348 DataOffset += DataLength;
1349 ReadFileInfo->FilePosition += DataLength;
1350
1351 BytesLeft -= DataLength;
1352 if (BytesLeft == 0) {
1353 //
1354 // There is no more file data to read.
1355 //
1356 Status = EFI_SUCCESS;
1357 goto Done;
1358 }
1359
1360 break;
1361 }
1362
1363 Skip_Ad:
1364 //
1365 // Point to the next AD (extent).
1366 //
1367 AdOffset += AD_LENGTH (RecordingFlags);
1368 }
1369
1370 break;
1371 case ExtendedAdsSequence:
1372 // FIXME: Not supported. Got no volume with it, yet.
1373 ASSERT (FALSE);
1374 Status = EFI_UNSUPPORTED;
1375 break;
1376
1377 default:
1378 //
1379 // A flag value reserved by the ECMA-167 standard (3rd Edition - June
1380 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
1381 //
1382 Status = EFI_UNSUPPORTED;
1383 break;
1384 }
1385
1386 Done:
1387 if (DoFreeAed) {
1388 FreePool (Data);
1389 }
1390
1391 return Status;
1392
1393 Error_Read_Disk_Blk:
1394 Error_Alloc_Buffer_To_Next_Ad:
1395 if (ReadFileInfo->Flags != ReadFileSeekAndRead) {
1396 FreePool (ReadFileInfo->FileData);
1397 }
1398
1399 if (DoFreeAed) {
1400 FreePool (Data);
1401 }
1402
1403 Error_Get_Aed:
1404 return Status;
1405 }
1406
1407 /**
1408 Find a file by its filename from a given Parent file.
1409
1410 @param[in] BlockIo BlockIo interface.
1411 @param[in] DiskIo DiskIo interface.
1412 @param[in] Volume Volume information pointer.
1413 @param[in] FileName File name string.
1414 @param[in] Parent Parent directory file.
1415 @param[in] Icb Long Allocation Descriptor pointer.
1416 @param[out] File Found file.
1417
1418 @retval EFI_SUCCESS The file was found.
1419 @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.
1420 @retval EFI_NOT_FOUND The file was not found.
1421
1422 **/
1423 EFI_STATUS
1424 InternalFindFile (
1425 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1426 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1427 IN UDF_VOLUME_INFO *Volume,
1428 IN CHAR16 *FileName,
1429 IN UDF_FILE_INFO *Parent,
1430 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
1431 OUT UDF_FILE_INFO *File
1432 )
1433 {
1434 EFI_STATUS Status;
1435 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
1436 UDF_READ_DIRECTORY_INFO ReadDirInfo;
1437 BOOLEAN Found;
1438 CHAR16 FoundFileName[UDF_FILENAME_LENGTH];
1439 VOID *CompareFileEntry;
1440
1441 //
1442 // Check if both Parent->FileIdentifierDesc and Icb are NULL.
1443 //
1444 if ((Parent->FileIdentifierDesc == NULL) && (Icb == NULL)) {
1445 return EFI_INVALID_PARAMETER;
1446 }
1447
1448 //
1449 // Check if parent file is really directory.
1450 //
1451 if (FE_ICB_FILE_TYPE (Parent->FileEntry) != UdfFileEntryDirectory) {
1452 return EFI_NOT_FOUND;
1453 }
1454
1455 //
1456 // If FileName is current file or working directory, just duplicate Parent's
1457 // FE/EFE and FID descriptors.
1458 //
1459 if (StrCmp (FileName, L".") == 0) {
1460 if (Parent->FileIdentifierDesc == NULL) {
1461 return EFI_INVALID_PARAMETER;
1462 }
1463
1464 DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);
1465 if (File->FileEntry == NULL) {
1466 return EFI_OUT_OF_RESOURCES;
1467 }
1468
1469 DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);
1470 if (File->FileIdentifierDesc == NULL) {
1471 FreePool (File->FileEntry);
1472 return EFI_OUT_OF_RESOURCES;
1473 }
1474
1475 return EFI_SUCCESS;
1476 }
1477
1478 //
1479 // Start directory listing.
1480 //
1481 ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
1482 Found = FALSE;
1483
1484 for (;;) {
1485 Status = ReadDirectoryEntry (
1486 BlockIo,
1487 DiskIo,
1488 Volume,
1489 (Parent->FileIdentifierDesc != NULL) ?
1490 &Parent->FileIdentifierDesc->Icb :
1491 Icb,
1492 Parent->FileEntry,
1493 &ReadDirInfo,
1494 &FileIdentifierDesc
1495 );
1496 if (EFI_ERROR (Status)) {
1497 if (Status == EFI_DEVICE_ERROR) {
1498 Status = EFI_NOT_FOUND;
1499 }
1500
1501 break;
1502 }
1503 //
1504 // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is
1505 // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code
1506 // reaches here, 'FileIdentifierDesc' must be not NULL.
1507 //
1508 // The ASSERT here is for addressing a false positive NULL pointer
1509 // dereference issue raised from static analysis.
1510 //
1511 ASSERT (FileIdentifierDesc != NULL);
1512
1513 if (FileIdentifierDesc->FileCharacteristics & PARENT_FILE) {
1514 //
1515 // This FID contains the location (FE/EFE) of the parent directory of this
1516 // directory (Parent), and if FileName is either ".." or "\\", then it's
1517 // the expected FID.
1518 //
1519 if (StrCmp (FileName, L"..") == 0 || StrCmp (FileName, L"\\") == 0) {
1520 Found = TRUE;
1521 break;
1522 }
1523 } else {
1524 Status = GetFileNameFromFid (FileIdentifierDesc, ARRAY_SIZE (FoundFileName), FoundFileName);
1525 if (EFI_ERROR (Status)) {
1526 break;
1527 }
1528
1529 if (StrCmp (FileName, FoundFileName) == 0) {
1530 //
1531 // FID has been found. Prepare to find its respective FE/EFE.
1532 //
1533 Found = TRUE;
1534 break;
1535 }
1536 }
1537
1538 FreePool ((VOID *)FileIdentifierDesc);
1539 }
1540
1541 if (ReadDirInfo.DirectoryData != NULL) {
1542 //
1543 // Free all allocated resources for the directory listing.
1544 //
1545 FreePool (ReadDirInfo.DirectoryData);
1546 }
1547
1548 if (Found) {
1549 Status = EFI_SUCCESS;
1550
1551 File->FileIdentifierDesc = FileIdentifierDesc;
1552
1553 //
1554 // If the requested file is root directory, then the FE/EFE was already
1555 // retrieved in UdfOpenVolume() function, thus no need to find it again.
1556 //
1557 // Otherwise, find FE/EFE from the respective FID.
1558 //
1559 if (StrCmp (FileName, L"\\") != 0) {
1560 Status = FindFileEntry (
1561 BlockIo,
1562 DiskIo,
1563 Volume,
1564 &FileIdentifierDesc->Icb,
1565 &CompareFileEntry
1566 );
1567 if (EFI_ERROR (Status)) {
1568 goto Error_Find_Fe;
1569 }
1570
1571 //
1572 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
1573 //
1574 if (CompareMem ((VOID *)Parent->FileEntry, (VOID *)CompareFileEntry,
1575 Volume->FileEntrySize) != 0) {
1576 File->FileEntry = CompareFileEntry;
1577 } else {
1578 FreePool ((VOID *)FileIdentifierDesc);
1579 FreePool ((VOID *)CompareFileEntry);
1580 Status = EFI_NOT_FOUND;
1581 }
1582 }
1583 }
1584
1585 return Status;
1586
1587 Error_Find_Fe:
1588 FreePool ((VOID *)FileIdentifierDesc);
1589
1590 return Status;
1591 }
1592
1593 /**
1594 Read volume information on a medium which contains a valid UDF file system.
1595
1596 @param[in] BlockIo BlockIo interface.
1597 @param[in] DiskIo DiskIo interface.
1598 @param[out] Volume UDF volume information structure.
1599
1600 @retval EFI_SUCCESS Volume information read.
1601 @retval EFI_NO_MEDIA The device has no media.
1602 @retval EFI_DEVICE_ERROR The device reported an error.
1603 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1604 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
1605
1606 **/
1607 EFI_STATUS
1608 ReadUdfVolumeInformation (
1609 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1610 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1611 OUT UDF_VOLUME_INFO *Volume
1612 )
1613 {
1614 EFI_STATUS Status;
1615
1616 //
1617 // Read all necessary UDF volume information and keep it private to the driver
1618 //
1619 Status = ReadVolumeFileStructure (
1620 BlockIo,
1621 DiskIo,
1622 Volume
1623 );
1624 if (EFI_ERROR (Status)) {
1625 return Status;
1626 }
1627
1628 //
1629 // Find File Set Descriptor
1630 //
1631 Status = FindFileSetDescriptor (BlockIo, DiskIo, Volume);
1632 if (EFI_ERROR (Status)) {
1633 return Status;
1634 }
1635
1636 return Status;
1637 }
1638
1639 /**
1640 Find the root directory on an UDF volume.
1641
1642 @param[in] BlockIo BlockIo interface.
1643 @param[in] DiskIo DiskIo interface.
1644 @param[in] Volume UDF volume information structure.
1645 @param[out] File Root directory file.
1646
1647 @retval EFI_SUCCESS Root directory found.
1648 @retval EFI_NO_MEDIA The device has no media.
1649 @retval EFI_DEVICE_ERROR The device reported an error.
1650 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1651 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
1652 resources.
1653
1654 **/
1655 EFI_STATUS
1656 FindRootDirectory (
1657 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1658 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1659 IN UDF_VOLUME_INFO *Volume,
1660 OUT UDF_FILE_INFO *File
1661 )
1662 {
1663 EFI_STATUS Status;
1664 UDF_FILE_INFO Parent;
1665
1666 Status = FindFileEntry (
1667 BlockIo,
1668 DiskIo,
1669 Volume,
1670 &Volume->FileSetDesc.RootDirectoryIcb,
1671 &File->FileEntry
1672 );
1673 if (EFI_ERROR (Status)) {
1674 return Status;
1675 }
1676
1677 Parent.FileEntry = File->FileEntry;
1678 Parent.FileIdentifierDesc = NULL;
1679
1680 Status = FindFile (
1681 BlockIo,
1682 DiskIo,
1683 Volume,
1684 L"\\",
1685 NULL,
1686 &Parent,
1687 &Volume->FileSetDesc.RootDirectoryIcb,
1688 File
1689 );
1690 if (EFI_ERROR (Status)) {
1691 FreePool (File->FileEntry);
1692 }
1693
1694 return Status;
1695 }
1696
1697 /**
1698 Find either a File Entry or a Extended File Entry from a given ICB.
1699
1700 @param[in] BlockIo BlockIo interface.
1701 @param[in] DiskIo DiskIo interface.
1702 @param[in] Volume UDF volume information structure.
1703 @param[in] Icb ICB of the FID.
1704 @param[out] FileEntry File Entry or Extended File Entry.
1705
1706 @retval EFI_SUCCESS File Entry or Extended File Entry found.
1707 @retval EFI_NO_MEDIA The device has no media.
1708 @retval EFI_DEVICE_ERROR The device reported an error.
1709 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1710 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
1711 resources.
1712
1713 **/
1714 EFI_STATUS
1715 FindFileEntry (
1716 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1717 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1718 IN UDF_VOLUME_INFO *Volume,
1719 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
1720 OUT VOID **FileEntry
1721 )
1722 {
1723 EFI_STATUS Status;
1724 UINT64 Lsn;
1725 UINT32 LogicalBlockSize;
1726 UDF_DESCRIPTOR_TAG *DescriptorTag;
1727 VOID *ReadBuffer;
1728
1729 Status = GetLongAdLsn (Volume, Icb, &Lsn);
1730 if (EFI_ERROR (Status)) {
1731 return Status;
1732 }
1733
1734 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
1735
1736 ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);
1737 if (ReadBuffer == NULL) {
1738 return EFI_OUT_OF_RESOURCES;
1739 }
1740
1741 //
1742 // Read extent.
1743 //
1744 Status = DiskIo->ReadDisk (
1745 DiskIo,
1746 BlockIo->Media->MediaId,
1747 MultU64x32 (Lsn, LogicalBlockSize),
1748 Volume->FileEntrySize,
1749 ReadBuffer
1750 );
1751 if (EFI_ERROR (Status)) {
1752 goto Error_Read_Disk_Blk;
1753 }
1754
1755 DescriptorTag = ReadBuffer;
1756
1757 //
1758 // Check if the read extent contains a valid Tag Identifier for the expected
1759 // FE/EFE.
1760 //
1761 if (DescriptorTag->TagIdentifier != UdfFileEntry &&
1762 DescriptorTag->TagIdentifier != UdfExtendedFileEntry) {
1763 Status = EFI_VOLUME_CORRUPTED;
1764 goto Error_Invalid_Fe;
1765 }
1766
1767 *FileEntry = ReadBuffer;
1768 return EFI_SUCCESS;
1769
1770 Error_Invalid_Fe:
1771 Error_Read_Disk_Blk:
1772 FreePool (ReadBuffer);
1773
1774 return Status;
1775 }
1776
1777 /**
1778 Find a file given its absolute path on an UDF volume.
1779
1780 @param[in] BlockIo BlockIo interface.
1781 @param[in] DiskIo DiskIo interface.
1782 @param[in] Volume UDF volume information structure.
1783 @param[in] FilePath File's absolute path.
1784 @param[in] Root Root directory file.
1785 @param[in] Parent Parent directory file.
1786 @param[in] Icb ICB of Parent.
1787 @param[out] File Found file.
1788
1789 @retval EFI_SUCCESS FilePath was found.
1790 @retval EFI_NO_MEDIA The device has no media.
1791 @retval EFI_DEVICE_ERROR The device reported an error.
1792 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1793 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
1794 resources.
1795
1796 **/
1797 EFI_STATUS
1798 FindFile (
1799 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1800 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1801 IN UDF_VOLUME_INFO *Volume,
1802 IN CHAR16 *FilePath,
1803 IN UDF_FILE_INFO *Root,
1804 IN UDF_FILE_INFO *Parent,
1805 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,
1806 OUT UDF_FILE_INFO *File
1807 )
1808 {
1809 EFI_STATUS Status;
1810 CHAR16 FileName[UDF_FILENAME_LENGTH];
1811 CHAR16 *FileNamePointer;
1812 UDF_FILE_INFO PreviousFile;
1813 VOID *FileEntry;
1814
1815 Status = EFI_NOT_FOUND;
1816
1817 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
1818 while (*FilePath != L'\0') {
1819 FileNamePointer = FileName;
1820 while (*FilePath != L'\0' && *FilePath != L'\\') {
1821 if ((((UINTN)FileNamePointer - (UINTN)FileName) / sizeof (CHAR16)) >=
1822 (ARRAY_SIZE (FileName) - 1)) {
1823 return EFI_NOT_FOUND;
1824 }
1825
1826 *FileNamePointer++ = *FilePath++;
1827 }
1828
1829 *FileNamePointer = L'\0';
1830 if (FileName[0] == L'\0') {
1831 //
1832 // Open root directory.
1833 //
1834 if (Root == NULL) {
1835 //
1836 // There is no file found for the root directory yet. So, find only its
1837 // FID by now.
1838 //
1839 // See UdfOpenVolume() function.
1840 //
1841 Status = InternalFindFile (BlockIo,
1842 DiskIo,
1843 Volume,
1844 L"\\",
1845 &PreviousFile,
1846 Icb,
1847 File);
1848 } else {
1849 //
1850 // We've already a file pointer (Root) for the root directory. Duplicate
1851 // its FE/EFE and FID descriptors.
1852 //
1853 Status = EFI_SUCCESS;
1854 DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);
1855 if (File->FileEntry == NULL) {
1856 Status = EFI_OUT_OF_RESOURCES;
1857 } else {
1858 //
1859 // File->FileEntry is not NULL.
1860 //
1861 DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);
1862 if (File->FileIdentifierDesc == NULL) {
1863 FreePool (File->FileEntry);
1864 Status = EFI_OUT_OF_RESOURCES;
1865 }
1866 }
1867 }
1868 } else {
1869 //
1870 // No root directory. Find filename from the current directory.
1871 //
1872 Status = InternalFindFile (BlockIo,
1873 DiskIo,
1874 Volume,
1875 FileName,
1876 &PreviousFile,
1877 Icb,
1878 File);
1879 }
1880
1881 if (EFI_ERROR (Status)) {
1882 return Status;
1883 }
1884
1885 //
1886 // If the found file is a symlink, then find its respective FE/EFE and
1887 // FID descriptors.
1888 //
1889 if (FE_ICB_FILE_TYPE (File->FileEntry) == UdfFileEntrySymlink) {
1890 FreePool ((VOID *)File->FileIdentifierDesc);
1891
1892 FileEntry = File->FileEntry;
1893
1894 Status = ResolveSymlink (BlockIo,
1895 DiskIo,
1896 Volume,
1897 &PreviousFile,
1898 FileEntry,
1899 File);
1900
1901 FreePool (FileEntry);
1902
1903 if (EFI_ERROR (Status)) {
1904 return Status;
1905 }
1906 }
1907
1908 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
1909 sizeof (UDF_FILE_INFO)) != 0) {
1910 CleanupFileInformation (&PreviousFile);
1911 }
1912
1913 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
1914 if (*FilePath != L'\0' && *FilePath == L'\\') {
1915 FilePath++;
1916 }
1917 }
1918
1919 return Status;
1920 }
1921
1922 /**
1923 Read a directory entry at a time on an UDF volume.
1924
1925 @param[in] BlockIo BlockIo interface.
1926 @param[in] DiskIo DiskIo interface.
1927 @param[in] Volume UDF volume information structure.
1928 @param[in] ParentIcb ICB of the parent file.
1929 @param[in] FileEntryData FE/EFE of the parent file.
1930 @param[in, out] ReadDirInfo Next read directory listing structure
1931 information.
1932 @param[out] FoundFid File Identifier Descriptor pointer.
1933
1934 @retval EFI_SUCCESS Directory entry read.
1935 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
1936 @retval EFI_NO_MEDIA The device has no media.
1937 @retval EFI_DEVICE_ERROR The device reported an error.
1938 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1939 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
1940 resources.
1941
1942 **/
1943 EFI_STATUS
1944 ReadDirectoryEntry (
1945 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
1946 IN EFI_DISK_IO_PROTOCOL *DiskIo,
1947 IN UDF_VOLUME_INFO *Volume,
1948 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,
1949 IN VOID *FileEntryData,
1950 IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,
1951 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid
1952 )
1953 {
1954 EFI_STATUS Status;
1955 UDF_READ_FILE_INFO ReadFileInfo;
1956 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
1957
1958 if (ReadDirInfo->DirectoryData == NULL) {
1959 //
1960 // The directory's recorded data has not been read yet. So let's cache it
1961 // into memory and the next calls won't need to read it again.
1962 //
1963 ReadFileInfo.Flags = ReadFileAllocateAndRead;
1964
1965 Status = ReadFile (
1966 BlockIo,
1967 DiskIo,
1968 Volume,
1969 ParentIcb,
1970 FileEntryData,
1971 &ReadFileInfo
1972 );
1973 if (EFI_ERROR (Status)) {
1974 return Status;
1975 }
1976
1977 //
1978 // Fill in ReadDirInfo structure with the read directory's data information.
1979 //
1980 ReadDirInfo->DirectoryData = ReadFileInfo.FileData;
1981 ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;
1982 }
1983
1984 do {
1985 if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {
1986 //
1987 // There are no longer FIDs for this directory. By returning
1988 // EFI_DEVICE_ERROR to the callee will indicate end of directory
1989 // listening.
1990 //
1991 return EFI_DEVICE_ERROR;
1992 }
1993
1994 //
1995 // Get FID for this entry.
1996 //
1997 FileIdentifierDesc = GET_FID_FROM_ADS (ReadDirInfo->DirectoryData,
1998 ReadDirInfo->FidOffset);
1999 //
2000 // Update FidOffset to point to next FID.
2001 //
2002 ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);
2003 } while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);
2004
2005 DuplicateFid (FileIdentifierDesc, FoundFid);
2006 if (*FoundFid == NULL) {
2007 return EFI_OUT_OF_RESOURCES;
2008 }
2009
2010 return EFI_SUCCESS;
2011 }
2012
2013 /**
2014 Get a filename (encoded in OSTA-compressed format) from a File Identifier
2015 Descriptor on an UDF volume.
2016
2017 @attention This is boundary function that may receive untrusted input.
2018 @attention The input is from FileSystem.
2019
2020 The File Identifier Descriptor is external input, so this routine will do
2021 basic validation for File Identifier Descriptor and report status.
2022
2023 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.
2024 @param[in] CharMax The maximum number of FileName Unicode char,
2025 including terminating null char.
2026 @param[out] FileName Decoded filename.
2027
2028 @retval EFI_SUCCESS Filename decoded and read.
2029 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2030 @retval EFI_BUFFER_TOO_SMALL The string buffer FileName cannot hold the
2031 decoded filename.
2032 **/
2033 EFI_STATUS
2034 GetFileNameFromFid (
2035 IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,
2036 IN UINTN CharMax,
2037 OUT CHAR16 *FileName
2038 )
2039 {
2040 UINT8 *OstaCompressed;
2041 UINT8 CompressionId;
2042 UINT8 Length;
2043 UINTN Index;
2044 CHAR16 *FileNameBak;
2045
2046 if (CharMax == 0) {
2047 return EFI_BUFFER_TOO_SMALL;
2048 }
2049
2050 OstaCompressed =
2051 (UINT8 *)(
2052 (UINT8 *)FileIdentifierDesc->Data +
2053 FileIdentifierDesc->LengthOfImplementationUse
2054 );
2055
2056 CompressionId = OstaCompressed[0];
2057 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
2058 return EFI_VOLUME_CORRUPTED;
2059 }
2060
2061 FileNameBak = FileName;
2062
2063 //
2064 // Decode filename.
2065 //
2066 Length = FileIdentifierDesc->LengthOfFileIdentifier;
2067 if (CompressionId == 16) {
2068 if (((UINTN)Length >> 1) > CharMax) {
2069 return EFI_BUFFER_TOO_SMALL;
2070 }
2071 } else {
2072 if ((Length != 0) && ((UINTN)Length - 1 > CharMax)) {
2073 return EFI_BUFFER_TOO_SMALL;
2074 }
2075 }
2076
2077 for (Index = 1; Index < Length; Index++) {
2078 if (CompressionId == 16) {
2079 *FileName = OstaCompressed[Index++] << 8;
2080 } else {
2081 *FileName = 0;
2082 }
2083
2084 if (Index < Length) {
2085 *FileName |= (CHAR16)(OstaCompressed[Index]);
2086 }
2087
2088 FileName++;
2089 }
2090
2091 Index = ((UINTN)FileName - (UINTN)FileNameBak) / sizeof (CHAR16);
2092 if (Index > CharMax - 1) {
2093 Index = CharMax - 1;
2094 }
2095 FileNameBak[Index] = L'\0';
2096
2097 return EFI_SUCCESS;
2098 }
2099
2100 /**
2101 Resolve a symlink file on an UDF volume.
2102
2103 @attention This is boundary function that may receive untrusted input.
2104 @attention The input is from FileSystem.
2105
2106 The Path Component is external input, so this routine will do basic
2107 validation for Path Component and report status.
2108
2109 @param[in] BlockIo BlockIo interface.
2110 @param[in] DiskIo DiskIo interface.
2111 @param[in] Volume UDF volume information structure.
2112 @param[in] Parent Parent file.
2113 @param[in] FileEntryData FE/EFE structure pointer.
2114 @param[out] File Resolved file.
2115
2116 @retval EFI_SUCCESS Symlink file resolved.
2117 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2118 @retval EFI_NO_MEDIA The device has no media.
2119 @retval EFI_DEVICE_ERROR The device reported an error.
2120 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2121 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
2122 resources.
2123
2124 **/
2125 EFI_STATUS
2126 ResolveSymlink (
2127 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2128 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2129 IN UDF_VOLUME_INFO *Volume,
2130 IN UDF_FILE_INFO *Parent,
2131 IN VOID *FileEntryData,
2132 OUT UDF_FILE_INFO *File
2133 )
2134 {
2135 EFI_STATUS Status;
2136 UDF_READ_FILE_INFO ReadFileInfo;
2137 UINT8 *Data;
2138 UINT64 Length;
2139 UINT8 *EndData;
2140 UDF_PATH_COMPONENT *PathComp;
2141 UINT8 PathCompLength;
2142 CHAR16 FileName[UDF_FILENAME_LENGTH];
2143 CHAR16 *Char;
2144 UINTN Index;
2145 UINT8 CompressionId;
2146 UDF_FILE_INFO PreviousFile;
2147
2148 //
2149 // Symlink files on UDF volumes do not contain so much data other than
2150 // Path Components which resolves to real filenames, so it's OK to read in
2151 // all its data here -- usually the data will be inline with the FE/EFE for
2152 // lower filenames.
2153 //
2154 ReadFileInfo.Flags = ReadFileAllocateAndRead;
2155
2156 Status = ReadFile (
2157 BlockIo,
2158 DiskIo,
2159 Volume,
2160 &Parent->FileIdentifierDesc->Icb,
2161 FileEntryData,
2162 &ReadFileInfo
2163 );
2164 if (EFI_ERROR (Status)) {
2165 return Status;
2166 }
2167
2168 Length = ReadFileInfo.ReadLength;
2169
2170 Data = (UINT8 *)ReadFileInfo.FileData;
2171 EndData = Data + Length;
2172
2173 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
2174
2175 for (;;) {
2176 PathComp = (UDF_PATH_COMPONENT *)Data;
2177
2178 PathCompLength = PathComp->LengthOfComponentIdentifier;
2179
2180 switch (PathComp->ComponentType) {
2181 case 1:
2182 //
2183 // This Path Component specifies the root directory hierarchy subject to
2184 // agreement between the originator and recipient of the medium. Skip it.
2185 //
2186 // Fall through.
2187 //
2188 case 2:
2189 //
2190 // "\\." of the current directory. Read next Path Component.
2191 //
2192 goto Next_Path_Component;
2193 case 3:
2194 //
2195 // ".." (parent directory). Go to it.
2196 //
2197 CopyMem ((VOID *)FileName, L"..", 6);
2198 break;
2199 case 4:
2200 //
2201 // "." (current file). Duplicate both FE/EFE and FID of this file.
2202 //
2203 DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);
2204 if (File->FileEntry == NULL) {
2205 Status = EFI_OUT_OF_RESOURCES;
2206 goto Error_Find_File;
2207 }
2208
2209 DuplicateFid (PreviousFile.FileIdentifierDesc,
2210 &File->FileIdentifierDesc);
2211 if (File->FileIdentifierDesc == NULL) {
2212 FreePool (File->FileEntry);
2213 Status = EFI_OUT_OF_RESOURCES;
2214 goto Error_Find_File;
2215 }
2216 goto Next_Path_Component;
2217 case 5:
2218 //
2219 // This Path Component identifies an object, either a file or a
2220 // directory or an alias.
2221 //
2222 // Decode it from the compressed data in ComponentIdentifier and find
2223 // respective path.
2224 //
2225 CompressionId = PathComp->ComponentIdentifier[0];
2226 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
2227 return EFI_VOLUME_CORRUPTED;
2228 }
2229
2230 if ((UINTN)PathComp->ComponentIdentifier + PathCompLength > (UINTN)EndData) {
2231 return EFI_VOLUME_CORRUPTED;
2232 }
2233
2234 Char = FileName;
2235 for (Index = 1; Index < PathCompLength; Index++) {
2236 if (CompressionId == 16) {
2237 *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +
2238 Index) << 8;
2239 Index++;
2240 } else {
2241 if (Index > ARRAY_SIZE (FileName)) {
2242 return EFI_UNSUPPORTED;
2243 }
2244 *Char = 0;
2245 }
2246
2247 if (Index < Length) {
2248 *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));
2249 }
2250
2251 Char++;
2252 }
2253
2254 Index = ((UINTN)Char - (UINTN)FileName) / sizeof (CHAR16);
2255 if (Index > ARRAY_SIZE (FileName) - 1) {
2256 Index = ARRAY_SIZE (FileName) - 1;
2257 }
2258 FileName[Index] = L'\0';
2259 break;
2260 }
2261
2262 //
2263 // Find file from the read filename in symlink's file data.
2264 //
2265 Status = InternalFindFile (
2266 BlockIo,
2267 DiskIo,
2268 Volume,
2269 FileName,
2270 &PreviousFile,
2271 NULL,
2272 File
2273 );
2274 if (EFI_ERROR (Status)) {
2275 goto Error_Find_File;
2276 }
2277
2278 Next_Path_Component:
2279 Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;
2280 if (Data >= EndData) {
2281 break;
2282 }
2283
2284 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
2285 sizeof (UDF_FILE_INFO)) != 0) {
2286 CleanupFileInformation (&PreviousFile);
2287 }
2288
2289 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
2290 }
2291
2292 //
2293 // Unmap the symlink file.
2294 //
2295 FreePool (ReadFileInfo.FileData);
2296
2297 return EFI_SUCCESS;
2298
2299 Error_Find_File:
2300 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
2301 sizeof (UDF_FILE_INFO)) != 0) {
2302 CleanupFileInformation (&PreviousFile);
2303 }
2304
2305 FreePool (ReadFileInfo.FileData);
2306
2307 return Status;
2308 }
2309
2310 /**
2311 Clean up in-memory UDF file information.
2312
2313 @param[in] File File information pointer.
2314
2315 **/
2316 VOID
2317 CleanupFileInformation (
2318 IN UDF_FILE_INFO *File
2319 )
2320 {
2321 if (File->FileEntry != NULL) {
2322 FreePool (File->FileEntry);
2323 }
2324 if (File->FileIdentifierDesc != NULL) {
2325 FreePool ((VOID *)File->FileIdentifierDesc);
2326 }
2327
2328 ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));
2329 }
2330
2331 /**
2332 Find a file from its absolute path on an UDF volume.
2333
2334 @param[in] BlockIo BlockIo interface.
2335 @param[in] DiskIo DiskIo interface.
2336 @param[in] Volume UDF volume information structure.
2337 @param[in] File File information structure.
2338 @param[out] Size Size of the file.
2339
2340 @retval EFI_SUCCESS File size calculated and set in Size.
2341 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2342 @retval EFI_NO_MEDIA The device has no media.
2343 @retval EFI_DEVICE_ERROR The device reported an error.
2344 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2345 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
2346 resources.
2347
2348 **/
2349 EFI_STATUS
2350 GetFileSize (
2351 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2352 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2353 IN UDF_VOLUME_INFO *Volume,
2354 IN UDF_FILE_INFO *File,
2355 OUT UINT64 *Size
2356 )
2357 {
2358 EFI_STATUS Status;
2359 UDF_READ_FILE_INFO ReadFileInfo;
2360
2361 ReadFileInfo.Flags = ReadFileGetFileSize;
2362
2363 Status = ReadFile (
2364 BlockIo,
2365 DiskIo,
2366 Volume,
2367 &File->FileIdentifierDesc->Icb,
2368 File->FileEntry,
2369 &ReadFileInfo
2370 );
2371 if (EFI_ERROR (Status)) {
2372 return Status;
2373 }
2374
2375 *Size = ReadFileInfo.ReadLength;
2376
2377 return EFI_SUCCESS;
2378 }
2379
2380 /**
2381 Set information about a file on an UDF volume.
2382
2383 @param[in] File File pointer.
2384 @param[in] FileSize Size of the file.
2385 @param[in] FileName Filename of the file.
2386 @param[in, out] BufferSize Size of the returned file infomation.
2387 @param[out] Buffer Data of the returned file information.
2388
2389 @retval EFI_SUCCESS File information set.
2390 @retval EFI_NO_MEDIA The device has no media.
2391 @retval EFI_DEVICE_ERROR The device reported an error.
2392 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2393 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
2394 resources.
2395
2396 **/
2397 EFI_STATUS
2398 SetFileInfo (
2399 IN UDF_FILE_INFO *File,
2400 IN UINT64 FileSize,
2401 IN CHAR16 *FileName,
2402 IN OUT UINTN *BufferSize,
2403 OUT VOID *Buffer
2404 )
2405 {
2406 UINTN FileInfoLength;
2407 EFI_FILE_INFO *FileInfo;
2408 UDF_FILE_ENTRY *FileEntry;
2409 UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;
2410 UDF_DESCRIPTOR_TAG *DescriptorTag;
2411
2412 //
2413 // Calculate the needed size for the EFI_FILE_INFO structure.
2414 //
2415 FileInfoLength = sizeof (EFI_FILE_INFO) + ((FileName != NULL) ?
2416 StrSize (FileName) :
2417 sizeof (CHAR16));
2418 if (*BufferSize < FileInfoLength) {
2419 //
2420 // The given Buffer has no size enough for EFI_FILE_INFO structure.
2421 //
2422 *BufferSize = FileInfoLength;
2423 return EFI_BUFFER_TOO_SMALL;
2424 }
2425
2426 //
2427 // Buffer now contains room enough to store EFI_FILE_INFO structure.
2428 // Now, fill it in with all necessary information about the file.
2429 //
2430 FileInfo = (EFI_FILE_INFO *)Buffer;
2431 FileInfo->Size = FileInfoLength;
2432 FileInfo->Attribute &= ~EFI_FILE_VALID_ATTR;
2433 FileInfo->Attribute |= EFI_FILE_READ_ONLY;
2434
2435 if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {
2436 FileInfo->Attribute |= EFI_FILE_DIRECTORY;
2437 } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {
2438 FileInfo->Attribute |= EFI_FILE_ARCHIVE;
2439 }
2440
2441 if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {
2442 FileInfo->Attribute |= EFI_FILE_HIDDEN;
2443 }
2444
2445 DescriptorTag = File->FileEntry;
2446
2447 if (DescriptorTag->TagIdentifier == UdfFileEntry) {
2448 FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;
2449
2450 //
2451 // Check if FE has the system attribute set.
2452 //
2453 if (FileEntry->IcbTag.Flags & (1 << 10)) {
2454 FileInfo->Attribute |= EFI_FILE_SYSTEM;
2455 }
2456
2457 FileInfo->FileSize = FileSize;
2458 FileInfo->PhysicalSize = FileSize;
2459
2460 FileInfo->CreateTime.Year = FileEntry->AccessTime.Year;
2461 FileInfo->CreateTime.Month = FileEntry->AccessTime.Month;
2462 FileInfo->CreateTime.Day = FileEntry->AccessTime.Day;
2463 FileInfo->CreateTime.Hour = FileEntry->AccessTime.Hour;
2464 FileInfo->CreateTime.Minute = FileEntry->AccessTime.Minute;
2465 FileInfo->CreateTime.Second = FileEntry->AccessTime.Second;
2466 FileInfo->CreateTime.Nanosecond =
2467 FileEntry->AccessTime.HundredsOfMicroseconds;
2468
2469 FileInfo->LastAccessTime.Year =
2470 FileEntry->AccessTime.Year;
2471 FileInfo->LastAccessTime.Month =
2472 FileEntry->AccessTime.Month;
2473 FileInfo->LastAccessTime.Day =
2474 FileEntry->AccessTime.Day;
2475 FileInfo->LastAccessTime.Hour =
2476 FileEntry->AccessTime.Hour;
2477 FileInfo->LastAccessTime.Minute =
2478 FileEntry->AccessTime.Minute;
2479 FileInfo->LastAccessTime.Second =
2480 FileEntry->AccessTime.Second;
2481 FileInfo->LastAccessTime.Nanosecond =
2482 FileEntry->AccessTime.HundredsOfMicroseconds;
2483 } else if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
2484 ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;
2485
2486 //
2487 // Check if EFE has the system attribute set.
2488 //
2489 if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {
2490 FileInfo->Attribute |= EFI_FILE_SYSTEM;
2491 }
2492
2493 FileInfo->FileSize = FileSize;
2494 FileInfo->PhysicalSize = FileSize;
2495
2496 FileInfo->CreateTime.Year = ExtendedFileEntry->CreationTime.Year;
2497 FileInfo->CreateTime.Month = ExtendedFileEntry->CreationTime.Month;
2498 FileInfo->CreateTime.Day = ExtendedFileEntry->CreationTime.Day;
2499 FileInfo->CreateTime.Hour = ExtendedFileEntry->CreationTime.Hour;
2500 FileInfo->CreateTime.Minute = ExtendedFileEntry->CreationTime.Second;
2501 FileInfo->CreateTime.Second = ExtendedFileEntry->CreationTime.Second;
2502 FileInfo->CreateTime.Nanosecond =
2503 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
2504
2505 FileInfo->LastAccessTime.Year =
2506 ExtendedFileEntry->AccessTime.Year;
2507 FileInfo->LastAccessTime.Month =
2508 ExtendedFileEntry->AccessTime.Month;
2509 FileInfo->LastAccessTime.Day =
2510 ExtendedFileEntry->AccessTime.Day;
2511 FileInfo->LastAccessTime.Hour =
2512 ExtendedFileEntry->AccessTime.Hour;
2513 FileInfo->LastAccessTime.Minute =
2514 ExtendedFileEntry->AccessTime.Minute;
2515 FileInfo->LastAccessTime.Second =
2516 ExtendedFileEntry->AccessTime.Second;
2517 FileInfo->LastAccessTime.Nanosecond =
2518 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
2519 }
2520
2521 FileInfo->CreateTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
2522 FileInfo->CreateTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
2523 FileInfo->LastAccessTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
2524 FileInfo->LastAccessTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
2525
2526 CopyMem ((VOID *)&FileInfo->ModificationTime,
2527 (VOID *)&FileInfo->LastAccessTime,
2528 sizeof (EFI_TIME));
2529
2530 if (FileName != NULL) {
2531 StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);
2532 } else {
2533 FileInfo->FileName[0] = '\0';
2534 }
2535
2536 *BufferSize = FileInfoLength;
2537
2538 return EFI_SUCCESS;
2539 }
2540
2541 /**
2542 Get volume label of an UDF volume.
2543
2544 @attention This is boundary function that may receive untrusted input.
2545 @attention The input is from FileSystem.
2546
2547 The File Set Descriptor is external input, so this routine will do basic
2548 validation for File Set Descriptor and report status.
2549
2550 @param[in] Volume Volume information pointer.
2551 @param[in] CharMax The maximum number of Unicode char in String,
2552 including terminating null char.
2553 @param[out] String String buffer pointer to store the volume label.
2554
2555 @retval EFI_SUCCESS Volume label is returned.
2556 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2557 @retval EFI_BUFFER_TOO_SMALL The string buffer String cannot hold the
2558 volume label.
2559
2560 **/
2561 EFI_STATUS
2562 GetVolumeLabel (
2563 IN UDF_VOLUME_INFO *Volume,
2564 IN UINTN CharMax,
2565 OUT CHAR16 *String
2566 )
2567 {
2568 UDF_FILE_SET_DESCRIPTOR *FileSetDesc;
2569 UINTN Index;
2570 UINT8 *OstaCompressed;
2571 UINT8 CompressionId;
2572 CHAR16 *StringBak;
2573
2574 FileSetDesc = &Volume->FileSetDesc;
2575
2576 OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];
2577
2578 CompressionId = OstaCompressed[0];
2579 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
2580 return EFI_VOLUME_CORRUPTED;
2581 }
2582
2583 StringBak = String;
2584 for (Index = 1; Index < 128; Index++) {
2585 if (CompressionId == 16) {
2586 if ((Index >> 1) > CharMax) {
2587 return EFI_BUFFER_TOO_SMALL;
2588 }
2589
2590 *String = *(UINT8 *)(OstaCompressed + Index) << 8;
2591 Index++;
2592 } else {
2593 if (Index > CharMax) {
2594 return EFI_BUFFER_TOO_SMALL;
2595 }
2596
2597 *String = 0;
2598 }
2599
2600 if (Index < 128) {
2601 *String |= (CHAR16)(*(UINT8 *)(OstaCompressed + Index));
2602 }
2603
2604 //
2605 // Unlike FID Identifiers, Logical Volume Identifier is stored in a
2606 // NULL-terminated OSTA compressed format, so we must check for the NULL
2607 // character.
2608 //
2609 if (*String == L'\0') {
2610 break;
2611 }
2612
2613 String++;
2614 }
2615
2616 Index = ((UINTN)String - (UINTN)StringBak) / sizeof (CHAR16);
2617 if (Index > CharMax - 1) {
2618 Index = CharMax - 1;
2619 }
2620 StringBak[Index] = L'\0';
2621
2622 return EFI_SUCCESS;
2623 }
2624
2625 /**
2626 Get volume and free space size information of an UDF volume.
2627
2628 @attention This is boundary function that may receive untrusted input.
2629 @attention The input is from FileSystem.
2630
2631 The Logical Volume Descriptor and the Logical Volume Integrity Descriptor are
2632 external inputs, so this routine will do basic validation for both descriptors
2633 and report status.
2634
2635 @param[in] BlockIo BlockIo interface.
2636 @param[in] DiskIo DiskIo interface.
2637 @param[in] Volume UDF volume information structure.
2638 @param[out] VolumeSize Volume size.
2639 @param[out] FreeSpaceSize Free space size.
2640
2641 @retval EFI_SUCCESS Volume and free space size calculated.
2642 @retval EFI_NO_MEDIA The device has no media.
2643 @retval EFI_DEVICE_ERROR The device reported an error.
2644 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2645 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
2646 calculated due to lack of resources.
2647
2648 **/
2649 EFI_STATUS
2650 GetVolumeSize (
2651 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2652 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2653 IN UDF_VOLUME_INFO *Volume,
2654 OUT UINT64 *VolumeSize,
2655 OUT UINT64 *FreeSpaceSize
2656 )
2657 {
2658 EFI_STATUS Status;
2659 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;
2660 UDF_EXTENT_AD *ExtentAd;
2661 UINT64 Lsn;
2662 UINT32 LogicalBlockSize;
2663 UDF_LOGICAL_VOLUME_INTEGRITY *LogicalVolInt;
2664 UDF_DESCRIPTOR_TAG *DescriptorTag;
2665 UINTN Index;
2666 UINTN Length;
2667 UINT32 LsnsNo;
2668
2669 LogicalVolDesc = &Volume->LogicalVolDesc;
2670
2671 ExtentAd = &LogicalVolDesc->IntegritySequenceExtent;
2672
2673 if ((ExtentAd->ExtentLength == 0) ||
2674 (ExtentAd->ExtentLength < sizeof (UDF_LOGICAL_VOLUME_INTEGRITY))) {
2675 return EFI_VOLUME_CORRUPTED;
2676 }
2677
2678 LogicalVolInt = AllocatePool (ExtentAd->ExtentLength);
2679 if (LogicalVolInt == NULL) {
2680 return EFI_OUT_OF_RESOURCES;
2681 }
2682
2683 //
2684 // Get location of Logical Volume Integrity Descriptor
2685 //
2686 Lsn = (UINT64)ExtentAd->ExtentLocation - Volume->MainVdsStartLocation;
2687
2688 LogicalBlockSize = LogicalVolDesc->LogicalBlockSize;
2689
2690 //
2691 // Read disk block
2692 //
2693 Status = DiskIo->ReadDisk (
2694 DiskIo,
2695 BlockIo->Media->MediaId,
2696 MultU64x32 (Lsn, LogicalBlockSize),
2697 ExtentAd->ExtentLength,
2698 LogicalVolInt
2699 );
2700 if (EFI_ERROR (Status)) {
2701 goto Out_Free;
2702 }
2703
2704 DescriptorTag = &LogicalVolInt->DescriptorTag;
2705
2706 //
2707 // Check if read block is a Logical Volume Integrity Descriptor
2708 //
2709 if (DescriptorTag->TagIdentifier != UdfLogicalVolumeIntegrityDescriptor) {
2710 Status = EFI_VOLUME_CORRUPTED;
2711 goto Out_Free;
2712 }
2713
2714 if ((LogicalVolInt->NumberOfPartitions > MAX_UINT32 / sizeof (UINT32) / 2) ||
2715 (LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2 >
2716 ExtentAd->ExtentLength - sizeof (UDF_LOGICAL_VOLUME_INTEGRITY))) {
2717 Status = EFI_VOLUME_CORRUPTED;
2718 goto Out_Free;
2719 }
2720
2721 *VolumeSize = 0;
2722 *FreeSpaceSize = 0;
2723
2724 Length = LogicalVolInt->NumberOfPartitions;
2725 for (Index = 0; Index < Length; Index += sizeof (UINT32)) {
2726 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
2727 //
2728 // Check if size is not specified
2729 //
2730 if (LsnsNo == 0xFFFFFFFFUL) {
2731 continue;
2732 }
2733 //
2734 // Accumulate free space size
2735 //
2736 *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
2737 }
2738
2739 Length = LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2;
2740 for (; Index < Length; Index += sizeof (UINT32)) {
2741 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
2742 //
2743 // Check if size is not specified
2744 //
2745 if (LsnsNo == 0xFFFFFFFFUL) {
2746 continue;
2747 }
2748 //
2749 // Accumulate used volume space
2750 //
2751 *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
2752 }
2753
2754 Status = EFI_SUCCESS;
2755
2756 Out_Free:
2757 //
2758 // Free Logical Volume Integrity Descriptor
2759 //
2760 FreePool (LogicalVolInt);
2761
2762 return Status;
2763 }
2764
2765 /**
2766 Seek a file and read its data into memory on an UDF volume.
2767
2768 @param[in] BlockIo BlockIo interface.
2769 @param[in] DiskIo DiskIo interface.
2770 @param[in] Volume UDF volume information structure.
2771 @param[in] File File information structure.
2772 @param[in] FileSize Size of the file.
2773 @param[in, out] FilePosition File position.
2774 @param[in, out] Buffer File data.
2775 @param[in, out] BufferSize Read size.
2776
2777 @retval EFI_SUCCESS File seeked and read.
2778 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.
2779 @retval EFI_NO_MEDIA The device has no media.
2780 @retval EFI_DEVICE_ERROR The device reported an error.
2781 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2782 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
2783 of resources.
2784
2785 **/
2786 EFI_STATUS
2787 ReadFileData (
2788 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
2789 IN EFI_DISK_IO_PROTOCOL *DiskIo,
2790 IN UDF_VOLUME_INFO *Volume,
2791 IN UDF_FILE_INFO *File,
2792 IN UINT64 FileSize,
2793 IN OUT UINT64 *FilePosition,
2794 IN OUT VOID *Buffer,
2795 IN OUT UINT64 *BufferSize
2796 )
2797 {
2798 EFI_STATUS Status;
2799 UDF_READ_FILE_INFO ReadFileInfo;
2800
2801 ReadFileInfo.Flags = ReadFileSeekAndRead;
2802 ReadFileInfo.FilePosition = *FilePosition;
2803 ReadFileInfo.FileData = Buffer;
2804 ReadFileInfo.FileDataSize = *BufferSize;
2805 ReadFileInfo.FileSize = FileSize;
2806
2807 Status = ReadFile (
2808 BlockIo,
2809 DiskIo,
2810 Volume,
2811 &File->FileIdentifierDesc->Icb,
2812 File->FileEntry,
2813 &ReadFileInfo
2814 );
2815 if (EFI_ERROR (Status)) {
2816 return Status;
2817 }
2818
2819 *BufferSize = ReadFileInfo.FileDataSize;
2820 *FilePosition = ReadFileInfo.FilePosition;
2821
2822 return EFI_SUCCESS;
2823 }
2824
2825 /**
2826 Check if ControllerHandle supports an UDF file system.
2827
2828 @param[in] This Protocol instance pointer.
2829 @param[in] ControllerHandle Handle of device to test.
2830
2831 @retval EFI_SUCCESS UDF file system found.
2832 @retval EFI_UNSUPPORTED UDF file system not found.
2833
2834 **/
2835 EFI_STATUS
2836 SupportUdfFileSystem (
2837 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2838 IN EFI_HANDLE ControllerHandle
2839 )
2840 {
2841 EFI_STATUS Status;
2842 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2843 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
2844 EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;
2845 EFI_GUID *VendorDefinedGuid;
2846
2847 //
2848 // Open Device Path protocol on ControllerHandle
2849 //
2850 Status = gBS->OpenProtocol (
2851 ControllerHandle,
2852 &gEfiDevicePathProtocolGuid,
2853 (VOID **)&DevicePath,
2854 This->DriverBindingHandle,
2855 ControllerHandle,
2856 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2857 );
2858 if (EFI_ERROR (Status)) {
2859 return EFI_UNSUPPORTED;
2860 }
2861
2862 Status = EFI_UNSUPPORTED;
2863
2864 //
2865 // Get last Device Path node
2866 //
2867 LastDevicePathNode = NULL;
2868 DevicePathNode = DevicePath;
2869 while (!IsDevicePathEnd (DevicePathNode)) {
2870 LastDevicePathNode = DevicePathNode;
2871 DevicePathNode = NextDevicePathNode (DevicePathNode);
2872 }
2873 //
2874 // Check if last Device Path node contains a Vendor-Defined Media Device Path
2875 // of an UDF file system.
2876 //
2877 if (LastDevicePathNode != NULL &&
2878 DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&
2879 DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP) {
2880 VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +
2881 OFFSET_OF (VENDOR_DEVICE_PATH, Guid));
2882 if (CompareGuid (VendorDefinedGuid, &gUdfDevPathGuid)) {
2883 Status = EFI_SUCCESS;
2884 }
2885 }
2886
2887 //
2888 // Close Device Path protocol on ControllerHandle
2889 //
2890 gBS->CloseProtocol (
2891 ControllerHandle,
2892 &gEfiDevicePathProtocolGuid,
2893 This->DriverBindingHandle,
2894 ControllerHandle
2895 );
2896
2897 return Status;
2898 }