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