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