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