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