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