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