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