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