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