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