]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
MdeModulePkg/UdfDxe: Handle dead codes in FileSystemOperations.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
5317e9cc
HW
741 //\r
742 // Code should never reach here.\r
743 //\r
744 ASSERT (FALSE);\r
99c9b949
PA
745 return EFI_DEVICE_ERROR;\r
746}\r
747\r
077f8c43
HW
748/**\r
749 Return logical sector number of either Short or Long Allocation Descriptor.\r
750\r
751 @param[in] RecordingFlags Flag to indicate the type of descriptor.\r
752 @param[in] Volume Volume information pointer.\r
753 @param[in] ParentIcb Long Allocation Descriptor pointer.\r
754 @param[in] Ad Allocation Descriptor pointer.\r
6086569e 755 @param[out] Lsn Logical sector number pointer.\r
077f8c43 756\r
6086569e
HW
757 @retval EFI_SUCCESS Logical sector number of the given Allocation\r
758 Descriptor successfully returned.\r
759 @retval EFI_UNSUPPORTED Logical sector number of the given Allocation\r
760 Descriptor is not returned due to unrecognized\r
761 format.\r
077f8c43
HW
762\r
763**/\r
6086569e 764EFI_STATUS\r
99c9b949 765GetAllocationDescriptorLsn (\r
6086569e
HW
766 IN UDF_FE_RECORDING_FLAGS RecordingFlags,\r
767 IN UDF_VOLUME_INFO *Volume,\r
768 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
769 IN VOID *Ad,\r
770 OUT UINT64 *Lsn\r
99c9b949
PA
771 )\r
772{\r
ce9aaba6
HW
773 UDF_PARTITION_DESCRIPTOR *PartitionDesc;\r
774\r
880ec683 775 if (RecordingFlags == LongAdsSequence) {\r
6086569e 776 return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad, Lsn);\r
880ec683 777 } else if (RecordingFlags == ShortAdsSequence) {\r
ce9aaba6 778 PartitionDesc = GetPdFromLongAd (Volume, ParentIcb);\r
6086569e
HW
779 if (PartitionDesc == NULL) {\r
780 return EFI_UNSUPPORTED;\r
781 }\r
ce9aaba6 782\r
6086569e
HW
783 *Lsn = GetShortAdLsn (\r
784 Volume,\r
785 PartitionDesc,\r
786 (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad\r
787 );\r
788 return EFI_SUCCESS;\r
99c9b949
PA
789 }\r
790\r
5317e9cc
HW
791 //\r
792 // Code should never reach here.\r
793 //\r
794 ASSERT (FALSE);\r
6086569e 795 return EFI_UNSUPPORTED;\r
99c9b949
PA
796}\r
797\r
077f8c43
HW
798/**\r
799 Return offset + length of a given indirect Allocation Descriptor (AED).\r
800\r
801 @param[in] BlockIo BlockIo interface.\r
802 @param[in] DiskIo DiskIo interface.\r
803 @param[in] Volume Volume information pointer.\r
804 @param[in] ParentIcb Long Allocation Descriptor pointer.\r
805 @param[in] RecordingFlags Flag to indicate the type of descriptor.\r
806 @param[in] Ad Allocation Descriptor pointer.\r
807 @param[out] Offset Offset of a given indirect Allocation\r
808 Descriptor.\r
809 @param[out] Length Length of a given indirect Allocation\r
810 Descriptor.\r
811\r
812 @retval EFI_SUCCESS The offset and length were returned.\r
813 @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due\r
814 to lack of resources.\r
815 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
816 @retval other The offset and length were not returned.\r
817\r
818**/\r
99c9b949
PA
819EFI_STATUS\r
820GetAedAdsOffset (\r
821 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
822 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
823 IN UDF_VOLUME_INFO *Volume,\r
824 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
825 IN UDF_FE_RECORDING_FLAGS RecordingFlags,\r
826 IN VOID *Ad,\r
827 OUT UINT64 *Offset,\r
828 OUT UINT64 *Length\r
829 )\r
830{\r
831 EFI_STATUS Status;\r
832 UINT32 ExtentLength;\r
833 UINT64 Lsn;\r
834 VOID *Data;\r
835 UINT32 LogicalBlockSize;\r
836 UDF_ALLOCATION_EXTENT_DESCRIPTOR *AllocExtDesc;\r
baaa3cee 837 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
99c9b949
PA
838\r
839 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
6086569e 840 Status = GetAllocationDescriptorLsn (RecordingFlags,\r
99c9b949
PA
841 Volume,\r
842 ParentIcb,\r
6086569e
HW
843 Ad,\r
844 &Lsn);\r
845 if (EFI_ERROR (Status)) {\r
846 return Status;\r
847 }\r
99c9b949
PA
848\r
849 Data = AllocatePool (ExtentLength);\r
850 if (Data == NULL) {\r
851 return EFI_OUT_OF_RESOURCES;\r
852 }\r
853\r
baaa3cee 854 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;\r
99c9b949
PA
855\r
856 //\r
857 // Read extent.\r
858 //\r
859 Status = DiskIo->ReadDisk (\r
860 DiskIo,\r
861 BlockIo->Media->MediaId,\r
862 MultU64x32 (Lsn, LogicalBlockSize),\r
863 ExtentLength,\r
864 Data\r
865 );\r
866 if (EFI_ERROR (Status)) {\r
867 goto Exit;\r
868 }\r
869\r
baaa3cee
PA
870 AllocExtDesc = (UDF_ALLOCATION_EXTENT_DESCRIPTOR *)Data;\r
871\r
872 DescriptorTag = &AllocExtDesc->DescriptorTag;\r
873\r
99c9b949
PA
874 //\r
875 // Check if read extent contains a valid tag identifier for AED.\r
876 //\r
baaa3cee 877 if (DescriptorTag->TagIdentifier != UdfAllocationExtentDescriptor) {\r
99c9b949
PA
878 Status = EFI_VOLUME_CORRUPTED;\r
879 goto Exit;\r
880 }\r
881\r
882 //\r
883 // Get AED's block offset and its length.\r
884 //\r
885 *Offset = MultU64x32 (Lsn, LogicalBlockSize) +\r
886 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR);\r
887 *Length = AllocExtDesc->LengthOfAllocationDescriptors;\r
888\r
889Exit:\r
890 FreePool (Data);\r
891\r
892 return Status;\r
893}\r
894\r
077f8c43
HW
895/**\r
896 Read Allocation Extent Descriptor into memory.\r
897\r
898 @param[in] BlockIo BlockIo interface.\r
899 @param[in] DiskIo DiskIo interface.\r
900 @param[in] Volume Volume information pointer.\r
901 @param[in] ParentIcb Long Allocation Descriptor pointer.\r
902 @param[in] RecordingFlags Flag to indicate the type of descriptor.\r
903 @param[in] Ad Allocation Descriptor pointer.\r
904 @param[out] Data Buffer that contains the Allocation Extent\r
905 Descriptor.\r
906 @param[out] Length Length of Data.\r
907\r
908 @retval EFI_SUCCESS The Allocation Extent Descriptor was read.\r
909 @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read\r
910 due to lack of resources.\r
911 @retval other Fail to read the disk.\r
912\r
913**/\r
99c9b949
PA
914EFI_STATUS\r
915GetAedAdsData (\r
916 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
917 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
918 IN UDF_VOLUME_INFO *Volume,\r
919 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
920 IN UDF_FE_RECORDING_FLAGS RecordingFlags,\r
921 IN VOID *Ad,\r
922 OUT VOID **Data,\r
923 OUT UINT64 *Length\r
924 )\r
925{\r
926 EFI_STATUS Status;\r
927 UINT64 Offset;\r
928\r
929 //\r
930 // Get AED's offset + length.\r
931 //\r
932 Status = GetAedAdsOffset (\r
933 BlockIo,\r
934 DiskIo,\r
935 Volume,\r
936 ParentIcb,\r
937 RecordingFlags,\r
938 Ad,\r
939 &Offset,\r
940 Length\r
941 );\r
942 if (EFI_ERROR (Status)) {\r
943 return Status;\r
944 }\r
945\r
946 //\r
947 // Allocate buffer to read in AED's data.\r
948 //\r
0b4c8f00 949 *Data = AllocatePool ((UINTN) (*Length));\r
99c9b949
PA
950 if (*Data == NULL) {\r
951 return EFI_OUT_OF_RESOURCES;\r
952 }\r
953\r
954 return DiskIo->ReadDisk (\r
955 DiskIo,\r
956 BlockIo->Media->MediaId,\r
957 Offset,\r
0b4c8f00 958 (UINTN) (*Length),\r
99c9b949
PA
959 *Data\r
960 );\r
961}\r
962\r
077f8c43
HW
963/**\r
964 Function used to serialise reads of Allocation Descriptors.\r
965\r
966 @param[in] RecordingFlags Flag to indicate the type of descriptor.\r
967 @param[in] Ad Allocation Descriptor pointer.\r
968 @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.\r
969 @param[in] Length Length of Buffer.\r
970\r
971 @retval EFI_SUCCESS Buffer was grown to hold the next Allocation\r
972 Descriptor.\r
973 @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.\r
974\r
975**/\r
99c9b949
PA
976EFI_STATUS\r
977GrowUpBufferToNextAd (\r
978 IN UDF_FE_RECORDING_FLAGS RecordingFlags,\r
979 IN VOID *Ad,\r
980 IN OUT VOID **Buffer,\r
981 IN UINT64 Length\r
982 )\r
983{\r
984 UINT32 ExtentLength;\r
985\r
986 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
987\r
988 if (*Buffer == NULL) {\r
989 *Buffer = AllocatePool (ExtentLength);\r
990 if (*Buffer == NULL) {\r
991 return EFI_OUT_OF_RESOURCES;\r
992 }\r
993 } else {\r
0b4c8f00 994 *Buffer = ReallocatePool ((UINTN) Length, (UINTN) (Length + ExtentLength), *Buffer);\r
99c9b949
PA
995 if (*Buffer == NULL) {\r
996 return EFI_OUT_OF_RESOURCES;\r
997 }\r
998 }\r
999\r
1000 return EFI_SUCCESS;\r
1001}\r
1002\r
077f8c43
HW
1003/**\r
1004 Read data or size of either a File Entry or an Extended File Entry.\r
1005\r
1006 @param[in] BlockIo BlockIo interface.\r
1007 @param[in] DiskIo DiskIo interface.\r
1008 @param[in] Volume Volume information pointer.\r
1009 @param[in] ParentIcb Long Allocation Descriptor pointer.\r
1010 @param[in] FileEntryData FE/EFE structure pointer.\r
1011 @param[in, out] ReadFileInfo Read file information pointer.\r
1012\r
1013 @retval EFI_SUCCESS Data or size of a FE/EFE was read.\r
1014 @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to\r
1015 lack of resources.\r
1016 @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is\r
1017 invalid.\r
1018 @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData\r
1019 is not supported.\r
1020 @retval other Data or size of a FE/EFE was not read.\r
1021\r
1022**/\r
99c9b949
PA
1023EFI_STATUS\r
1024ReadFile (\r
1025 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1026 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1027 IN UDF_VOLUME_INFO *Volume,\r
1028 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
1029 IN VOID *FileEntryData,\r
1030 IN OUT UDF_READ_FILE_INFO *ReadFileInfo\r
1031 )\r
1032{\r
1033 EFI_STATUS Status;\r
1034 UINT32 LogicalBlockSize;\r
1035 VOID *Data;\r
1036 UINT64 Length;\r
1037 VOID *Ad;\r
1038 UINT64 AdOffset;\r
1039 UINT64 Lsn;\r
1040 BOOLEAN DoFreeAed;\r
1041 UINT64 FilePosition;\r
1042 UINT64 Offset;\r
1043 UINT64 DataOffset;\r
1044 UINT64 BytesLeft;\r
1045 UINT64 DataLength;\r
1046 BOOLEAN FinishedSeeking;\r
1047 UINT32 ExtentLength;\r
1048 UDF_FE_RECORDING_FLAGS RecordingFlags;\r
1049\r
baaa3cee 1050 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;\r
99c9b949
PA
1051 DoFreeAed = FALSE;\r
1052\r
5afa5b81
LE
1053 //\r
1054 // set BytesLeft to suppress incorrect compiler/analyzer warnings\r
1055 //\r
1056 BytesLeft = 0;\r
54537008
SZ
1057 DataOffset = 0;\r
1058 FilePosition = 0;\r
1059 FinishedSeeking = FALSE;\r
1060 Data = NULL;\r
5afa5b81 1061\r
99c9b949 1062 switch (ReadFileInfo->Flags) {\r
880ec683
HW
1063 case ReadFileGetFileSize:\r
1064 case ReadFileAllocateAndRead:\r
99c9b949
PA
1065 //\r
1066 // Initialise ReadFileInfo structure for either getting file size, or\r
1067 // reading file's recorded data.\r
1068 //\r
1069 ReadFileInfo->ReadLength = 0;\r
1070 ReadFileInfo->FileData = NULL;\r
1071 break;\r
880ec683 1072 case ReadFileSeekAndRead:\r
99c9b949
PA
1073 //\r
1074 // About to seek a file and/or read its data.\r
1075 //\r
1076 Length = ReadFileInfo->FileSize - ReadFileInfo->FilePosition;\r
1077 if (ReadFileInfo->FileDataSize > Length) {\r
1078 //\r
1079 // About to read beyond the EOF -- truncate it.\r
1080 //\r
1081 ReadFileInfo->FileDataSize = Length;\r
1082 }\r
1083\r
1084 //\r
1085 // Initialise data to start seeking and/or reading a file.\r
1086 //\r
1087 BytesLeft = ReadFileInfo->FileDataSize;\r
1088 DataOffset = 0;\r
1089 FilePosition = 0;\r
1090 FinishedSeeking = FALSE;\r
1091\r
1092 break;\r
1093 }\r
1094\r
1095 RecordingFlags = GET_FE_RECORDING_FLAGS (FileEntryData);\r
1096 switch (RecordingFlags) {\r
880ec683 1097 case InlineData:\r
99c9b949
PA
1098 //\r
1099 // There are no extents for this FE/EFE. All data is inline.\r
1100 //\r
1101 GetFileEntryData (FileEntryData, &Data, &Length);\r
1102\r
880ec683 1103 if (ReadFileInfo->Flags == ReadFileGetFileSize) {\r
99c9b949 1104 ReadFileInfo->ReadLength = Length;\r
880ec683 1105 } else if (ReadFileInfo->Flags == ReadFileAllocateAndRead) {\r
99c9b949
PA
1106 //\r
1107 // Allocate buffer for starting read data.\r
1108 //\r
0b4c8f00 1109 ReadFileInfo->FileData = AllocatePool ((UINTN) Length);\r
99c9b949
PA
1110 if (ReadFileInfo->FileData == NULL) {\r
1111 return EFI_OUT_OF_RESOURCES;\r
1112 }\r
1113\r
1114 //\r
1115 // Read all inline data into ReadFileInfo->FileData\r
1116 //\r
0b4c8f00 1117 CopyMem (ReadFileInfo->FileData, Data, (UINTN) Length);\r
99c9b949 1118 ReadFileInfo->ReadLength = Length;\r
880ec683 1119 } else if (ReadFileInfo->Flags == ReadFileSeekAndRead) {\r
99c9b949
PA
1120 //\r
1121 // If FilePosition is non-zero, seek file to FilePosition, read\r
1122 // FileDataSize bytes and then updates FilePosition.\r
1123 //\r
1124 CopyMem (\r
1125 ReadFileInfo->FileData,\r
1126 (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition),\r
0b4c8f00 1127 (UINTN) ReadFileInfo->FileDataSize\r
99c9b949
PA
1128 );\r
1129\r
1130 ReadFileInfo->FilePosition += ReadFileInfo->FileDataSize;\r
a3240c63
LE
1131 } else {\r
1132 ASSERT (FALSE);\r
1133 return EFI_INVALID_PARAMETER;\r
99c9b949
PA
1134 }\r
1135\r
131fd40f 1136 Status = EFI_SUCCESS;\r
99c9b949 1137 break;\r
131fd40f 1138\r
880ec683
HW
1139 case LongAdsSequence:\r
1140 case ShortAdsSequence:\r
99c9b949
PA
1141 //\r
1142 // This FE/EFE contains a run of Allocation Descriptors. Get data + size\r
1143 // for start reading them out.\r
1144 //\r
1145 GetAdsInformation (FileEntryData, &Data, &Length);\r
1146 AdOffset = 0;\r
1147\r
1148 for (;;) {\r
1149 //\r
1150 // Read AD.\r
1151 //\r
1152 Status = GetAllocationDescriptor (\r
1153 RecordingFlags,\r
1154 Data,\r
1155 &AdOffset,\r
1156 Length,\r
1157 &Ad\r
1158 );\r
1159 if (Status == EFI_DEVICE_ERROR) {\r
1160 Status = EFI_SUCCESS;\r
1161 goto Done;\r
1162 }\r
1163\r
1164 //\r
1165 // Check if AD is an indirect AD. If so, read Allocation Extent\r
1166 // Descriptor and its extents (ADs).\r
1167 //\r
880ec683 1168 if (GET_EXTENT_FLAGS (RecordingFlags, Ad) == ExtentIsNextExtent) {\r
99c9b949
PA
1169 if (!DoFreeAed) {\r
1170 DoFreeAed = TRUE;\r
1171 } else {\r
1172 FreePool (Data);\r
1173 }\r
1174\r
1175 Status = GetAedAdsData (\r
1176 BlockIo,\r
1177 DiskIo,\r
1178 Volume,\r
1179 ParentIcb,\r
1180 RecordingFlags,\r
1181 Ad,\r
1182 &Data,\r
1183 &Length\r
1184 );\r
1185 if (EFI_ERROR (Status)) {\r
1186 goto Error_Get_Aed;\r
1187 }\r
3fa40d58 1188 ASSERT (Data != NULL);\r
99c9b949
PA
1189\r
1190 AdOffset = 0;\r
1191 continue;\r
1192 }\r
1193\r
1194 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
1195\r
6086569e
HW
1196 Status = GetAllocationDescriptorLsn (RecordingFlags,\r
1197 Volume,\r
1198 ParentIcb,\r
1199 Ad,\r
1200 &Lsn);\r
1201 if (EFI_ERROR (Status)) {\r
1202 goto Done;\r
1203 }\r
99c9b949
PA
1204\r
1205 switch (ReadFileInfo->Flags) {\r
880ec683 1206 case ReadFileGetFileSize:\r
99c9b949
PA
1207 ReadFileInfo->ReadLength += ExtentLength;\r
1208 break;\r
880ec683 1209 case ReadFileAllocateAndRead:\r
99c9b949
PA
1210 //\r
1211 // Increase FileData (if necessary) to read next extent.\r
1212 //\r
1213 Status = GrowUpBufferToNextAd (\r
1214 RecordingFlags,\r
1215 Ad,\r
1216 &ReadFileInfo->FileData,\r
1217 ReadFileInfo->ReadLength\r
1218 );\r
1219 if (EFI_ERROR (Status)) {\r
1220 goto Error_Alloc_Buffer_To_Next_Ad;\r
1221 }\r
1222\r
1223 //\r
1224 // Read extent's data into FileData.\r
1225 //\r
1226 Status = DiskIo->ReadDisk (\r
1227 DiskIo,\r
1228 BlockIo->Media->MediaId,\r
1229 MultU64x32 (Lsn, LogicalBlockSize),\r
1230 ExtentLength,\r
1231 (VOID *)((UINT8 *)ReadFileInfo->FileData +\r
1232 ReadFileInfo->ReadLength)\r
1233 );\r
1234 if (EFI_ERROR (Status)) {\r
1235 goto Error_Read_Disk_Blk;\r
1236 }\r
1237\r
1238 ReadFileInfo->ReadLength += ExtentLength;\r
1239 break;\r
880ec683 1240 case ReadFileSeekAndRead:\r
99c9b949
PA
1241 //\r
1242 // Seek file first before reading in its data.\r
1243 //\r
1244 if (FinishedSeeking) {\r
1245 Offset = 0;\r
1246 goto Skip_File_Seek;\r
1247 }\r
1248\r
1249 if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) {\r
1250 FilePosition += ExtentLength;\r
1251 goto Skip_Ad;\r
1252 }\r
1253\r
1254 if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) {\r
1255 Offset = ReadFileInfo->FilePosition - FilePosition;\r
99c9b949
PA
1256 } else {\r
1257 Offset = 0;\r
1258 }\r
1259\r
1260 //\r
1261 // Done with seeking file. Start reading its data.\r
1262 //\r
1263 FinishedSeeking = TRUE;\r
1264\r
1265 Skip_File_Seek:\r
1266 //\r
1267 // Make sure we don't read more data than really wanted.\r
1268 //\r
1269 if (ExtentLength - Offset > BytesLeft) {\r
1270 DataLength = BytesLeft;\r
1271 } else {\r
1272 DataLength = ExtentLength - Offset;\r
1273 }\r
1274\r
1275 //\r
1276 // Read extent's data into FileData.\r
1277 //\r
1278 Status = DiskIo->ReadDisk (\r
1279 DiskIo,\r
1280 BlockIo->Media->MediaId,\r
1281 Offset + MultU64x32 (Lsn, LogicalBlockSize),\r
0b4c8f00 1282 (UINTN) DataLength,\r
99c9b949
PA
1283 (VOID *)((UINT8 *)ReadFileInfo->FileData +\r
1284 DataOffset)\r
1285 );\r
1286 if (EFI_ERROR (Status)) {\r
1287 goto Error_Read_Disk_Blk;\r
1288 }\r
1289\r
1290 //\r
1291 // Update current file's position.\r
1292 //\r
1293 DataOffset += DataLength;\r
1294 ReadFileInfo->FilePosition += DataLength;\r
1295\r
1296 BytesLeft -= DataLength;\r
1297 if (BytesLeft == 0) {\r
1298 //\r
1299 // There is no more file data to read.\r
1300 //\r
1301 Status = EFI_SUCCESS;\r
1302 goto Done;\r
1303 }\r
1304\r
1305 break;\r
1306 }\r
1307\r
1308 Skip_Ad:\r
1309 //\r
1310 // Point to the next AD (extent).\r
1311 //\r
1312 AdOffset += AD_LENGTH (RecordingFlags);\r
1313 }\r
1314\r
1315 break;\r
880ec683 1316 case ExtendedAdsSequence:\r
99c9b949
PA
1317 // FIXME: Not supported. Got no volume with it, yet.\r
1318 ASSERT (FALSE);\r
1319 Status = EFI_UNSUPPORTED;\r
1320 break;\r
998aee89
LE
1321\r
1322 default:\r
1323 //\r
1324 // A flag value reserved by the ECMA-167 standard (3rd Edition - June\r
1325 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.\r
1326 //\r
1327 Status = EFI_UNSUPPORTED;\r
1328 break;\r
99c9b949
PA
1329 }\r
1330\r
1331Done:\r
1332 if (DoFreeAed) {\r
1333 FreePool (Data);\r
1334 }\r
1335\r
1336 return Status;\r
1337\r
1338Error_Read_Disk_Blk:\r
1339Error_Alloc_Buffer_To_Next_Ad:\r
880ec683 1340 if (ReadFileInfo->Flags != ReadFileSeekAndRead) {\r
99c9b949
PA
1341 FreePool (ReadFileInfo->FileData);\r
1342 }\r
1343\r
1344 if (DoFreeAed) {\r
1345 FreePool (Data);\r
1346 }\r
1347\r
1348Error_Get_Aed:\r
1349 return Status;\r
1350}\r
1351\r
077f8c43
HW
1352/**\r
1353 Find a file by its filename from a given Parent file.\r
1354\r
1355 @param[in] BlockIo BlockIo interface.\r
1356 @param[in] DiskIo DiskIo interface.\r
1357 @param[in] Volume Volume information pointer.\r
1358 @param[in] FileName File name string.\r
1359 @param[in] Parent Parent directory file.\r
1360 @param[in] Icb Long Allocation Descriptor pointer.\r
1361 @param[out] File Found file.\r
1362\r
1363 @retval EFI_SUCCESS The file was found.\r
1364 @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.\r
1365 @retval EFI_NOT_FOUND The file was not found.\r
1366\r
1367**/\r
99c9b949
PA
1368EFI_STATUS\r
1369InternalFindFile (\r
1370 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1371 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1372 IN UDF_VOLUME_INFO *Volume,\r
1373 IN CHAR16 *FileName,\r
1374 IN UDF_FILE_INFO *Parent,\r
1375 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,\r
1376 OUT UDF_FILE_INFO *File\r
1377 )\r
1378{\r
1379 EFI_STATUS Status;\r
1380 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;\r
1381 UDF_READ_DIRECTORY_INFO ReadDirInfo;\r
1382 BOOLEAN Found;\r
1383 CHAR16 FoundFileName[UDF_FILENAME_LENGTH];\r
1384 VOID *CompareFileEntry;\r
1385\r
3fa40d58
HW
1386 //\r
1387 // Check if both Parent->FileIdentifierDesc and Icb are NULL.\r
1388 //\r
1389 if ((Parent->FileIdentifierDesc == NULL) && (Icb == NULL)) {\r
1390 return EFI_INVALID_PARAMETER;\r
1391 }\r
1392\r
99c9b949
PA
1393 //\r
1394 // Check if parent file is really directory.\r
1395 //\r
baaa3cee 1396 if (FE_ICB_FILE_TYPE (Parent->FileEntry) != UdfFileEntryDirectory) {\r
99c9b949
PA
1397 return EFI_NOT_FOUND;\r
1398 }\r
1399\r
1400 //\r
1401 // If FileName is current file or working directory, just duplicate Parent's\r
1402 // FE/EFE and FID descriptors.\r
1403 //\r
1404 if (StrCmp (FileName, L".") == 0) {\r
3fa40d58
HW
1405 if (Parent->FileIdentifierDesc == NULL) {\r
1406 return EFI_INVALID_PARAMETER;\r
1407 }\r
1408\r
99c9b949 1409 DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);\r
ebb12f51
HW
1410 if (File->FileEntry == NULL) {\r
1411 return EFI_OUT_OF_RESOURCES;\r
1412 }\r
1413\r
99c9b949 1414 DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);\r
ebb12f51
HW
1415 if (File->FileIdentifierDesc == NULL) {\r
1416 FreePool (File->FileEntry);\r
1417 return EFI_OUT_OF_RESOURCES;\r
1418 }\r
99c9b949
PA
1419\r
1420 return EFI_SUCCESS;\r
1421 }\r
1422\r
1423 //\r
1424 // Start directory listing.\r
1425 //\r
1426 ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));\r
1427 Found = FALSE;\r
1428\r
1429 for (;;) {\r
1430 Status = ReadDirectoryEntry (\r
1431 BlockIo,\r
1432 DiskIo,\r
1433 Volume,\r
12b83f56 1434 (Parent->FileIdentifierDesc != NULL) ?\r
99c9b949
PA
1435 &Parent->FileIdentifierDesc->Icb :\r
1436 Icb,\r
1437 Parent->FileEntry,\r
1438 &ReadDirInfo,\r
1439 &FileIdentifierDesc\r
1440 );\r
1441 if (EFI_ERROR (Status)) {\r
1442 if (Status == EFI_DEVICE_ERROR) {\r
1443 Status = EFI_NOT_FOUND;\r
1444 }\r
1445\r
1446 break;\r
1447 }\r
5fb22f59
HW
1448 //\r
1449 // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is\r
1450 // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code\r
1451 // reaches here, 'FileIdentifierDesc' must be not NULL.\r
1452 //\r
1453 // The ASSERT here is for addressing a false positive NULL pointer\r
1454 // dereference issue raised from static analysis.\r
1455 //\r
1456 ASSERT (FileIdentifierDesc != NULL);\r
99c9b949 1457\r
baaa3cee 1458 if (FileIdentifierDesc->FileCharacteristics & PARENT_FILE) {\r
99c9b949
PA
1459 //\r
1460 // This FID contains the location (FE/EFE) of the parent directory of this\r
1461 // directory (Parent), and if FileName is either ".." or "\\", then it's\r
1462 // the expected FID.\r
1463 //\r
1464 if (StrCmp (FileName, L"..") == 0 || StrCmp (FileName, L"\\") == 0) {\r
1465 Found = TRUE;\r
1466 break;\r
1467 }\r
1468 } else {\r
1469 Status = GetFileNameFromFid (FileIdentifierDesc, FoundFileName);\r
1470 if (EFI_ERROR (Status)) {\r
1471 break;\r
1472 }\r
1473\r
1474 if (StrCmp (FileName, FoundFileName) == 0) {\r
1475 //\r
1476 // FID has been found. Prepare to find its respective FE/EFE.\r
1477 //\r
1478 Found = TRUE;\r
1479 break;\r
1480 }\r
1481 }\r
1482\r
1483 FreePool ((VOID *)FileIdentifierDesc);\r
1484 }\r
1485\r
1486 if (ReadDirInfo.DirectoryData != NULL) {\r
1487 //\r
1488 // Free all allocated resources for the directory listing.\r
1489 //\r
1490 FreePool (ReadDirInfo.DirectoryData);\r
1491 }\r
1492\r
1493 if (Found) {\r
1494 Status = EFI_SUCCESS;\r
1495\r
1496 File->FileIdentifierDesc = FileIdentifierDesc;\r
1497\r
1498 //\r
1499 // If the requested file is root directory, then the FE/EFE was already\r
1500 // retrieved in UdfOpenVolume() function, thus no need to find it again.\r
1501 //\r
1502 // Otherwise, find FE/EFE from the respective FID.\r
1503 //\r
1504 if (StrCmp (FileName, L"\\") != 0) {\r
1505 Status = FindFileEntry (\r
1506 BlockIo,\r
1507 DiskIo,\r
1508 Volume,\r
1509 &FileIdentifierDesc->Icb,\r
1510 &CompareFileEntry\r
1511 );\r
1512 if (EFI_ERROR (Status)) {\r
1513 goto Error_Find_Fe;\r
1514 }\r
1515\r
1516 //\r
1517 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.\r
1518 //\r
1519 if (CompareMem ((VOID *)Parent->FileEntry, (VOID *)CompareFileEntry,\r
1520 Volume->FileEntrySize) != 0) {\r
1521 File->FileEntry = CompareFileEntry;\r
1522 } else {\r
1523 FreePool ((VOID *)FileIdentifierDesc);\r
1524 FreePool ((VOID *)CompareFileEntry);\r
1525 Status = EFI_NOT_FOUND;\r
1526 }\r
1527 }\r
1528 }\r
1529\r
1530 return Status;\r
1531\r
1532Error_Find_Fe:\r
1533 FreePool ((VOID *)FileIdentifierDesc);\r
1534\r
1535 return Status;\r
1536}\r
1537\r
1538/**\r
1539 Read volume information on a medium which contains a valid UDF file system.\r
1540\r
1541 @param[in] BlockIo BlockIo interface.\r
1542 @param[in] DiskIo DiskIo interface.\r
1543 @param[out] Volume UDF volume information structure.\r
1544\r
1545 @retval EFI_SUCCESS Volume information read.\r
1546 @retval EFI_NO_MEDIA The device has no media.\r
1547 @retval EFI_DEVICE_ERROR The device reported an error.\r
1548 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1549 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.\r
1550\r
1551**/\r
1552EFI_STATUS\r
1553ReadUdfVolumeInformation (\r
1554 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1555 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1556 OUT UDF_VOLUME_INFO *Volume\r
1557 )\r
1558{\r
1559 EFI_STATUS Status;\r
1560\r
baaa3cee
PA
1561 //\r
1562 // Read all necessary UDF volume information and keep it private to the driver\r
1563 //\r
99c9b949
PA
1564 Status = ReadVolumeFileStructure (\r
1565 BlockIo,\r
1566 DiskIo,\r
1567 Volume\r
1568 );\r
1569 if (EFI_ERROR (Status)) {\r
1570 return Status;\r
1571 }\r
1572\r
baaa3cee
PA
1573 //\r
1574 // Find File Set Descriptor\r
1575 //\r
1576 Status = FindFileSetDescriptor (BlockIo, DiskIo, Volume);\r
99c9b949 1577 if (EFI_ERROR (Status)) {\r
baaa3cee 1578 return Status;\r
99c9b949
PA
1579 }\r
1580\r
1581 return Status;\r
1582}\r
1583\r
1584/**\r
1585 Find the root directory on an UDF volume.\r
1586\r
1587 @param[in] BlockIo BlockIo interface.\r
1588 @param[in] DiskIo DiskIo interface.\r
1589 @param[in] Volume UDF volume information structure.\r
1590 @param[out] File Root directory file.\r
1591\r
1592 @retval EFI_SUCCESS Root directory found.\r
1593 @retval EFI_NO_MEDIA The device has no media.\r
1594 @retval EFI_DEVICE_ERROR The device reported an error.\r
1595 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1596 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of\r
1597 resources.\r
1598\r
1599**/\r
1600EFI_STATUS\r
1601FindRootDirectory (\r
1602 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1603 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1604 IN UDF_VOLUME_INFO *Volume,\r
1605 OUT UDF_FILE_INFO *File\r
1606 )\r
1607{\r
1608 EFI_STATUS Status;\r
1609 UDF_FILE_INFO Parent;\r
1610\r
1611 Status = FindFileEntry (\r
1612 BlockIo,\r
1613 DiskIo,\r
1614 Volume,\r
baaa3cee 1615 &Volume->FileSetDesc.RootDirectoryIcb,\r
99c9b949
PA
1616 &File->FileEntry\r
1617 );\r
1618 if (EFI_ERROR (Status)) {\r
1619 return Status;\r
1620 }\r
1621\r
1622 Parent.FileEntry = File->FileEntry;\r
1623 Parent.FileIdentifierDesc = NULL;\r
1624\r
1625 Status = FindFile (\r
1626 BlockIo,\r
1627 DiskIo,\r
1628 Volume,\r
1629 L"\\",\r
1630 NULL,\r
1631 &Parent,\r
baaa3cee 1632 &Volume->FileSetDesc.RootDirectoryIcb,\r
99c9b949
PA
1633 File\r
1634 );\r
1635 if (EFI_ERROR (Status)) {\r
1636 FreePool (File->FileEntry);\r
1637 }\r
1638\r
1639 return Status;\r
1640}\r
1641\r
1642/**\r
1643 Find either a File Entry or a Extended File Entry from a given ICB.\r
1644\r
1645 @param[in] BlockIo BlockIo interface.\r
1646 @param[in] DiskIo DiskIo interface.\r
1647 @param[in] Volume UDF volume information structure.\r
1648 @param[in] Icb ICB of the FID.\r
1649 @param[out] FileEntry File Entry or Extended File Entry.\r
1650\r
1651 @retval EFI_SUCCESS File Entry or Extended File Entry found.\r
1652 @retval EFI_NO_MEDIA The device has no media.\r
1653 @retval EFI_DEVICE_ERROR The device reported an error.\r
1654 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1655 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of\r
1656 resources.\r
1657\r
1658**/\r
1659EFI_STATUS\r
1660FindFileEntry (\r
1661 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1662 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1663 IN UDF_VOLUME_INFO *Volume,\r
1664 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,\r
1665 OUT VOID **FileEntry\r
1666 )\r
1667{\r
baaa3cee
PA
1668 EFI_STATUS Status;\r
1669 UINT64 Lsn;\r
1670 UINT32 LogicalBlockSize;\r
1671 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
7a966348 1672 VOID *ReadBuffer;\r
99c9b949 1673\r
6086569e
HW
1674 Status = GetLongAdLsn (Volume, Icb, &Lsn);\r
1675 if (EFI_ERROR (Status)) {\r
1676 return Status;\r
1677 }\r
1678\r
baaa3cee 1679 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;\r
99c9b949 1680\r
7a966348
HW
1681 ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);\r
1682 if (ReadBuffer == NULL) {\r
99c9b949
PA
1683 return EFI_OUT_OF_RESOURCES;\r
1684 }\r
1685\r
1686 //\r
1687 // Read extent.\r
1688 //\r
1689 Status = DiskIo->ReadDisk (\r
1690 DiskIo,\r
1691 BlockIo->Media->MediaId,\r
1692 MultU64x32 (Lsn, LogicalBlockSize),\r
1693 Volume->FileEntrySize,\r
7a966348 1694 ReadBuffer\r
99c9b949
PA
1695 );\r
1696 if (EFI_ERROR (Status)) {\r
1697 goto Error_Read_Disk_Blk;\r
1698 }\r
1699\r
7a966348 1700 DescriptorTag = ReadBuffer;\r
baaa3cee 1701\r
99c9b949
PA
1702 //\r
1703 // Check if the read extent contains a valid Tag Identifier for the expected\r
1704 // FE/EFE.\r
1705 //\r
baaa3cee
PA
1706 if (DescriptorTag->TagIdentifier != UdfFileEntry &&\r
1707 DescriptorTag->TagIdentifier != UdfExtendedFileEntry) {\r
99c9b949
PA
1708 Status = EFI_VOLUME_CORRUPTED;\r
1709 goto Error_Invalid_Fe;\r
1710 }\r
1711\r
7a966348 1712 *FileEntry = ReadBuffer;\r
99c9b949
PA
1713 return EFI_SUCCESS;\r
1714\r
1715Error_Invalid_Fe:\r
1716Error_Read_Disk_Blk:\r
7a966348 1717 FreePool (ReadBuffer);\r
99c9b949
PA
1718\r
1719 return Status;\r
1720}\r
1721\r
1722/**\r
1723 Find a file given its absolute path on an UDF volume.\r
1724\r
1725 @param[in] BlockIo BlockIo interface.\r
1726 @param[in] DiskIo DiskIo interface.\r
1727 @param[in] Volume UDF volume information structure.\r
1728 @param[in] FilePath File's absolute path.\r
1729 @param[in] Root Root directory file.\r
1730 @param[in] Parent Parent directory file.\r
077f8c43 1731 @param[in] Icb ICB of Parent.\r
99c9b949
PA
1732 @param[out] File Found file.\r
1733\r
077f8c43 1734 @retval EFI_SUCCESS FilePath was found.\r
99c9b949
PA
1735 @retval EFI_NO_MEDIA The device has no media.\r
1736 @retval EFI_DEVICE_ERROR The device reported an error.\r
1737 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
077f8c43 1738 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of\r
99c9b949
PA
1739 resources.\r
1740\r
1741**/\r
1742EFI_STATUS\r
1743FindFile (\r
1744 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1745 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1746 IN UDF_VOLUME_INFO *Volume,\r
1747 IN CHAR16 *FilePath,\r
1748 IN UDF_FILE_INFO *Root,\r
1749 IN UDF_FILE_INFO *Parent,\r
1750 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,\r
1751 OUT UDF_FILE_INFO *File\r
1752 )\r
1753{\r
1754 EFI_STATUS Status;\r
1755 CHAR16 FileName[UDF_FILENAME_LENGTH];\r
1756 CHAR16 *FileNamePointer;\r
1757 UDF_FILE_INFO PreviousFile;\r
1758 VOID *FileEntry;\r
1759\r
1760 Status = EFI_NOT_FOUND;\r
1761\r
1762 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));\r
1763 while (*FilePath != L'\0') {\r
1764 FileNamePointer = FileName;\r
1765 while (*FilePath != L'\0' && *FilePath != L'\\') {\r
1766 *FileNamePointer++ = *FilePath++;\r
1767 }\r
1768\r
1769 *FileNamePointer = L'\0';\r
1770 if (FileName[0] == L'\0') {\r
1771 //\r
1772 // Open root directory.\r
1773 //\r
1774 if (Root == NULL) {\r
1775 //\r
1776 // There is no file found for the root directory yet. So, find only its\r
1777 // FID by now.\r
1778 //\r
1779 // See UdfOpenVolume() function.\r
1780 //\r
1781 Status = InternalFindFile (BlockIo,\r
1782 DiskIo,\r
1783 Volume,\r
1784 L"\\",\r
1785 &PreviousFile,\r
1786 Icb,\r
1787 File);\r
1788 } else {\r
1789 //\r
1790 // We've already a file pointer (Root) for the root directory. Duplicate\r
1791 // its FE/EFE and FID descriptors.\r
1792 //\r
99c9b949 1793 Status = EFI_SUCCESS;\r
ebb12f51
HW
1794 DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);\r
1795 if (File->FileEntry == NULL) {\r
1796 Status = EFI_OUT_OF_RESOURCES;\r
1797 } else {\r
1798 //\r
1799 // File->FileEntry is not NULL.\r
1800 //\r
1801 DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);\r
1802 if (File->FileIdentifierDesc == NULL) {\r
1803 FreePool (File->FileEntry);\r
1804 Status = EFI_OUT_OF_RESOURCES;\r
1805 }\r
1806 }\r
99c9b949
PA
1807 }\r
1808 } else {\r
1809 //\r
1810 // No root directory. Find filename from the current directory.\r
1811 //\r
1812 Status = InternalFindFile (BlockIo,\r
1813 DiskIo,\r
1814 Volume,\r
1815 FileName,\r
1816 &PreviousFile,\r
1817 Icb,\r
1818 File);\r
1819 }\r
1820\r
1821 if (EFI_ERROR (Status)) {\r
1822 return Status;\r
1823 }\r
1824\r
1825 //\r
1826 // If the found file is a symlink, then find its respective FE/EFE and\r
1827 // FID descriptors.\r
1828 //\r
baaa3cee 1829 if (FE_ICB_FILE_TYPE (File->FileEntry) == UdfFileEntrySymlink) {\r
99c9b949
PA
1830 FreePool ((VOID *)File->FileIdentifierDesc);\r
1831\r
1832 FileEntry = File->FileEntry;\r
1833\r
1834 Status = ResolveSymlink (BlockIo,\r
1835 DiskIo,\r
1836 Volume,\r
1837 &PreviousFile,\r
1838 FileEntry,\r
1839 File);\r
1840\r
1841 FreePool (FileEntry);\r
1842\r
1843 if (EFI_ERROR (Status)) {\r
1844 return Status;\r
1845 }\r
1846 }\r
1847\r
1848 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
1849 sizeof (UDF_FILE_INFO)) != 0) {\r
1850 CleanupFileInformation (&PreviousFile);\r
1851 }\r
1852\r
1853 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));\r
1854 if (*FilePath != L'\0' && *FilePath == L'\\') {\r
1855 FilePath++;\r
1856 }\r
1857 }\r
1858\r
1859 return Status;\r
1860}\r
1861\r
1862/**\r
1863 Read a directory entry at a time on an UDF volume.\r
1864\r
1865 @param[in] BlockIo BlockIo interface.\r
1866 @param[in] DiskIo DiskIo interface.\r
1867 @param[in] Volume UDF volume information structure.\r
1868 @param[in] ParentIcb ICB of the parent file.\r
1869 @param[in] FileEntryData FE/EFE of the parent file.\r
077f8c43 1870 @param[in, out] ReadDirInfo Next read directory listing structure\r
99c9b949
PA
1871 information.\r
1872 @param[out] FoundFid File Identifier Descriptor pointer.\r
1873\r
1874 @retval EFI_SUCCESS Directory entry read.\r
1875 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
1876 @retval EFI_NO_MEDIA The device has no media.\r
1877 @retval EFI_DEVICE_ERROR The device reported an error.\r
1878 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1879 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of\r
1880 resources.\r
1881\r
1882**/\r
1883EFI_STATUS\r
1884ReadDirectoryEntry (\r
1885 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1886 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1887 IN UDF_VOLUME_INFO *Volume,\r
1888 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
1889 IN VOID *FileEntryData,\r
1890 IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,\r
1891 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid\r
1892 )\r
1893{\r
1894 EFI_STATUS Status;\r
1895 UDF_READ_FILE_INFO ReadFileInfo;\r
1896 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;\r
1897\r
1898 if (ReadDirInfo->DirectoryData == NULL) {\r
1899 //\r
1900 // The directory's recorded data has not been read yet. So let's cache it\r
1901 // into memory and the next calls won't need to read it again.\r
1902 //\r
880ec683 1903 ReadFileInfo.Flags = ReadFileAllocateAndRead;\r
99c9b949
PA
1904\r
1905 Status = ReadFile (\r
1906 BlockIo,\r
1907 DiskIo,\r
1908 Volume,\r
1909 ParentIcb,\r
1910 FileEntryData,\r
1911 &ReadFileInfo\r
1912 );\r
1913 if (EFI_ERROR (Status)) {\r
1914 return Status;\r
1915 }\r
1916\r
1917 //\r
1918 // Fill in ReadDirInfo structure with the read directory's data information.\r
1919 //\r
1920 ReadDirInfo->DirectoryData = ReadFileInfo.FileData;\r
1921 ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;\r
1922 }\r
1923\r
1924 do {\r
1925 if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {\r
1926 //\r
1927 // There are no longer FIDs for this directory. By returning\r
1928 // EFI_DEVICE_ERROR to the callee will indicate end of directory\r
1929 // listening.\r
1930 //\r
1931 return EFI_DEVICE_ERROR;\r
1932 }\r
1933\r
1934 //\r
1935 // Get FID for this entry.\r
1936 //\r
1937 FileIdentifierDesc = GET_FID_FROM_ADS (ReadDirInfo->DirectoryData,\r
1938 ReadDirInfo->FidOffset);\r
1939 //\r
1940 // Update FidOffset to point to next FID.\r
1941 //\r
1942 ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);\r
baaa3cee 1943 } while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);\r
99c9b949
PA
1944\r
1945 DuplicateFid (FileIdentifierDesc, FoundFid);\r
ebb12f51
HW
1946 if (*FoundFid == NULL) {\r
1947 return EFI_OUT_OF_RESOURCES;\r
1948 }\r
99c9b949
PA
1949\r
1950 return EFI_SUCCESS;\r
1951}\r
1952\r
1953/**\r
1954 Get a filename (encoded in OSTA-compressed format) from a File Identifier\r
1955 Descriptor on an UDF volume.\r
1956\r
1957 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.\r
1958 @param[out] FileName Decoded filename.\r
1959\r
1960 @retval EFI_SUCCESS Filename decoded and read.\r
1961 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1962**/\r
1963EFI_STATUS\r
1964GetFileNameFromFid (\r
1965 IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,\r
1966 OUT CHAR16 *FileName\r
1967 )\r
1968{\r
1969 UINT8 *OstaCompressed;\r
1970 UINT8 CompressionId;\r
1971 UINT8 Length;\r
1972 UINTN Index;\r
1973\r
1974 OstaCompressed =\r
1975 (UINT8 *)(\r
1976 (UINT8 *)FileIdentifierDesc->Data +\r
1977 FileIdentifierDesc->LengthOfImplementationUse\r
1978 );\r
1979\r
1980 CompressionId = OstaCompressed[0];\r
1981 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
1982 return EFI_VOLUME_CORRUPTED;\r
1983 }\r
1984\r
1985 //\r
1986 // Decode filename.\r
1987 //\r
1988 Length = FileIdentifierDesc->LengthOfFileIdentifier;\r
1989 for (Index = 1; Index < Length; Index++) {\r
1990 if (CompressionId == 16) {\r
1991 *FileName = OstaCompressed[Index++] << 8;\r
1992 } else {\r
1993 *FileName = 0;\r
1994 }\r
1995\r
1996 if (Index < Length) {\r
fedec0a3 1997 *FileName |= (CHAR16)(OstaCompressed[Index]);\r
99c9b949
PA
1998 }\r
1999\r
2000 FileName++;\r
2001 }\r
2002\r
2003 *FileName = L'\0';\r
2004\r
2005 return EFI_SUCCESS;\r
2006}\r
2007\r
2008/**\r
2009 Resolve a symlink file on an UDF volume.\r
2010\r
2011 @param[in] BlockIo BlockIo interface.\r
2012 @param[in] DiskIo DiskIo interface.\r
2013 @param[in] Volume UDF volume information structure.\r
2014 @param[in] Parent Parent file.\r
2015 @param[in] FileEntryData FE/EFE structure pointer.\r
2016 @param[out] File Resolved file.\r
2017\r
2018 @retval EFI_SUCCESS Symlink file resolved.\r
2019 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
2020 @retval EFI_NO_MEDIA The device has no media.\r
2021 @retval EFI_DEVICE_ERROR The device reported an error.\r
2022 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2023 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of\r
2024 resources.\r
2025\r
2026**/\r
2027EFI_STATUS\r
2028ResolveSymlink (\r
2029 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2030 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2031 IN UDF_VOLUME_INFO *Volume,\r
2032 IN UDF_FILE_INFO *Parent,\r
2033 IN VOID *FileEntryData,\r
2034 OUT UDF_FILE_INFO *File\r
2035 )\r
2036{\r
2037 EFI_STATUS Status;\r
2038 UDF_READ_FILE_INFO ReadFileInfo;\r
2039 UINT8 *Data;\r
2040 UINT64 Length;\r
2041 UINT8 *EndData;\r
2042 UDF_PATH_COMPONENT *PathComp;\r
2043 UINT8 PathCompLength;\r
2044 CHAR16 FileName[UDF_FILENAME_LENGTH];\r
32492fee 2045 CHAR16 *Char;\r
99c9b949
PA
2046 UINTN Index;\r
2047 UINT8 CompressionId;\r
2048 UDF_FILE_INFO PreviousFile;\r
2049\r
2050 //\r
2051 // Symlink files on UDF volumes do not contain so much data other than\r
2052 // Path Components which resolves to real filenames, so it's OK to read in\r
2053 // all its data here -- usually the data will be inline with the FE/EFE for\r
2054 // lower filenames.\r
2055 //\r
880ec683 2056 ReadFileInfo.Flags = ReadFileAllocateAndRead;\r
99c9b949
PA
2057\r
2058 Status = ReadFile (\r
2059 BlockIo,\r
2060 DiskIo,\r
2061 Volume,\r
2062 &Parent->FileIdentifierDesc->Icb,\r
2063 FileEntryData,\r
2064 &ReadFileInfo\r
2065 );\r
2066 if (EFI_ERROR (Status)) {\r
2067 return Status;\r
2068 }\r
2069\r
2070 Length = ReadFileInfo.ReadLength;\r
2071\r
2072 Data = (UINT8 *)ReadFileInfo.FileData;\r
2073 EndData = Data + Length;\r
2074\r
2075 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));\r
2076\r
2077 for (;;) {\r
2078 PathComp = (UDF_PATH_COMPONENT *)Data;\r
2079\r
2080 PathCompLength = PathComp->LengthOfComponentIdentifier;\r
2081\r
2082 switch (PathComp->ComponentType) {\r
2083 case 1:\r
2084 //\r
2085 // This Path Component specifies the root directory hierarchy subject to\r
2086 // agreement between the originator and recipient of the medium. Skip it.\r
2087 //\r
2088 // Fall through.\r
2089 //\r
2090 case 2:\r
2091 //\r
2092 // "\\." of the current directory. Read next Path Component.\r
2093 //\r
2094 goto Next_Path_Component;\r
2095 case 3:\r
2096 //\r
2097 // ".." (parent directory). Go to it.\r
2098 //\r
2099 CopyMem ((VOID *)FileName, L"..", 6);\r
2100 break;\r
2101 case 4:\r
2102 //\r
2103 // "." (current file). Duplicate both FE/EFE and FID of this file.\r
2104 //\r
2105 DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);\r
ebb12f51
HW
2106 if (File->FileEntry == NULL) {\r
2107 Status = EFI_OUT_OF_RESOURCES;\r
2108 goto Error_Find_File;\r
2109 }\r
2110\r
99c9b949
PA
2111 DuplicateFid (PreviousFile.FileIdentifierDesc,\r
2112 &File->FileIdentifierDesc);\r
ebb12f51
HW
2113 if (File->FileIdentifierDesc == NULL) {\r
2114 FreePool (File->FileEntry);\r
2115 Status = EFI_OUT_OF_RESOURCES;\r
2116 goto Error_Find_File;\r
2117 }\r
99c9b949
PA
2118 goto Next_Path_Component;\r
2119 case 5:\r
2120 //\r
2121 // This Path Component identifies an object, either a file or a\r
2122 // directory or an alias.\r
2123 //\r
2124 // Decode it from the compressed data in ComponentIdentifier and find\r
2125 // respective path.\r
2126 //\r
2127 CompressionId = PathComp->ComponentIdentifier[0];\r
2128 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
2129 return EFI_VOLUME_CORRUPTED;\r
2130 }\r
2131\r
32492fee 2132 Char = FileName;\r
99c9b949
PA
2133 for (Index = 1; Index < PathCompLength; Index++) {\r
2134 if (CompressionId == 16) {\r
32492fee 2135 *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +\r
99c9b949
PA
2136 Index) << 8;\r
2137 Index++;\r
2138 } else {\r
32492fee 2139 *Char = 0;\r
99c9b949
PA
2140 }\r
2141\r
2142 if (Index < Length) {\r
32492fee 2143 *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));\r
99c9b949
PA
2144 }\r
2145\r
32492fee 2146 Char++;\r
99c9b949
PA
2147 }\r
2148\r
32492fee 2149 *Char = L'\0';\r
99c9b949
PA
2150 break;\r
2151 }\r
2152\r
2153 //\r
2154 // Find file from the read filename in symlink's file data.\r
2155 //\r
2156 Status = InternalFindFile (\r
2157 BlockIo,\r
2158 DiskIo,\r
2159 Volume,\r
2160 FileName,\r
2161 &PreviousFile,\r
2162 NULL,\r
2163 File\r
2164 );\r
2165 if (EFI_ERROR (Status)) {\r
2166 goto Error_Find_File;\r
2167 }\r
2168\r
2169 Next_Path_Component:\r
2170 Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;\r
2171 if (Data >= EndData) {\r
2172 break;\r
2173 }\r
2174\r
2175 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
2176 sizeof (UDF_FILE_INFO)) != 0) {\r
2177 CleanupFileInformation (&PreviousFile);\r
2178 }\r
2179\r
2180 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));\r
2181 }\r
2182\r
2183 //\r
2184 // Unmap the symlink file.\r
2185 //\r
2186 FreePool (ReadFileInfo.FileData);\r
2187\r
2188 return EFI_SUCCESS;\r
2189\r
2190Error_Find_File:\r
2191 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
2192 sizeof (UDF_FILE_INFO)) != 0) {\r
2193 CleanupFileInformation (&PreviousFile);\r
2194 }\r
2195\r
2196 FreePool (ReadFileInfo.FileData);\r
2197\r
2198 return Status;\r
2199}\r
2200\r
99c9b949
PA
2201/**\r
2202 Clean up in-memory UDF file information.\r
2203\r
2204 @param[in] File File information pointer.\r
2205\r
2206**/\r
2207VOID\r
2208CleanupFileInformation (\r
2209 IN UDF_FILE_INFO *File\r
2210 )\r
2211{\r
2212 if (File->FileEntry != NULL) {\r
2213 FreePool (File->FileEntry);\r
2214 }\r
2215 if (File->FileIdentifierDesc != NULL) {\r
2216 FreePool ((VOID *)File->FileIdentifierDesc);\r
2217 }\r
2218\r
2219 ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));\r
2220}\r
2221\r
2222/**\r
2223 Find a file from its absolute path on an UDF volume.\r
2224\r
2225 @param[in] BlockIo BlockIo interface.\r
2226 @param[in] DiskIo DiskIo interface.\r
2227 @param[in] Volume UDF volume information structure.\r
2228 @param[in] File File information structure.\r
2229 @param[out] Size Size of the file.\r
2230\r
077f8c43 2231 @retval EFI_SUCCESS File size calculated and set in Size.\r
99c9b949
PA
2232 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
2233 @retval EFI_NO_MEDIA The device has no media.\r
2234 @retval EFI_DEVICE_ERROR The device reported an error.\r
2235 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2236 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of\r
2237 resources.\r
2238\r
2239**/\r
2240EFI_STATUS\r
2241GetFileSize (\r
2242 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2243 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2244 IN UDF_VOLUME_INFO *Volume,\r
2245 IN UDF_FILE_INFO *File,\r
2246 OUT UINT64 *Size\r
2247 )\r
2248{\r
2249 EFI_STATUS Status;\r
2250 UDF_READ_FILE_INFO ReadFileInfo;\r
2251\r
880ec683 2252 ReadFileInfo.Flags = ReadFileGetFileSize;\r
99c9b949
PA
2253\r
2254 Status = ReadFile (\r
2255 BlockIo,\r
2256 DiskIo,\r
2257 Volume,\r
2258 &File->FileIdentifierDesc->Icb,\r
2259 File->FileEntry,\r
2260 &ReadFileInfo\r
2261 );\r
2262 if (EFI_ERROR (Status)) {\r
2263 return Status;\r
2264 }\r
2265\r
2266 *Size = ReadFileInfo.ReadLength;\r
2267\r
2268 return EFI_SUCCESS;\r
2269}\r
2270\r
2271/**\r
2272 Set information about a file on an UDF volume.\r
2273\r
2274 @param[in] File File pointer.\r
2275 @param[in] FileSize Size of the file.\r
2276 @param[in] FileName Filename of the file.\r
077f8c43 2277 @param[in, out] BufferSize Size of the returned file infomation.\r
99c9b949
PA
2278 @param[out] Buffer Data of the returned file information.\r
2279\r
2280 @retval EFI_SUCCESS File information set.\r
2281 @retval EFI_NO_MEDIA The device has no media.\r
2282 @retval EFI_DEVICE_ERROR The device reported an error.\r
2283 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2284 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of\r
2285 resources.\r
2286\r
2287**/\r
2288EFI_STATUS\r
2289SetFileInfo (\r
2290 IN UDF_FILE_INFO *File,\r
2291 IN UINT64 FileSize,\r
2292 IN CHAR16 *FileName,\r
2293 IN OUT UINTN *BufferSize,\r
2294 OUT VOID *Buffer\r
2295 )\r
2296{\r
2297 UINTN FileInfoLength;\r
2298 EFI_FILE_INFO *FileInfo;\r
2299 UDF_FILE_ENTRY *FileEntry;\r
2300 UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;\r
baaa3cee 2301 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
99c9b949
PA
2302\r
2303 //\r
2304 // Calculate the needed size for the EFI_FILE_INFO structure.\r
2305 //\r
12b83f56 2306 FileInfoLength = sizeof (EFI_FILE_INFO) + ((FileName != NULL) ?\r
99c9b949
PA
2307 StrSize (FileName) :\r
2308 sizeof (CHAR16));\r
2309 if (*BufferSize < FileInfoLength) {\r
2310 //\r
2311 // The given Buffer has no size enough for EFI_FILE_INFO structure.\r
2312 //\r
2313 *BufferSize = FileInfoLength;\r
2314 return EFI_BUFFER_TOO_SMALL;\r
2315 }\r
2316\r
2317 //\r
2318 // Buffer now contains room enough to store EFI_FILE_INFO structure.\r
2319 // Now, fill it in with all necessary information about the file.\r
2320 //\r
2321 FileInfo = (EFI_FILE_INFO *)Buffer;\r
2322 FileInfo->Size = FileInfoLength;\r
2323 FileInfo->Attribute &= ~EFI_FILE_VALID_ATTR;\r
2324 FileInfo->Attribute |= EFI_FILE_READ_ONLY;\r
2325\r
2326 if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {\r
2327 FileInfo->Attribute |= EFI_FILE_DIRECTORY;\r
2328 } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {\r
2329 FileInfo->Attribute |= EFI_FILE_ARCHIVE;\r
2330 }\r
2331\r
2332 if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {\r
2333 FileInfo->Attribute |= EFI_FILE_HIDDEN;\r
2334 }\r
2335\r
baaa3cee
PA
2336 DescriptorTag = File->FileEntry;\r
2337\r
2338 if (DescriptorTag->TagIdentifier == UdfFileEntry) {\r
99c9b949
PA
2339 FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;\r
2340\r
2341 //\r
2342 // Check if FE has the system attribute set.\r
2343 //\r
2344 if (FileEntry->IcbTag.Flags & (1 << 10)) {\r
2345 FileInfo->Attribute |= EFI_FILE_SYSTEM;\r
2346 }\r
2347\r
2348 FileInfo->FileSize = FileSize;\r
2349 FileInfo->PhysicalSize = FileSize;\r
2350\r
2351 FileInfo->CreateTime.Year = FileEntry->AccessTime.Year;\r
2352 FileInfo->CreateTime.Month = FileEntry->AccessTime.Month;\r
2353 FileInfo->CreateTime.Day = FileEntry->AccessTime.Day;\r
2354 FileInfo->CreateTime.Hour = FileEntry->AccessTime.Hour;\r
2355 FileInfo->CreateTime.Minute = FileEntry->AccessTime.Second;\r
2356 FileInfo->CreateTime.Second = FileEntry->AccessTime.Second;\r
2357 FileInfo->CreateTime.Nanosecond =\r
2358 FileEntry->AccessTime.HundredsOfMicroseconds;\r
2359\r
2360 FileInfo->LastAccessTime.Year =\r
2361 FileEntry->AccessTime.Year;\r
2362 FileInfo->LastAccessTime.Month =\r
2363 FileEntry->AccessTime.Month;\r
2364 FileInfo->LastAccessTime.Day =\r
2365 FileEntry->AccessTime.Day;\r
2366 FileInfo->LastAccessTime.Hour =\r
2367 FileEntry->AccessTime.Hour;\r
2368 FileInfo->LastAccessTime.Minute =\r
2369 FileEntry->AccessTime.Minute;\r
2370 FileInfo->LastAccessTime.Second =\r
2371 FileEntry->AccessTime.Second;\r
2372 FileInfo->LastAccessTime.Nanosecond =\r
2373 FileEntry->AccessTime.HundredsOfMicroseconds;\r
baaa3cee 2374 } else if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {\r
99c9b949
PA
2375 ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;\r
2376\r
2377 //\r
2378 // Check if EFE has the system attribute set.\r
2379 //\r
2380 if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {\r
2381 FileInfo->Attribute |= EFI_FILE_SYSTEM;\r
2382 }\r
2383\r
2384 FileInfo->FileSize = FileSize;\r
2385 FileInfo->PhysicalSize = FileSize;\r
2386\r
2387 FileInfo->CreateTime.Year = ExtendedFileEntry->CreationTime.Year;\r
2388 FileInfo->CreateTime.Month = ExtendedFileEntry->CreationTime.Month;\r
2389 FileInfo->CreateTime.Day = ExtendedFileEntry->CreationTime.Day;\r
2390 FileInfo->CreateTime.Hour = ExtendedFileEntry->CreationTime.Hour;\r
2391 FileInfo->CreateTime.Minute = ExtendedFileEntry->CreationTime.Second;\r
2392 FileInfo->CreateTime.Second = ExtendedFileEntry->CreationTime.Second;\r
2393 FileInfo->CreateTime.Nanosecond =\r
2394 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;\r
2395\r
2396 FileInfo->LastAccessTime.Year =\r
2397 ExtendedFileEntry->AccessTime.Year;\r
2398 FileInfo->LastAccessTime.Month =\r
2399 ExtendedFileEntry->AccessTime.Month;\r
2400 FileInfo->LastAccessTime.Day =\r
2401 ExtendedFileEntry->AccessTime.Day;\r
2402 FileInfo->LastAccessTime.Hour =\r
2403 ExtendedFileEntry->AccessTime.Hour;\r
2404 FileInfo->LastAccessTime.Minute =\r
2405 ExtendedFileEntry->AccessTime.Minute;\r
2406 FileInfo->LastAccessTime.Second =\r
2407 ExtendedFileEntry->AccessTime.Second;\r
2408 FileInfo->LastAccessTime.Nanosecond =\r
2409 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;\r
2410 }\r
2411\r
2412 FileInfo->CreateTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
2413 FileInfo->CreateTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;\r
2414 FileInfo->LastAccessTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
2415 FileInfo->LastAccessTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;\r
2416\r
2417 CopyMem ((VOID *)&FileInfo->ModificationTime,\r
2418 (VOID *)&FileInfo->LastAccessTime,\r
2419 sizeof (EFI_TIME));\r
2420\r
2421 if (FileName != NULL) {\r
2422 StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);\r
2423 } else {\r
2424 FileInfo->FileName[0] = '\0';\r
2425 }\r
2426\r
2427 *BufferSize = FileInfoLength;\r
2428\r
2429 return EFI_SUCCESS;\r
2430}\r
2431\r
2432/**\r
2433 Get volume and free space size information of an UDF volume.\r
2434\r
2435 @param[in] BlockIo BlockIo interface.\r
2436 @param[in] DiskIo DiskIo interface.\r
2437 @param[in] Volume UDF volume information structure.\r
2438 @param[out] VolumeSize Volume size.\r
2439 @param[out] FreeSpaceSize Free space size.\r
2440\r
2441 @retval EFI_SUCCESS Volume and free space size calculated.\r
2442 @retval EFI_NO_MEDIA The device has no media.\r
2443 @retval EFI_DEVICE_ERROR The device reported an error.\r
2444 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2445 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not\r
2446 calculated due to lack of resources.\r
2447\r
2448**/\r
2449EFI_STATUS\r
2450GetVolumeSize (\r
2451 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2452 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2453 IN UDF_VOLUME_INFO *Volume,\r
2454 OUT UINT64 *VolumeSize,\r
2455 OUT UINT64 *FreeSpaceSize\r
2456 )\r
2457{\r
baaa3cee
PA
2458 EFI_STATUS Status;\r
2459 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;\r
2460 UDF_EXTENT_AD *ExtentAd;\r
2461 UINT64 Lsn;\r
2462 UINT32 LogicalBlockSize;\r
2463 UDF_LOGICAL_VOLUME_INTEGRITY *LogicalVolInt;\r
2464 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
2465 UINTN Index;\r
2466 UINTN Length;\r
2467 UINT32 LsnsNo;\r
99c9b949 2468\r
baaa3cee 2469 LogicalVolDesc = &Volume->LogicalVolDesc;\r
99c9b949 2470\r
baaa3cee 2471 ExtentAd = &LogicalVolDesc->IntegritySequenceExtent;\r
99c9b949 2472\r
baaa3cee
PA
2473 if (ExtentAd->ExtentLength == 0) {\r
2474 return EFI_VOLUME_CORRUPTED;\r
2475 }\r
99c9b949 2476\r
baaa3cee
PA
2477 LogicalVolInt = AllocatePool (ExtentAd->ExtentLength);\r
2478 if (LogicalVolInt == NULL) {\r
2479 return EFI_OUT_OF_RESOURCES;\r
2480 }\r
99c9b949 2481\r
baaa3cee
PA
2482 //\r
2483 // Get location of Logical Volume Integrity Descriptor\r
2484 //\r
2485 Lsn = (UINT64)ExtentAd->ExtentLocation - Volume->MainVdsStartLocation;\r
99c9b949 2486\r
baaa3cee 2487 LogicalBlockSize = LogicalVolDesc->LogicalBlockSize;\r
99c9b949 2488\r
baaa3cee
PA
2489 //\r
2490 // Read disk block\r
2491 //\r
2492 Status = DiskIo->ReadDisk (\r
2493 DiskIo,\r
2494 BlockIo->Media->MediaId,\r
2495 MultU64x32 (Lsn, LogicalBlockSize),\r
2496 ExtentAd->ExtentLength,\r
2497 LogicalVolInt\r
2498 );\r
2499 if (EFI_ERROR (Status)) {\r
2500 goto Out_Free;\r
2501 }\r
99c9b949 2502\r
baaa3cee 2503 DescriptorTag = &LogicalVolInt->DescriptorTag;\r
99c9b949 2504\r
baaa3cee
PA
2505 //\r
2506 // Check if read block is a Logical Volume Integrity Descriptor\r
2507 //\r
2508 if (DescriptorTag->TagIdentifier != UdfLogicalVolumeIntegrityDescriptor) {\r
2509 Status = EFI_VOLUME_CORRUPTED;\r
2510 goto Out_Free;\r
2511 }\r
2512\r
2513 *VolumeSize = 0;\r
2514 *FreeSpaceSize = 0;\r
99c9b949 2515\r
baaa3cee
PA
2516 Length = LogicalVolInt->NumberOfPartitions;\r
2517 for (Index = 0; Index < Length; Index += sizeof (UINT32)) {\r
2518 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);\r
2519 //\r
2520 // Check if size is not specified\r
2521 //\r
2522 if (LsnsNo == 0xFFFFFFFFUL) {\r
2523 continue;\r
99c9b949 2524 }\r
baaa3cee
PA
2525 //\r
2526 // Accumulate free space size\r
2527 //\r
2528 *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);\r
2529 }\r
99c9b949 2530\r
baaa3cee
PA
2531 Length = LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2;\r
2532 for (; Index < Length; Index += sizeof (UINT32)) {\r
2533 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);\r
2534 //\r
2535 // Check if size is not specified\r
2536 //\r
2537 if (LsnsNo == 0xFFFFFFFFUL) {\r
2538 continue;\r
2539 }\r
2540 //\r
2541 // Accumulate used volume space\r
2542 //\r
2543 *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);\r
99c9b949
PA
2544 }\r
2545\r
baaa3cee
PA
2546 Status = EFI_SUCCESS;\r
2547\r
2548Out_Free:\r
2549 //\r
2550 // Free Logical Volume Integrity Descriptor\r
2551 //\r
2552 FreePool (LogicalVolInt);\r
2553\r
2554 return Status;\r
99c9b949
PA
2555}\r
2556\r
2557/**\r
2558 Seek a file and read its data into memory on an UDF volume.\r
2559\r
2560 @param[in] BlockIo BlockIo interface.\r
2561 @param[in] DiskIo DiskIo interface.\r
2562 @param[in] Volume UDF volume information structure.\r
2563 @param[in] File File information structure.\r
2564 @param[in] FileSize Size of the file.\r
077f8c43
HW
2565 @param[in, out] FilePosition File position.\r
2566 @param[in, out] Buffer File data.\r
2567 @param[in, out] BufferSize Read size.\r
99c9b949
PA
2568\r
2569 @retval EFI_SUCCESS File seeked and read.\r
2570 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
2571 @retval EFI_NO_MEDIA The device has no media.\r
2572 @retval EFI_DEVICE_ERROR The device reported an error.\r
2573 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2574 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack\r
2575 of resources.\r
2576\r
2577**/\r
2578EFI_STATUS\r
2579ReadFileData (\r
2580 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2581 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2582 IN UDF_VOLUME_INFO *Volume,\r
2583 IN UDF_FILE_INFO *File,\r
2584 IN UINT64 FileSize,\r
2585 IN OUT UINT64 *FilePosition,\r
2586 IN OUT VOID *Buffer,\r
2587 IN OUT UINT64 *BufferSize\r
2588 )\r
2589{\r
2590 EFI_STATUS Status;\r
2591 UDF_READ_FILE_INFO ReadFileInfo;\r
2592\r
880ec683 2593 ReadFileInfo.Flags = ReadFileSeekAndRead;\r
99c9b949
PA
2594 ReadFileInfo.FilePosition = *FilePosition;\r
2595 ReadFileInfo.FileData = Buffer;\r
2596 ReadFileInfo.FileDataSize = *BufferSize;\r
2597 ReadFileInfo.FileSize = FileSize;\r
2598\r
2599 Status = ReadFile (\r
2600 BlockIo,\r
2601 DiskIo,\r
2602 Volume,\r
2603 &File->FileIdentifierDesc->Icb,\r
2604 File->FileEntry,\r
2605 &ReadFileInfo\r
2606 );\r
2607 if (EFI_ERROR (Status)) {\r
2608 return Status;\r
2609 }\r
2610\r
2611 *BufferSize = ReadFileInfo.FileDataSize;\r
2612 *FilePosition = ReadFileInfo.FilePosition;\r
2613\r
2614 return EFI_SUCCESS;\r
2615}\r
2616\r
2617/**\r
2618 Check if ControllerHandle supports an UDF file system.\r
2619\r
2620 @param[in] This Protocol instance pointer.\r
2621 @param[in] ControllerHandle Handle of device to test.\r
2622\r
2623 @retval EFI_SUCCESS UDF file system found.\r
2624 @retval EFI_UNSUPPORTED UDF file system not found.\r
2625\r
2626**/\r
2627EFI_STATUS\r
2628SupportUdfFileSystem (\r
2629 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2630 IN EFI_HANDLE ControllerHandle\r
2631 )\r
2632{\r
2633 EFI_STATUS Status;\r
2634 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2635 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
2636 EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;\r
2637 EFI_GUID *VendorDefinedGuid;\r
99c9b949
PA
2638\r
2639 //\r
2640 // Open Device Path protocol on ControllerHandle\r
2641 //\r
2642 Status = gBS->OpenProtocol (\r
2643 ControllerHandle,\r
2644 &gEfiDevicePathProtocolGuid,\r
2645 (VOID **)&DevicePath,\r
2646 This->DriverBindingHandle,\r
2647 ControllerHandle,\r
2648 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2649 );\r
2650 if (EFI_ERROR (Status)) {\r
2651 return EFI_UNSUPPORTED;\r
2652 }\r
2653\r
2654 Status = EFI_UNSUPPORTED;\r
2655\r
2656 //\r
2657 // Get last Device Path node\r
2658 //\r
2659 LastDevicePathNode = NULL;\r
2660 DevicePathNode = DevicePath;\r
2661 while (!IsDevicePathEnd (DevicePathNode)) {\r
2662 LastDevicePathNode = DevicePathNode;\r
2663 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
2664 }\r
2665 //\r
2666 // Check if last Device Path node contains a Vendor-Defined Media Device Path\r
2667 // of an UDF file system.\r
2668 //\r
2669 if (LastDevicePathNode != NULL &&\r
2670 DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&\r
2671 DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP) {\r
2672 VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +\r
2673 OFFSET_OF (VENDOR_DEVICE_PATH, Guid));\r
3f92b104 2674 if (CompareGuid (VendorDefinedGuid, &gUdfDevPathGuid)) {\r
99c9b949
PA
2675 Status = EFI_SUCCESS;\r
2676 }\r
2677 }\r
2678\r
2679 //\r
2680 // Close Device Path protocol on ControllerHandle\r
2681 //\r
2682 gBS->CloseProtocol (\r
2683 ControllerHandle,\r
2684 &gEfiDevicePathProtocolGuid,\r
2685 This->DriverBindingHandle,\r
2686 ControllerHandle\r
2687 );\r
2688\r
2689 return Status;\r
2690}\r