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