]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
MdeModulePkg/PartitionDxe: Merge the discovery of ElTorito into UDF
[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
ce9aaba6
HW
751 UDF_PARTITION_DESCRIPTOR *PartitionDesc;\r
752\r
880ec683 753 if (RecordingFlags == LongAdsSequence) {\r
99c9b949 754 return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad);\r
880ec683 755 } else if (RecordingFlags == ShortAdsSequence) {\r
ce9aaba6
HW
756 PartitionDesc = GetPdFromLongAd (Volume, ParentIcb);\r
757 ASSERT (PartitionDesc != NULL);\r
758\r
99c9b949 759 return GetShortAdLsn (\r
baaa3cee 760 Volume,\r
ce9aaba6 761 PartitionDesc,\r
99c9b949
PA
762 (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad\r
763 );\r
764 }\r
765\r
766 return 0;\r
767}\r
768\r
077f8c43
HW
769/**\r
770 Return offset + length of a given indirect Allocation Descriptor (AED).\r
771\r
772 @param[in] BlockIo BlockIo interface.\r
773 @param[in] DiskIo DiskIo interface.\r
774 @param[in] Volume Volume information pointer.\r
775 @param[in] ParentIcb Long Allocation Descriptor pointer.\r
776 @param[in] RecordingFlags Flag to indicate the type of descriptor.\r
777 @param[in] Ad Allocation Descriptor pointer.\r
778 @param[out] Offset Offset of a given indirect Allocation\r
779 Descriptor.\r
780 @param[out] Length Length of a given indirect Allocation\r
781 Descriptor.\r
782\r
783 @retval EFI_SUCCESS The offset and length were returned.\r
784 @retval EFI_OUT_OF_RESOURCES The offset and length were not returned due\r
785 to lack of resources.\r
786 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
787 @retval other The offset and length were not returned.\r
788\r
789**/\r
99c9b949
PA
790EFI_STATUS\r
791GetAedAdsOffset (\r
792 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
793 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
794 IN UDF_VOLUME_INFO *Volume,\r
795 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
796 IN UDF_FE_RECORDING_FLAGS RecordingFlags,\r
797 IN VOID *Ad,\r
798 OUT UINT64 *Offset,\r
799 OUT UINT64 *Length\r
800 )\r
801{\r
802 EFI_STATUS Status;\r
803 UINT32 ExtentLength;\r
804 UINT64 Lsn;\r
805 VOID *Data;\r
806 UINT32 LogicalBlockSize;\r
807 UDF_ALLOCATION_EXTENT_DESCRIPTOR *AllocExtDesc;\r
baaa3cee 808 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
99c9b949
PA
809\r
810 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
811 Lsn = GetAllocationDescriptorLsn (RecordingFlags,\r
812 Volume,\r
813 ParentIcb,\r
814 Ad);\r
815\r
816 Data = AllocatePool (ExtentLength);\r
817 if (Data == NULL) {\r
818 return EFI_OUT_OF_RESOURCES;\r
819 }\r
820\r
baaa3cee 821 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;\r
99c9b949
PA
822\r
823 //\r
824 // Read extent.\r
825 //\r
826 Status = DiskIo->ReadDisk (\r
827 DiskIo,\r
828 BlockIo->Media->MediaId,\r
829 MultU64x32 (Lsn, LogicalBlockSize),\r
830 ExtentLength,\r
831 Data\r
832 );\r
833 if (EFI_ERROR (Status)) {\r
834 goto Exit;\r
835 }\r
836\r
baaa3cee
PA
837 AllocExtDesc = (UDF_ALLOCATION_EXTENT_DESCRIPTOR *)Data;\r
838\r
839 DescriptorTag = &AllocExtDesc->DescriptorTag;\r
840\r
99c9b949
PA
841 //\r
842 // Check if read extent contains a valid tag identifier for AED.\r
843 //\r
baaa3cee 844 if (DescriptorTag->TagIdentifier != UdfAllocationExtentDescriptor) {\r
99c9b949
PA
845 Status = EFI_VOLUME_CORRUPTED;\r
846 goto Exit;\r
847 }\r
848\r
849 //\r
850 // Get AED's block offset and its length.\r
851 //\r
852 *Offset = MultU64x32 (Lsn, LogicalBlockSize) +\r
853 sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR);\r
854 *Length = AllocExtDesc->LengthOfAllocationDescriptors;\r
855\r
856Exit:\r
857 FreePool (Data);\r
858\r
859 return Status;\r
860}\r
861\r
077f8c43
HW
862/**\r
863 Read Allocation Extent Descriptor into memory.\r
864\r
865 @param[in] BlockIo BlockIo interface.\r
866 @param[in] DiskIo DiskIo interface.\r
867 @param[in] Volume Volume information pointer.\r
868 @param[in] ParentIcb Long Allocation Descriptor pointer.\r
869 @param[in] RecordingFlags Flag to indicate the type of descriptor.\r
870 @param[in] Ad Allocation Descriptor pointer.\r
871 @param[out] Data Buffer that contains the Allocation Extent\r
872 Descriptor.\r
873 @param[out] Length Length of Data.\r
874\r
875 @retval EFI_SUCCESS The Allocation Extent Descriptor was read.\r
876 @retval EFI_OUT_OF_RESOURCES The Allocation Extent Descriptor was not read\r
877 due to lack of resources.\r
878 @retval other Fail to read the disk.\r
879\r
880**/\r
99c9b949
PA
881EFI_STATUS\r
882GetAedAdsData (\r
883 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
884 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
885 IN UDF_VOLUME_INFO *Volume,\r
886 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
887 IN UDF_FE_RECORDING_FLAGS RecordingFlags,\r
888 IN VOID *Ad,\r
889 OUT VOID **Data,\r
890 OUT UINT64 *Length\r
891 )\r
892{\r
893 EFI_STATUS Status;\r
894 UINT64 Offset;\r
895\r
896 //\r
897 // Get AED's offset + length.\r
898 //\r
899 Status = GetAedAdsOffset (\r
900 BlockIo,\r
901 DiskIo,\r
902 Volume,\r
903 ParentIcb,\r
904 RecordingFlags,\r
905 Ad,\r
906 &Offset,\r
907 Length\r
908 );\r
909 if (EFI_ERROR (Status)) {\r
910 return Status;\r
911 }\r
912\r
913 //\r
914 // Allocate buffer to read in AED's data.\r
915 //\r
0b4c8f00 916 *Data = AllocatePool ((UINTN) (*Length));\r
99c9b949
PA
917 if (*Data == NULL) {\r
918 return EFI_OUT_OF_RESOURCES;\r
919 }\r
920\r
921 return DiskIo->ReadDisk (\r
922 DiskIo,\r
923 BlockIo->Media->MediaId,\r
924 Offset,\r
0b4c8f00 925 (UINTN) (*Length),\r
99c9b949
PA
926 *Data\r
927 );\r
928}\r
929\r
077f8c43
HW
930/**\r
931 Function used to serialise reads of Allocation Descriptors.\r
932\r
933 @param[in] RecordingFlags Flag to indicate the type of descriptor.\r
934 @param[in] Ad Allocation Descriptor pointer.\r
935 @param[in, out] Buffer Buffer to hold the next Allocation Descriptor.\r
936 @param[in] Length Length of Buffer.\r
937\r
938 @retval EFI_SUCCESS Buffer was grown to hold the next Allocation\r
939 Descriptor.\r
940 @retval EFI_OUT_OF_RESOURCES Buffer was not grown due to lack of resources.\r
941\r
942**/\r
99c9b949
PA
943EFI_STATUS\r
944GrowUpBufferToNextAd (\r
945 IN UDF_FE_RECORDING_FLAGS RecordingFlags,\r
946 IN VOID *Ad,\r
947 IN OUT VOID **Buffer,\r
948 IN UINT64 Length\r
949 )\r
950{\r
951 UINT32 ExtentLength;\r
952\r
953 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
954\r
955 if (*Buffer == NULL) {\r
956 *Buffer = AllocatePool (ExtentLength);\r
957 if (*Buffer == NULL) {\r
958 return EFI_OUT_OF_RESOURCES;\r
959 }\r
960 } else {\r
0b4c8f00 961 *Buffer = ReallocatePool ((UINTN) Length, (UINTN) (Length + ExtentLength), *Buffer);\r
99c9b949
PA
962 if (*Buffer == NULL) {\r
963 return EFI_OUT_OF_RESOURCES;\r
964 }\r
965 }\r
966\r
967 return EFI_SUCCESS;\r
968}\r
969\r
077f8c43
HW
970/**\r
971 Read data or size of either a File Entry or an Extended File Entry.\r
972\r
973 @param[in] BlockIo BlockIo interface.\r
974 @param[in] DiskIo DiskIo interface.\r
975 @param[in] Volume Volume information pointer.\r
976 @param[in] ParentIcb Long Allocation Descriptor pointer.\r
977 @param[in] FileEntryData FE/EFE structure pointer.\r
978 @param[in, out] ReadFileInfo Read file information pointer.\r
979\r
980 @retval EFI_SUCCESS Data or size of a FE/EFE was read.\r
981 @retval EFI_OUT_OF_RESOURCES Data or size of a FE/EFE was not read due to\r
982 lack of resources.\r
983 @retval EFI_INVALID_PARAMETER The read file flag given in ReadFileInfo is\r
984 invalid.\r
985 @retval EFI_UNSUPPORTED The FE recording flag given in FileEntryData\r
986 is not supported.\r
987 @retval other Data or size of a FE/EFE was not read.\r
988\r
989**/\r
99c9b949
PA
990EFI_STATUS\r
991ReadFile (\r
992 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
993 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
994 IN UDF_VOLUME_INFO *Volume,\r
995 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
996 IN VOID *FileEntryData,\r
997 IN OUT UDF_READ_FILE_INFO *ReadFileInfo\r
998 )\r
999{\r
1000 EFI_STATUS Status;\r
1001 UINT32 LogicalBlockSize;\r
1002 VOID *Data;\r
1003 UINT64 Length;\r
1004 VOID *Ad;\r
1005 UINT64 AdOffset;\r
1006 UINT64 Lsn;\r
1007 BOOLEAN DoFreeAed;\r
1008 UINT64 FilePosition;\r
1009 UINT64 Offset;\r
1010 UINT64 DataOffset;\r
1011 UINT64 BytesLeft;\r
1012 UINT64 DataLength;\r
1013 BOOLEAN FinishedSeeking;\r
1014 UINT32 ExtentLength;\r
1015 UDF_FE_RECORDING_FLAGS RecordingFlags;\r
1016\r
baaa3cee 1017 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;\r
99c9b949
PA
1018 DoFreeAed = FALSE;\r
1019\r
5afa5b81
LE
1020 //\r
1021 // set BytesLeft to suppress incorrect compiler/analyzer warnings\r
1022 //\r
1023 BytesLeft = 0;\r
54537008
SZ
1024 DataOffset = 0;\r
1025 FilePosition = 0;\r
1026 FinishedSeeking = FALSE;\r
1027 Data = NULL;\r
5afa5b81 1028\r
99c9b949 1029 switch (ReadFileInfo->Flags) {\r
880ec683
HW
1030 case ReadFileGetFileSize:\r
1031 case ReadFileAllocateAndRead:\r
99c9b949
PA
1032 //\r
1033 // Initialise ReadFileInfo structure for either getting file size, or\r
1034 // reading file's recorded data.\r
1035 //\r
1036 ReadFileInfo->ReadLength = 0;\r
1037 ReadFileInfo->FileData = NULL;\r
1038 break;\r
880ec683 1039 case ReadFileSeekAndRead:\r
99c9b949
PA
1040 //\r
1041 // About to seek a file and/or read its data.\r
1042 //\r
1043 Length = ReadFileInfo->FileSize - ReadFileInfo->FilePosition;\r
1044 if (ReadFileInfo->FileDataSize > Length) {\r
1045 //\r
1046 // About to read beyond the EOF -- truncate it.\r
1047 //\r
1048 ReadFileInfo->FileDataSize = Length;\r
1049 }\r
1050\r
1051 //\r
1052 // Initialise data to start seeking and/or reading a file.\r
1053 //\r
1054 BytesLeft = ReadFileInfo->FileDataSize;\r
1055 DataOffset = 0;\r
1056 FilePosition = 0;\r
1057 FinishedSeeking = FALSE;\r
1058\r
1059 break;\r
1060 }\r
1061\r
1062 RecordingFlags = GET_FE_RECORDING_FLAGS (FileEntryData);\r
1063 switch (RecordingFlags) {\r
880ec683 1064 case InlineData:\r
99c9b949
PA
1065 //\r
1066 // There are no extents for this FE/EFE. All data is inline.\r
1067 //\r
1068 GetFileEntryData (FileEntryData, &Data, &Length);\r
1069\r
880ec683 1070 if (ReadFileInfo->Flags == ReadFileGetFileSize) {\r
99c9b949 1071 ReadFileInfo->ReadLength = Length;\r
880ec683 1072 } else if (ReadFileInfo->Flags == ReadFileAllocateAndRead) {\r
99c9b949
PA
1073 //\r
1074 // Allocate buffer for starting read data.\r
1075 //\r
0b4c8f00 1076 ReadFileInfo->FileData = AllocatePool ((UINTN) Length);\r
99c9b949
PA
1077 if (ReadFileInfo->FileData == NULL) {\r
1078 return EFI_OUT_OF_RESOURCES;\r
1079 }\r
1080\r
1081 //\r
1082 // Read all inline data into ReadFileInfo->FileData\r
1083 //\r
0b4c8f00 1084 CopyMem (ReadFileInfo->FileData, Data, (UINTN) Length);\r
99c9b949 1085 ReadFileInfo->ReadLength = Length;\r
880ec683 1086 } else if (ReadFileInfo->Flags == ReadFileSeekAndRead) {\r
99c9b949
PA
1087 //\r
1088 // If FilePosition is non-zero, seek file to FilePosition, read\r
1089 // FileDataSize bytes and then updates FilePosition.\r
1090 //\r
1091 CopyMem (\r
1092 ReadFileInfo->FileData,\r
1093 (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition),\r
0b4c8f00 1094 (UINTN) ReadFileInfo->FileDataSize\r
99c9b949
PA
1095 );\r
1096\r
1097 ReadFileInfo->FilePosition += ReadFileInfo->FileDataSize;\r
a3240c63
LE
1098 } else {\r
1099 ASSERT (FALSE);\r
1100 return EFI_INVALID_PARAMETER;\r
99c9b949
PA
1101 }\r
1102\r
131fd40f 1103 Status = EFI_SUCCESS;\r
99c9b949 1104 break;\r
131fd40f 1105\r
880ec683
HW
1106 case LongAdsSequence:\r
1107 case ShortAdsSequence:\r
99c9b949
PA
1108 //\r
1109 // This FE/EFE contains a run of Allocation Descriptors. Get data + size\r
1110 // for start reading them out.\r
1111 //\r
1112 GetAdsInformation (FileEntryData, &Data, &Length);\r
1113 AdOffset = 0;\r
1114\r
1115 for (;;) {\r
1116 //\r
1117 // Read AD.\r
1118 //\r
1119 Status = GetAllocationDescriptor (\r
1120 RecordingFlags,\r
1121 Data,\r
1122 &AdOffset,\r
1123 Length,\r
1124 &Ad\r
1125 );\r
1126 if (Status == EFI_DEVICE_ERROR) {\r
1127 Status = EFI_SUCCESS;\r
1128 goto Done;\r
1129 }\r
1130\r
1131 //\r
1132 // Check if AD is an indirect AD. If so, read Allocation Extent\r
1133 // Descriptor and its extents (ADs).\r
1134 //\r
880ec683 1135 if (GET_EXTENT_FLAGS (RecordingFlags, Ad) == ExtentIsNextExtent) {\r
99c9b949
PA
1136 if (!DoFreeAed) {\r
1137 DoFreeAed = TRUE;\r
1138 } else {\r
1139 FreePool (Data);\r
1140 }\r
1141\r
1142 Status = GetAedAdsData (\r
1143 BlockIo,\r
1144 DiskIo,\r
1145 Volume,\r
1146 ParentIcb,\r
1147 RecordingFlags,\r
1148 Ad,\r
1149 &Data,\r
1150 &Length\r
1151 );\r
1152 if (EFI_ERROR (Status)) {\r
1153 goto Error_Get_Aed;\r
1154 }\r
3fa40d58 1155 ASSERT (Data != NULL);\r
99c9b949
PA
1156\r
1157 AdOffset = 0;\r
1158 continue;\r
1159 }\r
1160\r
1161 ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);\r
1162\r
1163 Lsn = GetAllocationDescriptorLsn (RecordingFlags,\r
1164 Volume,\r
1165 ParentIcb,\r
1166 Ad);\r
1167\r
1168 switch (ReadFileInfo->Flags) {\r
880ec683 1169 case ReadFileGetFileSize:\r
99c9b949
PA
1170 ReadFileInfo->ReadLength += ExtentLength;\r
1171 break;\r
880ec683 1172 case ReadFileAllocateAndRead:\r
99c9b949
PA
1173 //\r
1174 // Increase FileData (if necessary) to read next extent.\r
1175 //\r
1176 Status = GrowUpBufferToNextAd (\r
1177 RecordingFlags,\r
1178 Ad,\r
1179 &ReadFileInfo->FileData,\r
1180 ReadFileInfo->ReadLength\r
1181 );\r
1182 if (EFI_ERROR (Status)) {\r
1183 goto Error_Alloc_Buffer_To_Next_Ad;\r
1184 }\r
1185\r
1186 //\r
1187 // Read extent's data into FileData.\r
1188 //\r
1189 Status = DiskIo->ReadDisk (\r
1190 DiskIo,\r
1191 BlockIo->Media->MediaId,\r
1192 MultU64x32 (Lsn, LogicalBlockSize),\r
1193 ExtentLength,\r
1194 (VOID *)((UINT8 *)ReadFileInfo->FileData +\r
1195 ReadFileInfo->ReadLength)\r
1196 );\r
1197 if (EFI_ERROR (Status)) {\r
1198 goto Error_Read_Disk_Blk;\r
1199 }\r
1200\r
1201 ReadFileInfo->ReadLength += ExtentLength;\r
1202 break;\r
880ec683 1203 case ReadFileSeekAndRead:\r
99c9b949
PA
1204 //\r
1205 // Seek file first before reading in its data.\r
1206 //\r
1207 if (FinishedSeeking) {\r
1208 Offset = 0;\r
1209 goto Skip_File_Seek;\r
1210 }\r
1211\r
1212 if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) {\r
1213 FilePosition += ExtentLength;\r
1214 goto Skip_Ad;\r
1215 }\r
1216\r
1217 if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) {\r
1218 Offset = ReadFileInfo->FilePosition - FilePosition;\r
99c9b949
PA
1219 } else {\r
1220 Offset = 0;\r
1221 }\r
1222\r
1223 //\r
1224 // Done with seeking file. Start reading its data.\r
1225 //\r
1226 FinishedSeeking = TRUE;\r
1227\r
1228 Skip_File_Seek:\r
1229 //\r
1230 // Make sure we don't read more data than really wanted.\r
1231 //\r
1232 if (ExtentLength - Offset > BytesLeft) {\r
1233 DataLength = BytesLeft;\r
1234 } else {\r
1235 DataLength = ExtentLength - Offset;\r
1236 }\r
1237\r
1238 //\r
1239 // Read extent's data into FileData.\r
1240 //\r
1241 Status = DiskIo->ReadDisk (\r
1242 DiskIo,\r
1243 BlockIo->Media->MediaId,\r
1244 Offset + MultU64x32 (Lsn, LogicalBlockSize),\r
0b4c8f00 1245 (UINTN) DataLength,\r
99c9b949
PA
1246 (VOID *)((UINT8 *)ReadFileInfo->FileData +\r
1247 DataOffset)\r
1248 );\r
1249 if (EFI_ERROR (Status)) {\r
1250 goto Error_Read_Disk_Blk;\r
1251 }\r
1252\r
1253 //\r
1254 // Update current file's position.\r
1255 //\r
1256 DataOffset += DataLength;\r
1257 ReadFileInfo->FilePosition += DataLength;\r
1258\r
1259 BytesLeft -= DataLength;\r
1260 if (BytesLeft == 0) {\r
1261 //\r
1262 // There is no more file data to read.\r
1263 //\r
1264 Status = EFI_SUCCESS;\r
1265 goto Done;\r
1266 }\r
1267\r
1268 break;\r
1269 }\r
1270\r
1271 Skip_Ad:\r
1272 //\r
1273 // Point to the next AD (extent).\r
1274 //\r
1275 AdOffset += AD_LENGTH (RecordingFlags);\r
1276 }\r
1277\r
1278 break;\r
880ec683 1279 case ExtendedAdsSequence:\r
99c9b949
PA
1280 // FIXME: Not supported. Got no volume with it, yet.\r
1281 ASSERT (FALSE);\r
1282 Status = EFI_UNSUPPORTED;\r
1283 break;\r
998aee89
LE
1284\r
1285 default:\r
1286 //\r
1287 // A flag value reserved by the ECMA-167 standard (3rd Edition - June\r
1288 // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.\r
1289 //\r
1290 Status = EFI_UNSUPPORTED;\r
1291 break;\r
99c9b949
PA
1292 }\r
1293\r
1294Done:\r
1295 if (DoFreeAed) {\r
1296 FreePool (Data);\r
1297 }\r
1298\r
1299 return Status;\r
1300\r
1301Error_Read_Disk_Blk:\r
1302Error_Alloc_Buffer_To_Next_Ad:\r
880ec683 1303 if (ReadFileInfo->Flags != ReadFileSeekAndRead) {\r
99c9b949
PA
1304 FreePool (ReadFileInfo->FileData);\r
1305 }\r
1306\r
1307 if (DoFreeAed) {\r
1308 FreePool (Data);\r
1309 }\r
1310\r
1311Error_Get_Aed:\r
1312 return Status;\r
1313}\r
1314\r
077f8c43
HW
1315/**\r
1316 Find a file by its filename from a given Parent file.\r
1317\r
1318 @param[in] BlockIo BlockIo interface.\r
1319 @param[in] DiskIo DiskIo interface.\r
1320 @param[in] Volume Volume information pointer.\r
1321 @param[in] FileName File name string.\r
1322 @param[in] Parent Parent directory file.\r
1323 @param[in] Icb Long Allocation Descriptor pointer.\r
1324 @param[out] File Found file.\r
1325\r
1326 @retval EFI_SUCCESS The file was found.\r
1327 @retval EFI_INVALID_PARAMETER One or more input parameters are invalid.\r
1328 @retval EFI_NOT_FOUND The file was not found.\r
1329\r
1330**/\r
99c9b949
PA
1331EFI_STATUS\r
1332InternalFindFile (\r
1333 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1334 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1335 IN UDF_VOLUME_INFO *Volume,\r
1336 IN CHAR16 *FileName,\r
1337 IN UDF_FILE_INFO *Parent,\r
1338 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,\r
1339 OUT UDF_FILE_INFO *File\r
1340 )\r
1341{\r
1342 EFI_STATUS Status;\r
1343 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;\r
1344 UDF_READ_DIRECTORY_INFO ReadDirInfo;\r
1345 BOOLEAN Found;\r
1346 CHAR16 FoundFileName[UDF_FILENAME_LENGTH];\r
1347 VOID *CompareFileEntry;\r
1348\r
3fa40d58
HW
1349 //\r
1350 // Check if both Parent->FileIdentifierDesc and Icb are NULL.\r
1351 //\r
1352 if ((Parent->FileIdentifierDesc == NULL) && (Icb == NULL)) {\r
1353 return EFI_INVALID_PARAMETER;\r
1354 }\r
1355\r
99c9b949
PA
1356 //\r
1357 // Check if parent file is really directory.\r
1358 //\r
baaa3cee 1359 if (FE_ICB_FILE_TYPE (Parent->FileEntry) != UdfFileEntryDirectory) {\r
99c9b949
PA
1360 return EFI_NOT_FOUND;\r
1361 }\r
1362\r
1363 //\r
1364 // If FileName is current file or working directory, just duplicate Parent's\r
1365 // FE/EFE and FID descriptors.\r
1366 //\r
1367 if (StrCmp (FileName, L".") == 0) {\r
3fa40d58
HW
1368 if (Parent->FileIdentifierDesc == NULL) {\r
1369 return EFI_INVALID_PARAMETER;\r
1370 }\r
1371\r
99c9b949
PA
1372 DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);\r
1373 DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);\r
1374\r
1375 return EFI_SUCCESS;\r
1376 }\r
1377\r
1378 //\r
1379 // Start directory listing.\r
1380 //\r
1381 ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));\r
1382 Found = FALSE;\r
1383\r
1384 for (;;) {\r
1385 Status = ReadDirectoryEntry (\r
1386 BlockIo,\r
1387 DiskIo,\r
1388 Volume,\r
12b83f56 1389 (Parent->FileIdentifierDesc != NULL) ?\r
99c9b949
PA
1390 &Parent->FileIdentifierDesc->Icb :\r
1391 Icb,\r
1392 Parent->FileEntry,\r
1393 &ReadDirInfo,\r
1394 &FileIdentifierDesc\r
1395 );\r
1396 if (EFI_ERROR (Status)) {\r
1397 if (Status == EFI_DEVICE_ERROR) {\r
1398 Status = EFI_NOT_FOUND;\r
1399 }\r
1400\r
1401 break;\r
1402 }\r
1403\r
baaa3cee 1404 if (FileIdentifierDesc->FileCharacteristics & PARENT_FILE) {\r
99c9b949
PA
1405 //\r
1406 // This FID contains the location (FE/EFE) of the parent directory of this\r
1407 // directory (Parent), and if FileName is either ".." or "\\", then it's\r
1408 // the expected FID.\r
1409 //\r
1410 if (StrCmp (FileName, L"..") == 0 || StrCmp (FileName, L"\\") == 0) {\r
1411 Found = TRUE;\r
1412 break;\r
1413 }\r
1414 } else {\r
1415 Status = GetFileNameFromFid (FileIdentifierDesc, FoundFileName);\r
1416 if (EFI_ERROR (Status)) {\r
1417 break;\r
1418 }\r
1419\r
1420 if (StrCmp (FileName, FoundFileName) == 0) {\r
1421 //\r
1422 // FID has been found. Prepare to find its respective FE/EFE.\r
1423 //\r
1424 Found = TRUE;\r
1425 break;\r
1426 }\r
1427 }\r
1428\r
1429 FreePool ((VOID *)FileIdentifierDesc);\r
1430 }\r
1431\r
1432 if (ReadDirInfo.DirectoryData != NULL) {\r
1433 //\r
1434 // Free all allocated resources for the directory listing.\r
1435 //\r
1436 FreePool (ReadDirInfo.DirectoryData);\r
1437 }\r
1438\r
1439 if (Found) {\r
1440 Status = EFI_SUCCESS;\r
1441\r
1442 File->FileIdentifierDesc = FileIdentifierDesc;\r
1443\r
1444 //\r
1445 // If the requested file is root directory, then the FE/EFE was already\r
1446 // retrieved in UdfOpenVolume() function, thus no need to find it again.\r
1447 //\r
1448 // Otherwise, find FE/EFE from the respective FID.\r
1449 //\r
1450 if (StrCmp (FileName, L"\\") != 0) {\r
1451 Status = FindFileEntry (\r
1452 BlockIo,\r
1453 DiskIo,\r
1454 Volume,\r
1455 &FileIdentifierDesc->Icb,\r
1456 &CompareFileEntry\r
1457 );\r
1458 if (EFI_ERROR (Status)) {\r
1459 goto Error_Find_Fe;\r
1460 }\r
1461\r
1462 //\r
1463 // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.\r
1464 //\r
1465 if (CompareMem ((VOID *)Parent->FileEntry, (VOID *)CompareFileEntry,\r
1466 Volume->FileEntrySize) != 0) {\r
1467 File->FileEntry = CompareFileEntry;\r
1468 } else {\r
1469 FreePool ((VOID *)FileIdentifierDesc);\r
1470 FreePool ((VOID *)CompareFileEntry);\r
1471 Status = EFI_NOT_FOUND;\r
1472 }\r
1473 }\r
1474 }\r
1475\r
1476 return Status;\r
1477\r
1478Error_Find_Fe:\r
1479 FreePool ((VOID *)FileIdentifierDesc);\r
1480\r
1481 return Status;\r
1482}\r
1483\r
1484/**\r
1485 Read volume information on a medium which contains a valid UDF file system.\r
1486\r
1487 @param[in] BlockIo BlockIo interface.\r
1488 @param[in] DiskIo DiskIo interface.\r
1489 @param[out] Volume UDF volume information structure.\r
1490\r
1491 @retval EFI_SUCCESS Volume information read.\r
1492 @retval EFI_NO_MEDIA The device has no media.\r
1493 @retval EFI_DEVICE_ERROR The device reported an error.\r
1494 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1495 @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.\r
1496\r
1497**/\r
1498EFI_STATUS\r
1499ReadUdfVolumeInformation (\r
1500 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1501 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1502 OUT UDF_VOLUME_INFO *Volume\r
1503 )\r
1504{\r
1505 EFI_STATUS Status;\r
1506\r
baaa3cee
PA
1507 //\r
1508 // Read all necessary UDF volume information and keep it private to the driver\r
1509 //\r
99c9b949
PA
1510 Status = ReadVolumeFileStructure (\r
1511 BlockIo,\r
1512 DiskIo,\r
1513 Volume\r
1514 );\r
1515 if (EFI_ERROR (Status)) {\r
1516 return Status;\r
1517 }\r
1518\r
baaa3cee
PA
1519 //\r
1520 // Find File Set Descriptor\r
1521 //\r
1522 Status = FindFileSetDescriptor (BlockIo, DiskIo, Volume);\r
99c9b949 1523 if (EFI_ERROR (Status)) {\r
baaa3cee 1524 return Status;\r
99c9b949
PA
1525 }\r
1526\r
1527 return Status;\r
1528}\r
1529\r
1530/**\r
1531 Find the root directory on an UDF volume.\r
1532\r
1533 @param[in] BlockIo BlockIo interface.\r
1534 @param[in] DiskIo DiskIo interface.\r
1535 @param[in] Volume UDF volume information structure.\r
1536 @param[out] File Root directory file.\r
1537\r
1538 @retval EFI_SUCCESS Root directory found.\r
1539 @retval EFI_NO_MEDIA The device has no media.\r
1540 @retval EFI_DEVICE_ERROR The device reported an error.\r
1541 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1542 @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of\r
1543 resources.\r
1544\r
1545**/\r
1546EFI_STATUS\r
1547FindRootDirectory (\r
1548 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1549 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1550 IN UDF_VOLUME_INFO *Volume,\r
1551 OUT UDF_FILE_INFO *File\r
1552 )\r
1553{\r
1554 EFI_STATUS Status;\r
1555 UDF_FILE_INFO Parent;\r
1556\r
1557 Status = FindFileEntry (\r
1558 BlockIo,\r
1559 DiskIo,\r
1560 Volume,\r
baaa3cee 1561 &Volume->FileSetDesc.RootDirectoryIcb,\r
99c9b949
PA
1562 &File->FileEntry\r
1563 );\r
1564 if (EFI_ERROR (Status)) {\r
1565 return Status;\r
1566 }\r
1567\r
1568 Parent.FileEntry = File->FileEntry;\r
1569 Parent.FileIdentifierDesc = NULL;\r
1570\r
1571 Status = FindFile (\r
1572 BlockIo,\r
1573 DiskIo,\r
1574 Volume,\r
1575 L"\\",\r
1576 NULL,\r
1577 &Parent,\r
baaa3cee 1578 &Volume->FileSetDesc.RootDirectoryIcb,\r
99c9b949
PA
1579 File\r
1580 );\r
1581 if (EFI_ERROR (Status)) {\r
1582 FreePool (File->FileEntry);\r
1583 }\r
1584\r
1585 return Status;\r
1586}\r
1587\r
1588/**\r
1589 Find either a File Entry or a Extended File Entry from a given ICB.\r
1590\r
1591 @param[in] BlockIo BlockIo interface.\r
1592 @param[in] DiskIo DiskIo interface.\r
1593 @param[in] Volume UDF volume information structure.\r
1594 @param[in] Icb ICB of the FID.\r
1595 @param[out] FileEntry File Entry or Extended File Entry.\r
1596\r
1597 @retval EFI_SUCCESS File Entry or Extended File Entry found.\r
1598 @retval EFI_NO_MEDIA The device has no media.\r
1599 @retval EFI_DEVICE_ERROR The device reported an error.\r
1600 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1601 @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of\r
1602 resources.\r
1603\r
1604**/\r
1605EFI_STATUS\r
1606FindFileEntry (\r
1607 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1608 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1609 IN UDF_VOLUME_INFO *Volume,\r
1610 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,\r
1611 OUT VOID **FileEntry\r
1612 )\r
1613{\r
baaa3cee
PA
1614 EFI_STATUS Status;\r
1615 UINT64 Lsn;\r
1616 UINT32 LogicalBlockSize;\r
1617 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
99c9b949
PA
1618\r
1619 Lsn = GetLongAdLsn (Volume, Icb);\r
baaa3cee 1620 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;\r
99c9b949
PA
1621\r
1622 *FileEntry = AllocateZeroPool (Volume->FileEntrySize);\r
1623 if (*FileEntry == NULL) {\r
1624 return EFI_OUT_OF_RESOURCES;\r
1625 }\r
1626\r
1627 //\r
1628 // Read extent.\r
1629 //\r
1630 Status = DiskIo->ReadDisk (\r
1631 DiskIo,\r
1632 BlockIo->Media->MediaId,\r
1633 MultU64x32 (Lsn, LogicalBlockSize),\r
1634 Volume->FileEntrySize,\r
1635 *FileEntry\r
1636 );\r
1637 if (EFI_ERROR (Status)) {\r
1638 goto Error_Read_Disk_Blk;\r
1639 }\r
1640\r
baaa3cee
PA
1641 DescriptorTag = *FileEntry;\r
1642\r
99c9b949
PA
1643 //\r
1644 // Check if the read extent contains a valid Tag Identifier for the expected\r
1645 // FE/EFE.\r
1646 //\r
baaa3cee
PA
1647 if (DescriptorTag->TagIdentifier != UdfFileEntry &&\r
1648 DescriptorTag->TagIdentifier != UdfExtendedFileEntry) {\r
99c9b949
PA
1649 Status = EFI_VOLUME_CORRUPTED;\r
1650 goto Error_Invalid_Fe;\r
1651 }\r
1652\r
1653 return EFI_SUCCESS;\r
1654\r
1655Error_Invalid_Fe:\r
1656Error_Read_Disk_Blk:\r
1657 FreePool (*FileEntry);\r
1658\r
1659 return Status;\r
1660}\r
1661\r
1662/**\r
1663 Find a file given its absolute path on an UDF volume.\r
1664\r
1665 @param[in] BlockIo BlockIo interface.\r
1666 @param[in] DiskIo DiskIo interface.\r
1667 @param[in] Volume UDF volume information structure.\r
1668 @param[in] FilePath File's absolute path.\r
1669 @param[in] Root Root directory file.\r
1670 @param[in] Parent Parent directory file.\r
077f8c43 1671 @param[in] Icb ICB of Parent.\r
99c9b949
PA
1672 @param[out] File Found file.\r
1673\r
077f8c43 1674 @retval EFI_SUCCESS FilePath was found.\r
99c9b949
PA
1675 @retval EFI_NO_MEDIA The device has no media.\r
1676 @retval EFI_DEVICE_ERROR The device reported an error.\r
1677 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
077f8c43 1678 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of\r
99c9b949
PA
1679 resources.\r
1680\r
1681**/\r
1682EFI_STATUS\r
1683FindFile (\r
1684 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1685 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1686 IN UDF_VOLUME_INFO *Volume,\r
1687 IN CHAR16 *FilePath,\r
1688 IN UDF_FILE_INFO *Root,\r
1689 IN UDF_FILE_INFO *Parent,\r
1690 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,\r
1691 OUT UDF_FILE_INFO *File\r
1692 )\r
1693{\r
1694 EFI_STATUS Status;\r
1695 CHAR16 FileName[UDF_FILENAME_LENGTH];\r
1696 CHAR16 *FileNamePointer;\r
1697 UDF_FILE_INFO PreviousFile;\r
1698 VOID *FileEntry;\r
1699\r
1700 Status = EFI_NOT_FOUND;\r
1701\r
1702 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));\r
1703 while (*FilePath != L'\0') {\r
1704 FileNamePointer = FileName;\r
1705 while (*FilePath != L'\0' && *FilePath != L'\\') {\r
1706 *FileNamePointer++ = *FilePath++;\r
1707 }\r
1708\r
1709 *FileNamePointer = L'\0';\r
1710 if (FileName[0] == L'\0') {\r
1711 //\r
1712 // Open root directory.\r
1713 //\r
1714 if (Root == NULL) {\r
1715 //\r
1716 // There is no file found for the root directory yet. So, find only its\r
1717 // FID by now.\r
1718 //\r
1719 // See UdfOpenVolume() function.\r
1720 //\r
1721 Status = InternalFindFile (BlockIo,\r
1722 DiskIo,\r
1723 Volume,\r
1724 L"\\",\r
1725 &PreviousFile,\r
1726 Icb,\r
1727 File);\r
1728 } else {\r
1729 //\r
1730 // We've already a file pointer (Root) for the root directory. Duplicate\r
1731 // its FE/EFE and FID descriptors.\r
1732 //\r
1733 DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);\r
1734 DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);\r
1735 Status = EFI_SUCCESS;\r
1736 }\r
1737 } else {\r
1738 //\r
1739 // No root directory. Find filename from the current directory.\r
1740 //\r
1741 Status = InternalFindFile (BlockIo,\r
1742 DiskIo,\r
1743 Volume,\r
1744 FileName,\r
1745 &PreviousFile,\r
1746 Icb,\r
1747 File);\r
1748 }\r
1749\r
1750 if (EFI_ERROR (Status)) {\r
1751 return Status;\r
1752 }\r
1753\r
1754 //\r
1755 // If the found file is a symlink, then find its respective FE/EFE and\r
1756 // FID descriptors.\r
1757 //\r
baaa3cee 1758 if (FE_ICB_FILE_TYPE (File->FileEntry) == UdfFileEntrySymlink) {\r
99c9b949
PA
1759 FreePool ((VOID *)File->FileIdentifierDesc);\r
1760\r
1761 FileEntry = File->FileEntry;\r
1762\r
1763 Status = ResolveSymlink (BlockIo,\r
1764 DiskIo,\r
1765 Volume,\r
1766 &PreviousFile,\r
1767 FileEntry,\r
1768 File);\r
1769\r
1770 FreePool (FileEntry);\r
1771\r
1772 if (EFI_ERROR (Status)) {\r
1773 return Status;\r
1774 }\r
1775 }\r
1776\r
1777 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
1778 sizeof (UDF_FILE_INFO)) != 0) {\r
1779 CleanupFileInformation (&PreviousFile);\r
1780 }\r
1781\r
1782 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));\r
1783 if (*FilePath != L'\0' && *FilePath == L'\\') {\r
1784 FilePath++;\r
1785 }\r
1786 }\r
1787\r
1788 return Status;\r
1789}\r
1790\r
1791/**\r
1792 Read a directory entry at a time on an UDF volume.\r
1793\r
1794 @param[in] BlockIo BlockIo interface.\r
1795 @param[in] DiskIo DiskIo interface.\r
1796 @param[in] Volume UDF volume information structure.\r
1797 @param[in] ParentIcb ICB of the parent file.\r
1798 @param[in] FileEntryData FE/EFE of the parent file.\r
077f8c43 1799 @param[in, out] ReadDirInfo Next read directory listing structure\r
99c9b949
PA
1800 information.\r
1801 @param[out] FoundFid File Identifier Descriptor pointer.\r
1802\r
1803 @retval EFI_SUCCESS Directory entry read.\r
1804 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
1805 @retval EFI_NO_MEDIA The device has no media.\r
1806 @retval EFI_DEVICE_ERROR The device reported an error.\r
1807 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1808 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of\r
1809 resources.\r
1810\r
1811**/\r
1812EFI_STATUS\r
1813ReadDirectoryEntry (\r
1814 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1815 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1816 IN UDF_VOLUME_INFO *Volume,\r
1817 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
1818 IN VOID *FileEntryData,\r
1819 IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,\r
1820 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid\r
1821 )\r
1822{\r
1823 EFI_STATUS Status;\r
1824 UDF_READ_FILE_INFO ReadFileInfo;\r
1825 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;\r
1826\r
1827 if (ReadDirInfo->DirectoryData == NULL) {\r
1828 //\r
1829 // The directory's recorded data has not been read yet. So let's cache it\r
1830 // into memory and the next calls won't need to read it again.\r
1831 //\r
880ec683 1832 ReadFileInfo.Flags = ReadFileAllocateAndRead;\r
99c9b949
PA
1833\r
1834 Status = ReadFile (\r
1835 BlockIo,\r
1836 DiskIo,\r
1837 Volume,\r
1838 ParentIcb,\r
1839 FileEntryData,\r
1840 &ReadFileInfo\r
1841 );\r
1842 if (EFI_ERROR (Status)) {\r
1843 return Status;\r
1844 }\r
1845\r
1846 //\r
1847 // Fill in ReadDirInfo structure with the read directory's data information.\r
1848 //\r
1849 ReadDirInfo->DirectoryData = ReadFileInfo.FileData;\r
1850 ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;\r
1851 }\r
1852\r
1853 do {\r
1854 if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {\r
1855 //\r
1856 // There are no longer FIDs for this directory. By returning\r
1857 // EFI_DEVICE_ERROR to the callee will indicate end of directory\r
1858 // listening.\r
1859 //\r
1860 return EFI_DEVICE_ERROR;\r
1861 }\r
1862\r
1863 //\r
1864 // Get FID for this entry.\r
1865 //\r
1866 FileIdentifierDesc = GET_FID_FROM_ADS (ReadDirInfo->DirectoryData,\r
1867 ReadDirInfo->FidOffset);\r
1868 //\r
1869 // Update FidOffset to point to next FID.\r
1870 //\r
1871 ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);\r
baaa3cee 1872 } while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);\r
99c9b949
PA
1873\r
1874 DuplicateFid (FileIdentifierDesc, FoundFid);\r
1875\r
1876 return EFI_SUCCESS;\r
1877}\r
1878\r
1879/**\r
1880 Get a filename (encoded in OSTA-compressed format) from a File Identifier\r
1881 Descriptor on an UDF volume.\r
1882\r
1883 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.\r
1884 @param[out] FileName Decoded filename.\r
1885\r
1886 @retval EFI_SUCCESS Filename decoded and read.\r
1887 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1888**/\r
1889EFI_STATUS\r
1890GetFileNameFromFid (\r
1891 IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,\r
1892 OUT CHAR16 *FileName\r
1893 )\r
1894{\r
1895 UINT8 *OstaCompressed;\r
1896 UINT8 CompressionId;\r
1897 UINT8 Length;\r
1898 UINTN Index;\r
1899\r
1900 OstaCompressed =\r
1901 (UINT8 *)(\r
1902 (UINT8 *)FileIdentifierDesc->Data +\r
1903 FileIdentifierDesc->LengthOfImplementationUse\r
1904 );\r
1905\r
1906 CompressionId = OstaCompressed[0];\r
1907 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
1908 return EFI_VOLUME_CORRUPTED;\r
1909 }\r
1910\r
1911 //\r
1912 // Decode filename.\r
1913 //\r
1914 Length = FileIdentifierDesc->LengthOfFileIdentifier;\r
1915 for (Index = 1; Index < Length; Index++) {\r
1916 if (CompressionId == 16) {\r
1917 *FileName = OstaCompressed[Index++] << 8;\r
1918 } else {\r
1919 *FileName = 0;\r
1920 }\r
1921\r
1922 if (Index < Length) {\r
fedec0a3 1923 *FileName |= (CHAR16)(OstaCompressed[Index]);\r
99c9b949
PA
1924 }\r
1925\r
1926 FileName++;\r
1927 }\r
1928\r
1929 *FileName = L'\0';\r
1930\r
1931 return EFI_SUCCESS;\r
1932}\r
1933\r
1934/**\r
1935 Resolve a symlink file on an UDF volume.\r
1936\r
1937 @param[in] BlockIo BlockIo interface.\r
1938 @param[in] DiskIo DiskIo interface.\r
1939 @param[in] Volume UDF volume information structure.\r
1940 @param[in] Parent Parent file.\r
1941 @param[in] FileEntryData FE/EFE structure pointer.\r
1942 @param[out] File Resolved file.\r
1943\r
1944 @retval EFI_SUCCESS Symlink file resolved.\r
1945 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
1946 @retval EFI_NO_MEDIA The device has no media.\r
1947 @retval EFI_DEVICE_ERROR The device reported an error.\r
1948 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1949 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of\r
1950 resources.\r
1951\r
1952**/\r
1953EFI_STATUS\r
1954ResolveSymlink (\r
1955 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1956 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1957 IN UDF_VOLUME_INFO *Volume,\r
1958 IN UDF_FILE_INFO *Parent,\r
1959 IN VOID *FileEntryData,\r
1960 OUT UDF_FILE_INFO *File\r
1961 )\r
1962{\r
1963 EFI_STATUS Status;\r
1964 UDF_READ_FILE_INFO ReadFileInfo;\r
1965 UINT8 *Data;\r
1966 UINT64 Length;\r
1967 UINT8 *EndData;\r
1968 UDF_PATH_COMPONENT *PathComp;\r
1969 UINT8 PathCompLength;\r
1970 CHAR16 FileName[UDF_FILENAME_LENGTH];\r
32492fee 1971 CHAR16 *Char;\r
99c9b949
PA
1972 UINTN Index;\r
1973 UINT8 CompressionId;\r
1974 UDF_FILE_INFO PreviousFile;\r
1975\r
1976 //\r
1977 // Symlink files on UDF volumes do not contain so much data other than\r
1978 // Path Components which resolves to real filenames, so it's OK to read in\r
1979 // all its data here -- usually the data will be inline with the FE/EFE for\r
1980 // lower filenames.\r
1981 //\r
880ec683 1982 ReadFileInfo.Flags = ReadFileAllocateAndRead;\r
99c9b949
PA
1983\r
1984 Status = ReadFile (\r
1985 BlockIo,\r
1986 DiskIo,\r
1987 Volume,\r
1988 &Parent->FileIdentifierDesc->Icb,\r
1989 FileEntryData,\r
1990 &ReadFileInfo\r
1991 );\r
1992 if (EFI_ERROR (Status)) {\r
1993 return Status;\r
1994 }\r
1995\r
1996 Length = ReadFileInfo.ReadLength;\r
1997\r
1998 Data = (UINT8 *)ReadFileInfo.FileData;\r
1999 EndData = Data + Length;\r
2000\r
2001 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));\r
2002\r
2003 for (;;) {\r
2004 PathComp = (UDF_PATH_COMPONENT *)Data;\r
2005\r
2006 PathCompLength = PathComp->LengthOfComponentIdentifier;\r
2007\r
2008 switch (PathComp->ComponentType) {\r
2009 case 1:\r
2010 //\r
2011 // This Path Component specifies the root directory hierarchy subject to\r
2012 // agreement between the originator and recipient of the medium. Skip it.\r
2013 //\r
2014 // Fall through.\r
2015 //\r
2016 case 2:\r
2017 //\r
2018 // "\\." of the current directory. Read next Path Component.\r
2019 //\r
2020 goto Next_Path_Component;\r
2021 case 3:\r
2022 //\r
2023 // ".." (parent directory). Go to it.\r
2024 //\r
2025 CopyMem ((VOID *)FileName, L"..", 6);\r
2026 break;\r
2027 case 4:\r
2028 //\r
2029 // "." (current file). Duplicate both FE/EFE and FID of this file.\r
2030 //\r
2031 DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);\r
2032 DuplicateFid (PreviousFile.FileIdentifierDesc,\r
2033 &File->FileIdentifierDesc);\r
2034 goto Next_Path_Component;\r
2035 case 5:\r
2036 //\r
2037 // This Path Component identifies an object, either a file or a\r
2038 // directory or an alias.\r
2039 //\r
2040 // Decode it from the compressed data in ComponentIdentifier and find\r
2041 // respective path.\r
2042 //\r
2043 CompressionId = PathComp->ComponentIdentifier[0];\r
2044 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
2045 return EFI_VOLUME_CORRUPTED;\r
2046 }\r
2047\r
32492fee 2048 Char = FileName;\r
99c9b949
PA
2049 for (Index = 1; Index < PathCompLength; Index++) {\r
2050 if (CompressionId == 16) {\r
32492fee 2051 *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +\r
99c9b949
PA
2052 Index) << 8;\r
2053 Index++;\r
2054 } else {\r
32492fee 2055 *Char = 0;\r
99c9b949
PA
2056 }\r
2057\r
2058 if (Index < Length) {\r
32492fee 2059 *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));\r
99c9b949
PA
2060 }\r
2061\r
32492fee 2062 Char++;\r
99c9b949
PA
2063 }\r
2064\r
32492fee 2065 *Char = L'\0';\r
99c9b949
PA
2066 break;\r
2067 }\r
2068\r
2069 //\r
2070 // Find file from the read filename in symlink's file data.\r
2071 //\r
2072 Status = InternalFindFile (\r
2073 BlockIo,\r
2074 DiskIo,\r
2075 Volume,\r
2076 FileName,\r
2077 &PreviousFile,\r
2078 NULL,\r
2079 File\r
2080 );\r
2081 if (EFI_ERROR (Status)) {\r
2082 goto Error_Find_File;\r
2083 }\r
2084\r
2085 Next_Path_Component:\r
2086 Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;\r
2087 if (Data >= EndData) {\r
2088 break;\r
2089 }\r
2090\r
2091 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
2092 sizeof (UDF_FILE_INFO)) != 0) {\r
2093 CleanupFileInformation (&PreviousFile);\r
2094 }\r
2095\r
2096 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));\r
2097 }\r
2098\r
2099 //\r
2100 // Unmap the symlink file.\r
2101 //\r
2102 FreePool (ReadFileInfo.FileData);\r
2103\r
2104 return EFI_SUCCESS;\r
2105\r
2106Error_Find_File:\r
2107 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
2108 sizeof (UDF_FILE_INFO)) != 0) {\r
2109 CleanupFileInformation (&PreviousFile);\r
2110 }\r
2111\r
2112 FreePool (ReadFileInfo.FileData);\r
2113\r
2114 return Status;\r
2115}\r
2116\r
99c9b949
PA
2117/**\r
2118 Clean up in-memory UDF file information.\r
2119\r
2120 @param[in] File File information pointer.\r
2121\r
2122**/\r
2123VOID\r
2124CleanupFileInformation (\r
2125 IN UDF_FILE_INFO *File\r
2126 )\r
2127{\r
2128 if (File->FileEntry != NULL) {\r
2129 FreePool (File->FileEntry);\r
2130 }\r
2131 if (File->FileIdentifierDesc != NULL) {\r
2132 FreePool ((VOID *)File->FileIdentifierDesc);\r
2133 }\r
2134\r
2135 ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));\r
2136}\r
2137\r
2138/**\r
2139 Find a file from its absolute path on an UDF volume.\r
2140\r
2141 @param[in] BlockIo BlockIo interface.\r
2142 @param[in] DiskIo DiskIo interface.\r
2143 @param[in] Volume UDF volume information structure.\r
2144 @param[in] File File information structure.\r
2145 @param[out] Size Size of the file.\r
2146\r
077f8c43 2147 @retval EFI_SUCCESS File size calculated and set in Size.\r
99c9b949
PA
2148 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
2149 @retval EFI_NO_MEDIA The device has no media.\r
2150 @retval EFI_DEVICE_ERROR The device reported an error.\r
2151 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2152 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of\r
2153 resources.\r
2154\r
2155**/\r
2156EFI_STATUS\r
2157GetFileSize (\r
2158 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2159 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2160 IN UDF_VOLUME_INFO *Volume,\r
2161 IN UDF_FILE_INFO *File,\r
2162 OUT UINT64 *Size\r
2163 )\r
2164{\r
2165 EFI_STATUS Status;\r
2166 UDF_READ_FILE_INFO ReadFileInfo;\r
2167\r
880ec683 2168 ReadFileInfo.Flags = ReadFileGetFileSize;\r
99c9b949
PA
2169\r
2170 Status = ReadFile (\r
2171 BlockIo,\r
2172 DiskIo,\r
2173 Volume,\r
2174 &File->FileIdentifierDesc->Icb,\r
2175 File->FileEntry,\r
2176 &ReadFileInfo\r
2177 );\r
2178 if (EFI_ERROR (Status)) {\r
2179 return Status;\r
2180 }\r
2181\r
2182 *Size = ReadFileInfo.ReadLength;\r
2183\r
2184 return EFI_SUCCESS;\r
2185}\r
2186\r
2187/**\r
2188 Set information about a file on an UDF volume.\r
2189\r
2190 @param[in] File File pointer.\r
2191 @param[in] FileSize Size of the file.\r
2192 @param[in] FileName Filename of the file.\r
077f8c43 2193 @param[in, out] BufferSize Size of the returned file infomation.\r
99c9b949
PA
2194 @param[out] Buffer Data of the returned file information.\r
2195\r
2196 @retval EFI_SUCCESS File information set.\r
2197 @retval EFI_NO_MEDIA The device has no media.\r
2198 @retval EFI_DEVICE_ERROR The device reported an error.\r
2199 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2200 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of\r
2201 resources.\r
2202\r
2203**/\r
2204EFI_STATUS\r
2205SetFileInfo (\r
2206 IN UDF_FILE_INFO *File,\r
2207 IN UINT64 FileSize,\r
2208 IN CHAR16 *FileName,\r
2209 IN OUT UINTN *BufferSize,\r
2210 OUT VOID *Buffer\r
2211 )\r
2212{\r
2213 UINTN FileInfoLength;\r
2214 EFI_FILE_INFO *FileInfo;\r
2215 UDF_FILE_ENTRY *FileEntry;\r
2216 UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;\r
baaa3cee 2217 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
99c9b949
PA
2218\r
2219 //\r
2220 // Calculate the needed size for the EFI_FILE_INFO structure.\r
2221 //\r
12b83f56 2222 FileInfoLength = sizeof (EFI_FILE_INFO) + ((FileName != NULL) ?\r
99c9b949
PA
2223 StrSize (FileName) :\r
2224 sizeof (CHAR16));\r
2225 if (*BufferSize < FileInfoLength) {\r
2226 //\r
2227 // The given Buffer has no size enough for EFI_FILE_INFO structure.\r
2228 //\r
2229 *BufferSize = FileInfoLength;\r
2230 return EFI_BUFFER_TOO_SMALL;\r
2231 }\r
2232\r
2233 //\r
2234 // Buffer now contains room enough to store EFI_FILE_INFO structure.\r
2235 // Now, fill it in with all necessary information about the file.\r
2236 //\r
2237 FileInfo = (EFI_FILE_INFO *)Buffer;\r
2238 FileInfo->Size = FileInfoLength;\r
2239 FileInfo->Attribute &= ~EFI_FILE_VALID_ATTR;\r
2240 FileInfo->Attribute |= EFI_FILE_READ_ONLY;\r
2241\r
2242 if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {\r
2243 FileInfo->Attribute |= EFI_FILE_DIRECTORY;\r
2244 } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {\r
2245 FileInfo->Attribute |= EFI_FILE_ARCHIVE;\r
2246 }\r
2247\r
2248 if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {\r
2249 FileInfo->Attribute |= EFI_FILE_HIDDEN;\r
2250 }\r
2251\r
baaa3cee
PA
2252 DescriptorTag = File->FileEntry;\r
2253\r
2254 if (DescriptorTag->TagIdentifier == UdfFileEntry) {\r
99c9b949
PA
2255 FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;\r
2256\r
2257 //\r
2258 // Check if FE has the system attribute set.\r
2259 //\r
2260 if (FileEntry->IcbTag.Flags & (1 << 10)) {\r
2261 FileInfo->Attribute |= EFI_FILE_SYSTEM;\r
2262 }\r
2263\r
2264 FileInfo->FileSize = FileSize;\r
2265 FileInfo->PhysicalSize = FileSize;\r
2266\r
2267 FileInfo->CreateTime.Year = FileEntry->AccessTime.Year;\r
2268 FileInfo->CreateTime.Month = FileEntry->AccessTime.Month;\r
2269 FileInfo->CreateTime.Day = FileEntry->AccessTime.Day;\r
2270 FileInfo->CreateTime.Hour = FileEntry->AccessTime.Hour;\r
2271 FileInfo->CreateTime.Minute = FileEntry->AccessTime.Second;\r
2272 FileInfo->CreateTime.Second = FileEntry->AccessTime.Second;\r
2273 FileInfo->CreateTime.Nanosecond =\r
2274 FileEntry->AccessTime.HundredsOfMicroseconds;\r
2275\r
2276 FileInfo->LastAccessTime.Year =\r
2277 FileEntry->AccessTime.Year;\r
2278 FileInfo->LastAccessTime.Month =\r
2279 FileEntry->AccessTime.Month;\r
2280 FileInfo->LastAccessTime.Day =\r
2281 FileEntry->AccessTime.Day;\r
2282 FileInfo->LastAccessTime.Hour =\r
2283 FileEntry->AccessTime.Hour;\r
2284 FileInfo->LastAccessTime.Minute =\r
2285 FileEntry->AccessTime.Minute;\r
2286 FileInfo->LastAccessTime.Second =\r
2287 FileEntry->AccessTime.Second;\r
2288 FileInfo->LastAccessTime.Nanosecond =\r
2289 FileEntry->AccessTime.HundredsOfMicroseconds;\r
baaa3cee 2290 } else if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {\r
99c9b949
PA
2291 ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;\r
2292\r
2293 //\r
2294 // Check if EFE has the system attribute set.\r
2295 //\r
2296 if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {\r
2297 FileInfo->Attribute |= EFI_FILE_SYSTEM;\r
2298 }\r
2299\r
2300 FileInfo->FileSize = FileSize;\r
2301 FileInfo->PhysicalSize = FileSize;\r
2302\r
2303 FileInfo->CreateTime.Year = ExtendedFileEntry->CreationTime.Year;\r
2304 FileInfo->CreateTime.Month = ExtendedFileEntry->CreationTime.Month;\r
2305 FileInfo->CreateTime.Day = ExtendedFileEntry->CreationTime.Day;\r
2306 FileInfo->CreateTime.Hour = ExtendedFileEntry->CreationTime.Hour;\r
2307 FileInfo->CreateTime.Minute = ExtendedFileEntry->CreationTime.Second;\r
2308 FileInfo->CreateTime.Second = ExtendedFileEntry->CreationTime.Second;\r
2309 FileInfo->CreateTime.Nanosecond =\r
2310 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;\r
2311\r
2312 FileInfo->LastAccessTime.Year =\r
2313 ExtendedFileEntry->AccessTime.Year;\r
2314 FileInfo->LastAccessTime.Month =\r
2315 ExtendedFileEntry->AccessTime.Month;\r
2316 FileInfo->LastAccessTime.Day =\r
2317 ExtendedFileEntry->AccessTime.Day;\r
2318 FileInfo->LastAccessTime.Hour =\r
2319 ExtendedFileEntry->AccessTime.Hour;\r
2320 FileInfo->LastAccessTime.Minute =\r
2321 ExtendedFileEntry->AccessTime.Minute;\r
2322 FileInfo->LastAccessTime.Second =\r
2323 ExtendedFileEntry->AccessTime.Second;\r
2324 FileInfo->LastAccessTime.Nanosecond =\r
2325 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;\r
2326 }\r
2327\r
2328 FileInfo->CreateTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
2329 FileInfo->CreateTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;\r
2330 FileInfo->LastAccessTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
2331 FileInfo->LastAccessTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;\r
2332\r
2333 CopyMem ((VOID *)&FileInfo->ModificationTime,\r
2334 (VOID *)&FileInfo->LastAccessTime,\r
2335 sizeof (EFI_TIME));\r
2336\r
2337 if (FileName != NULL) {\r
2338 StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);\r
2339 } else {\r
2340 FileInfo->FileName[0] = '\0';\r
2341 }\r
2342\r
2343 *BufferSize = FileInfoLength;\r
2344\r
2345 return EFI_SUCCESS;\r
2346}\r
2347\r
2348/**\r
2349 Get volume and free space size information of an UDF volume.\r
2350\r
2351 @param[in] BlockIo BlockIo interface.\r
2352 @param[in] DiskIo DiskIo interface.\r
2353 @param[in] Volume UDF volume information structure.\r
2354 @param[out] VolumeSize Volume size.\r
2355 @param[out] FreeSpaceSize Free space size.\r
2356\r
2357 @retval EFI_SUCCESS Volume and free space size calculated.\r
2358 @retval EFI_NO_MEDIA The device has no media.\r
2359 @retval EFI_DEVICE_ERROR The device reported an error.\r
2360 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2361 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not\r
2362 calculated due to lack of resources.\r
2363\r
2364**/\r
2365EFI_STATUS\r
2366GetVolumeSize (\r
2367 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2368 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2369 IN UDF_VOLUME_INFO *Volume,\r
2370 OUT UINT64 *VolumeSize,\r
2371 OUT UINT64 *FreeSpaceSize\r
2372 )\r
2373{\r
baaa3cee
PA
2374 EFI_STATUS Status;\r
2375 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;\r
2376 UDF_EXTENT_AD *ExtentAd;\r
2377 UINT64 Lsn;\r
2378 UINT32 LogicalBlockSize;\r
2379 UDF_LOGICAL_VOLUME_INTEGRITY *LogicalVolInt;\r
2380 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
2381 UINTN Index;\r
2382 UINTN Length;\r
2383 UINT32 LsnsNo;\r
99c9b949 2384\r
baaa3cee 2385 LogicalVolDesc = &Volume->LogicalVolDesc;\r
99c9b949 2386\r
baaa3cee 2387 ExtentAd = &LogicalVolDesc->IntegritySequenceExtent;\r
99c9b949 2388\r
baaa3cee
PA
2389 if (ExtentAd->ExtentLength == 0) {\r
2390 return EFI_VOLUME_CORRUPTED;\r
2391 }\r
99c9b949 2392\r
baaa3cee
PA
2393 LogicalVolInt = AllocatePool (ExtentAd->ExtentLength);\r
2394 if (LogicalVolInt == NULL) {\r
2395 return EFI_OUT_OF_RESOURCES;\r
2396 }\r
99c9b949 2397\r
baaa3cee
PA
2398 //\r
2399 // Get location of Logical Volume Integrity Descriptor\r
2400 //\r
2401 Lsn = (UINT64)ExtentAd->ExtentLocation - Volume->MainVdsStartLocation;\r
99c9b949 2402\r
baaa3cee 2403 LogicalBlockSize = LogicalVolDesc->LogicalBlockSize;\r
99c9b949 2404\r
baaa3cee
PA
2405 //\r
2406 // Read disk block\r
2407 //\r
2408 Status = DiskIo->ReadDisk (\r
2409 DiskIo,\r
2410 BlockIo->Media->MediaId,\r
2411 MultU64x32 (Lsn, LogicalBlockSize),\r
2412 ExtentAd->ExtentLength,\r
2413 LogicalVolInt\r
2414 );\r
2415 if (EFI_ERROR (Status)) {\r
2416 goto Out_Free;\r
2417 }\r
99c9b949 2418\r
baaa3cee 2419 DescriptorTag = &LogicalVolInt->DescriptorTag;\r
99c9b949 2420\r
baaa3cee
PA
2421 //\r
2422 // Check if read block is a Logical Volume Integrity Descriptor\r
2423 //\r
2424 if (DescriptorTag->TagIdentifier != UdfLogicalVolumeIntegrityDescriptor) {\r
2425 Status = EFI_VOLUME_CORRUPTED;\r
2426 goto Out_Free;\r
2427 }\r
2428\r
2429 *VolumeSize = 0;\r
2430 *FreeSpaceSize = 0;\r
99c9b949 2431\r
baaa3cee
PA
2432 Length = LogicalVolInt->NumberOfPartitions;\r
2433 for (Index = 0; Index < Length; Index += sizeof (UINT32)) {\r
2434 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);\r
2435 //\r
2436 // Check if size is not specified\r
2437 //\r
2438 if (LsnsNo == 0xFFFFFFFFUL) {\r
2439 continue;\r
99c9b949 2440 }\r
baaa3cee
PA
2441 //\r
2442 // Accumulate free space size\r
2443 //\r
2444 *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);\r
2445 }\r
99c9b949 2446\r
baaa3cee
PA
2447 Length = LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2;\r
2448 for (; Index < Length; Index += sizeof (UINT32)) {\r
2449 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);\r
2450 //\r
2451 // Check if size is not specified\r
2452 //\r
2453 if (LsnsNo == 0xFFFFFFFFUL) {\r
2454 continue;\r
2455 }\r
2456 //\r
2457 // Accumulate used volume space\r
2458 //\r
2459 *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);\r
99c9b949
PA
2460 }\r
2461\r
baaa3cee
PA
2462 Status = EFI_SUCCESS;\r
2463\r
2464Out_Free:\r
2465 //\r
2466 // Free Logical Volume Integrity Descriptor\r
2467 //\r
2468 FreePool (LogicalVolInt);\r
2469\r
2470 return Status;\r
99c9b949
PA
2471}\r
2472\r
2473/**\r
2474 Seek a file and read its data into memory on an UDF volume.\r
2475\r
2476 @param[in] BlockIo BlockIo interface.\r
2477 @param[in] DiskIo DiskIo interface.\r
2478 @param[in] Volume UDF volume information structure.\r
2479 @param[in] File File information structure.\r
2480 @param[in] FileSize Size of the file.\r
077f8c43
HW
2481 @param[in, out] FilePosition File position.\r
2482 @param[in, out] Buffer File data.\r
2483 @param[in, out] BufferSize Read size.\r
99c9b949
PA
2484\r
2485 @retval EFI_SUCCESS File seeked and read.\r
2486 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
2487 @retval EFI_NO_MEDIA The device has no media.\r
2488 @retval EFI_DEVICE_ERROR The device reported an error.\r
2489 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2490 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack\r
2491 of resources.\r
2492\r
2493**/\r
2494EFI_STATUS\r
2495ReadFileData (\r
2496 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2497 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2498 IN UDF_VOLUME_INFO *Volume,\r
2499 IN UDF_FILE_INFO *File,\r
2500 IN UINT64 FileSize,\r
2501 IN OUT UINT64 *FilePosition,\r
2502 IN OUT VOID *Buffer,\r
2503 IN OUT UINT64 *BufferSize\r
2504 )\r
2505{\r
2506 EFI_STATUS Status;\r
2507 UDF_READ_FILE_INFO ReadFileInfo;\r
2508\r
880ec683 2509 ReadFileInfo.Flags = ReadFileSeekAndRead;\r
99c9b949
PA
2510 ReadFileInfo.FilePosition = *FilePosition;\r
2511 ReadFileInfo.FileData = Buffer;\r
2512 ReadFileInfo.FileDataSize = *BufferSize;\r
2513 ReadFileInfo.FileSize = FileSize;\r
2514\r
2515 Status = ReadFile (\r
2516 BlockIo,\r
2517 DiskIo,\r
2518 Volume,\r
2519 &File->FileIdentifierDesc->Icb,\r
2520 File->FileEntry,\r
2521 &ReadFileInfo\r
2522 );\r
2523 if (EFI_ERROR (Status)) {\r
2524 return Status;\r
2525 }\r
2526\r
2527 *BufferSize = ReadFileInfo.FileDataSize;\r
2528 *FilePosition = ReadFileInfo.FilePosition;\r
2529\r
2530 return EFI_SUCCESS;\r
2531}\r
2532\r
2533/**\r
2534 Check if ControllerHandle supports an UDF file system.\r
2535\r
2536 @param[in] This Protocol instance pointer.\r
2537 @param[in] ControllerHandle Handle of device to test.\r
2538\r
2539 @retval EFI_SUCCESS UDF file system found.\r
2540 @retval EFI_UNSUPPORTED UDF file system not found.\r
2541\r
2542**/\r
2543EFI_STATUS\r
2544SupportUdfFileSystem (\r
2545 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2546 IN EFI_HANDLE ControllerHandle\r
2547 )\r
2548{\r
2549 EFI_STATUS Status;\r
2550 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2551 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
2552 EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;\r
2553 EFI_GUID *VendorDefinedGuid;\r
99c9b949
PA
2554\r
2555 //\r
2556 // Open Device Path protocol on ControllerHandle\r
2557 //\r
2558 Status = gBS->OpenProtocol (\r
2559 ControllerHandle,\r
2560 &gEfiDevicePathProtocolGuid,\r
2561 (VOID **)&DevicePath,\r
2562 This->DriverBindingHandle,\r
2563 ControllerHandle,\r
2564 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2565 );\r
2566 if (EFI_ERROR (Status)) {\r
2567 return EFI_UNSUPPORTED;\r
2568 }\r
2569\r
2570 Status = EFI_UNSUPPORTED;\r
2571\r
2572 //\r
2573 // Get last Device Path node\r
2574 //\r
2575 LastDevicePathNode = NULL;\r
2576 DevicePathNode = DevicePath;\r
2577 while (!IsDevicePathEnd (DevicePathNode)) {\r
2578 LastDevicePathNode = DevicePathNode;\r
2579 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
2580 }\r
2581 //\r
2582 // Check if last Device Path node contains a Vendor-Defined Media Device Path\r
2583 // of an UDF file system.\r
2584 //\r
2585 if (LastDevicePathNode != NULL &&\r
2586 DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&\r
2587 DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP) {\r
2588 VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +\r
2589 OFFSET_OF (VENDOR_DEVICE_PATH, Guid));\r
3f92b104 2590 if (CompareGuid (VendorDefinedGuid, &gUdfDevPathGuid)) {\r
99c9b949
PA
2591 Status = EFI_SUCCESS;\r
2592 }\r
2593 }\r
2594\r
2595 //\r
2596 // Close Device Path protocol on ControllerHandle\r
2597 //\r
2598 gBS->CloseProtocol (\r
2599 ControllerHandle,\r
2600 &gEfiDevicePathProtocolGuid,\r
2601 This->DriverBindingHandle,\r
2602 ControllerHandle\r
2603 );\r
2604\r
2605 return Status;\r
2606}\r