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