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