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