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