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