]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/UdfDxe/FileSystemOperations.c
MdePkg/BaseSynchronizationLib GCC: simplify IA32 InternalSyncCompareExchange64()
[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
7a966348 1618 VOID *ReadBuffer;\r
99c9b949
PA
1619\r
1620 Lsn = GetLongAdLsn (Volume, Icb);\r
baaa3cee 1621 LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;\r
99c9b949 1622\r
7a966348
HW
1623 ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);\r
1624 if (ReadBuffer == NULL) {\r
99c9b949
PA
1625 return EFI_OUT_OF_RESOURCES;\r
1626 }\r
1627\r
1628 //\r
1629 // Read extent.\r
1630 //\r
1631 Status = DiskIo->ReadDisk (\r
1632 DiskIo,\r
1633 BlockIo->Media->MediaId,\r
1634 MultU64x32 (Lsn, LogicalBlockSize),\r
1635 Volume->FileEntrySize,\r
7a966348 1636 ReadBuffer\r
99c9b949
PA
1637 );\r
1638 if (EFI_ERROR (Status)) {\r
1639 goto Error_Read_Disk_Blk;\r
1640 }\r
1641\r
7a966348 1642 DescriptorTag = ReadBuffer;\r
baaa3cee 1643\r
99c9b949
PA
1644 //\r
1645 // Check if the read extent contains a valid Tag Identifier for the expected\r
1646 // FE/EFE.\r
1647 //\r
baaa3cee
PA
1648 if (DescriptorTag->TagIdentifier != UdfFileEntry &&\r
1649 DescriptorTag->TagIdentifier != UdfExtendedFileEntry) {\r
99c9b949
PA
1650 Status = EFI_VOLUME_CORRUPTED;\r
1651 goto Error_Invalid_Fe;\r
1652 }\r
1653\r
7a966348 1654 *FileEntry = ReadBuffer;\r
99c9b949
PA
1655 return EFI_SUCCESS;\r
1656\r
1657Error_Invalid_Fe:\r
1658Error_Read_Disk_Blk:\r
7a966348 1659 FreePool (ReadBuffer);\r
99c9b949
PA
1660\r
1661 return Status;\r
1662}\r
1663\r
1664/**\r
1665 Find a file given its absolute path on an UDF volume.\r
1666\r
1667 @param[in] BlockIo BlockIo interface.\r
1668 @param[in] DiskIo DiskIo interface.\r
1669 @param[in] Volume UDF volume information structure.\r
1670 @param[in] FilePath File's absolute path.\r
1671 @param[in] Root Root directory file.\r
1672 @param[in] Parent Parent directory file.\r
077f8c43 1673 @param[in] Icb ICB of Parent.\r
99c9b949
PA
1674 @param[out] File Found file.\r
1675\r
077f8c43 1676 @retval EFI_SUCCESS FilePath was found.\r
99c9b949
PA
1677 @retval EFI_NO_MEDIA The device has no media.\r
1678 @retval EFI_DEVICE_ERROR The device reported an error.\r
1679 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
077f8c43 1680 @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of\r
99c9b949
PA
1681 resources.\r
1682\r
1683**/\r
1684EFI_STATUS\r
1685FindFile (\r
1686 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1687 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1688 IN UDF_VOLUME_INFO *Volume,\r
1689 IN CHAR16 *FilePath,\r
1690 IN UDF_FILE_INFO *Root,\r
1691 IN UDF_FILE_INFO *Parent,\r
1692 IN UDF_LONG_ALLOCATION_DESCRIPTOR *Icb,\r
1693 OUT UDF_FILE_INFO *File\r
1694 )\r
1695{\r
1696 EFI_STATUS Status;\r
1697 CHAR16 FileName[UDF_FILENAME_LENGTH];\r
1698 CHAR16 *FileNamePointer;\r
1699 UDF_FILE_INFO PreviousFile;\r
1700 VOID *FileEntry;\r
1701\r
1702 Status = EFI_NOT_FOUND;\r
1703\r
1704 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));\r
1705 while (*FilePath != L'\0') {\r
1706 FileNamePointer = FileName;\r
1707 while (*FilePath != L'\0' && *FilePath != L'\\') {\r
1708 *FileNamePointer++ = *FilePath++;\r
1709 }\r
1710\r
1711 *FileNamePointer = L'\0';\r
1712 if (FileName[0] == L'\0') {\r
1713 //\r
1714 // Open root directory.\r
1715 //\r
1716 if (Root == NULL) {\r
1717 //\r
1718 // There is no file found for the root directory yet. So, find only its\r
1719 // FID by now.\r
1720 //\r
1721 // See UdfOpenVolume() function.\r
1722 //\r
1723 Status = InternalFindFile (BlockIo,\r
1724 DiskIo,\r
1725 Volume,\r
1726 L"\\",\r
1727 &PreviousFile,\r
1728 Icb,\r
1729 File);\r
1730 } else {\r
1731 //\r
1732 // We've already a file pointer (Root) for the root directory. Duplicate\r
1733 // its FE/EFE and FID descriptors.\r
1734 //\r
1735 DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);\r
1736 DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);\r
1737 Status = EFI_SUCCESS;\r
1738 }\r
1739 } else {\r
1740 //\r
1741 // No root directory. Find filename from the current directory.\r
1742 //\r
1743 Status = InternalFindFile (BlockIo,\r
1744 DiskIo,\r
1745 Volume,\r
1746 FileName,\r
1747 &PreviousFile,\r
1748 Icb,\r
1749 File);\r
1750 }\r
1751\r
1752 if (EFI_ERROR (Status)) {\r
1753 return Status;\r
1754 }\r
1755\r
1756 //\r
1757 // If the found file is a symlink, then find its respective FE/EFE and\r
1758 // FID descriptors.\r
1759 //\r
baaa3cee 1760 if (FE_ICB_FILE_TYPE (File->FileEntry) == UdfFileEntrySymlink) {\r
99c9b949
PA
1761 FreePool ((VOID *)File->FileIdentifierDesc);\r
1762\r
1763 FileEntry = File->FileEntry;\r
1764\r
1765 Status = ResolveSymlink (BlockIo,\r
1766 DiskIo,\r
1767 Volume,\r
1768 &PreviousFile,\r
1769 FileEntry,\r
1770 File);\r
1771\r
1772 FreePool (FileEntry);\r
1773\r
1774 if (EFI_ERROR (Status)) {\r
1775 return Status;\r
1776 }\r
1777 }\r
1778\r
1779 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
1780 sizeof (UDF_FILE_INFO)) != 0) {\r
1781 CleanupFileInformation (&PreviousFile);\r
1782 }\r
1783\r
1784 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));\r
1785 if (*FilePath != L'\0' && *FilePath == L'\\') {\r
1786 FilePath++;\r
1787 }\r
1788 }\r
1789\r
1790 return Status;\r
1791}\r
1792\r
1793/**\r
1794 Read a directory entry at a time on an UDF volume.\r
1795\r
1796 @param[in] BlockIo BlockIo interface.\r
1797 @param[in] DiskIo DiskIo interface.\r
1798 @param[in] Volume UDF volume information structure.\r
1799 @param[in] ParentIcb ICB of the parent file.\r
1800 @param[in] FileEntryData FE/EFE of the parent file.\r
077f8c43 1801 @param[in, out] ReadDirInfo Next read directory listing structure\r
99c9b949
PA
1802 information.\r
1803 @param[out] FoundFid File Identifier Descriptor pointer.\r
1804\r
1805 @retval EFI_SUCCESS Directory entry read.\r
1806 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
1807 @retval EFI_NO_MEDIA The device has no media.\r
1808 @retval EFI_DEVICE_ERROR The device reported an error.\r
1809 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1810 @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of\r
1811 resources.\r
1812\r
1813**/\r
1814EFI_STATUS\r
1815ReadDirectoryEntry (\r
1816 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1817 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1818 IN UDF_VOLUME_INFO *Volume,\r
1819 IN UDF_LONG_ALLOCATION_DESCRIPTOR *ParentIcb,\r
1820 IN VOID *FileEntryData,\r
1821 IN OUT UDF_READ_DIRECTORY_INFO *ReadDirInfo,\r
1822 OUT UDF_FILE_IDENTIFIER_DESCRIPTOR **FoundFid\r
1823 )\r
1824{\r
1825 EFI_STATUS Status;\r
1826 UDF_READ_FILE_INFO ReadFileInfo;\r
1827 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;\r
1828\r
1829 if (ReadDirInfo->DirectoryData == NULL) {\r
1830 //\r
1831 // The directory's recorded data has not been read yet. So let's cache it\r
1832 // into memory and the next calls won't need to read it again.\r
1833 //\r
880ec683 1834 ReadFileInfo.Flags = ReadFileAllocateAndRead;\r
99c9b949
PA
1835\r
1836 Status = ReadFile (\r
1837 BlockIo,\r
1838 DiskIo,\r
1839 Volume,\r
1840 ParentIcb,\r
1841 FileEntryData,\r
1842 &ReadFileInfo\r
1843 );\r
1844 if (EFI_ERROR (Status)) {\r
1845 return Status;\r
1846 }\r
1847\r
1848 //\r
1849 // Fill in ReadDirInfo structure with the read directory's data information.\r
1850 //\r
1851 ReadDirInfo->DirectoryData = ReadFileInfo.FileData;\r
1852 ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;\r
1853 }\r
1854\r
1855 do {\r
1856 if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {\r
1857 //\r
1858 // There are no longer FIDs for this directory. By returning\r
1859 // EFI_DEVICE_ERROR to the callee will indicate end of directory\r
1860 // listening.\r
1861 //\r
1862 return EFI_DEVICE_ERROR;\r
1863 }\r
1864\r
1865 //\r
1866 // Get FID for this entry.\r
1867 //\r
1868 FileIdentifierDesc = GET_FID_FROM_ADS (ReadDirInfo->DirectoryData,\r
1869 ReadDirInfo->FidOffset);\r
1870 //\r
1871 // Update FidOffset to point to next FID.\r
1872 //\r
1873 ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);\r
baaa3cee 1874 } while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);\r
99c9b949
PA
1875\r
1876 DuplicateFid (FileIdentifierDesc, FoundFid);\r
1877\r
1878 return EFI_SUCCESS;\r
1879}\r
1880\r
1881/**\r
1882 Get a filename (encoded in OSTA-compressed format) from a File Identifier\r
1883 Descriptor on an UDF volume.\r
1884\r
1885 @param[in] FileIdentifierDesc File Identifier Descriptor pointer.\r
1886 @param[out] FileName Decoded filename.\r
1887\r
1888 @retval EFI_SUCCESS Filename decoded and read.\r
1889 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1890**/\r
1891EFI_STATUS\r
1892GetFileNameFromFid (\r
1893 IN UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc,\r
1894 OUT CHAR16 *FileName\r
1895 )\r
1896{\r
1897 UINT8 *OstaCompressed;\r
1898 UINT8 CompressionId;\r
1899 UINT8 Length;\r
1900 UINTN Index;\r
1901\r
1902 OstaCompressed =\r
1903 (UINT8 *)(\r
1904 (UINT8 *)FileIdentifierDesc->Data +\r
1905 FileIdentifierDesc->LengthOfImplementationUse\r
1906 );\r
1907\r
1908 CompressionId = OstaCompressed[0];\r
1909 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
1910 return EFI_VOLUME_CORRUPTED;\r
1911 }\r
1912\r
1913 //\r
1914 // Decode filename.\r
1915 //\r
1916 Length = FileIdentifierDesc->LengthOfFileIdentifier;\r
1917 for (Index = 1; Index < Length; Index++) {\r
1918 if (CompressionId == 16) {\r
1919 *FileName = OstaCompressed[Index++] << 8;\r
1920 } else {\r
1921 *FileName = 0;\r
1922 }\r
1923\r
1924 if (Index < Length) {\r
fedec0a3 1925 *FileName |= (CHAR16)(OstaCompressed[Index]);\r
99c9b949
PA
1926 }\r
1927\r
1928 FileName++;\r
1929 }\r
1930\r
1931 *FileName = L'\0';\r
1932\r
1933 return EFI_SUCCESS;\r
1934}\r
1935\r
1936/**\r
1937 Resolve a symlink file on an UDF volume.\r
1938\r
1939 @param[in] BlockIo BlockIo interface.\r
1940 @param[in] DiskIo DiskIo interface.\r
1941 @param[in] Volume UDF volume information structure.\r
1942 @param[in] Parent Parent file.\r
1943 @param[in] FileEntryData FE/EFE structure pointer.\r
1944 @param[out] File Resolved file.\r
1945\r
1946 @retval EFI_SUCCESS Symlink file resolved.\r
1947 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
1948 @retval EFI_NO_MEDIA The device has no media.\r
1949 @retval EFI_DEVICE_ERROR The device reported an error.\r
1950 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1951 @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of\r
1952 resources.\r
1953\r
1954**/\r
1955EFI_STATUS\r
1956ResolveSymlink (\r
1957 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
1958 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
1959 IN UDF_VOLUME_INFO *Volume,\r
1960 IN UDF_FILE_INFO *Parent,\r
1961 IN VOID *FileEntryData,\r
1962 OUT UDF_FILE_INFO *File\r
1963 )\r
1964{\r
1965 EFI_STATUS Status;\r
1966 UDF_READ_FILE_INFO ReadFileInfo;\r
1967 UINT8 *Data;\r
1968 UINT64 Length;\r
1969 UINT8 *EndData;\r
1970 UDF_PATH_COMPONENT *PathComp;\r
1971 UINT8 PathCompLength;\r
1972 CHAR16 FileName[UDF_FILENAME_LENGTH];\r
32492fee 1973 CHAR16 *Char;\r
99c9b949
PA
1974 UINTN Index;\r
1975 UINT8 CompressionId;\r
1976 UDF_FILE_INFO PreviousFile;\r
1977\r
1978 //\r
1979 // Symlink files on UDF volumes do not contain so much data other than\r
1980 // Path Components which resolves to real filenames, so it's OK to read in\r
1981 // all its data here -- usually the data will be inline with the FE/EFE for\r
1982 // lower filenames.\r
1983 //\r
880ec683 1984 ReadFileInfo.Flags = ReadFileAllocateAndRead;\r
99c9b949
PA
1985\r
1986 Status = ReadFile (\r
1987 BlockIo,\r
1988 DiskIo,\r
1989 Volume,\r
1990 &Parent->FileIdentifierDesc->Icb,\r
1991 FileEntryData,\r
1992 &ReadFileInfo\r
1993 );\r
1994 if (EFI_ERROR (Status)) {\r
1995 return Status;\r
1996 }\r
1997\r
1998 Length = ReadFileInfo.ReadLength;\r
1999\r
2000 Data = (UINT8 *)ReadFileInfo.FileData;\r
2001 EndData = Data + Length;\r
2002\r
2003 CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));\r
2004\r
2005 for (;;) {\r
2006 PathComp = (UDF_PATH_COMPONENT *)Data;\r
2007\r
2008 PathCompLength = PathComp->LengthOfComponentIdentifier;\r
2009\r
2010 switch (PathComp->ComponentType) {\r
2011 case 1:\r
2012 //\r
2013 // This Path Component specifies the root directory hierarchy subject to\r
2014 // agreement between the originator and recipient of the medium. Skip it.\r
2015 //\r
2016 // Fall through.\r
2017 //\r
2018 case 2:\r
2019 //\r
2020 // "\\." of the current directory. Read next Path Component.\r
2021 //\r
2022 goto Next_Path_Component;\r
2023 case 3:\r
2024 //\r
2025 // ".." (parent directory). Go to it.\r
2026 //\r
2027 CopyMem ((VOID *)FileName, L"..", 6);\r
2028 break;\r
2029 case 4:\r
2030 //\r
2031 // "." (current file). Duplicate both FE/EFE and FID of this file.\r
2032 //\r
2033 DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);\r
2034 DuplicateFid (PreviousFile.FileIdentifierDesc,\r
2035 &File->FileIdentifierDesc);\r
2036 goto Next_Path_Component;\r
2037 case 5:\r
2038 //\r
2039 // This Path Component identifies an object, either a file or a\r
2040 // directory or an alias.\r
2041 //\r
2042 // Decode it from the compressed data in ComponentIdentifier and find\r
2043 // respective path.\r
2044 //\r
2045 CompressionId = PathComp->ComponentIdentifier[0];\r
2046 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
2047 return EFI_VOLUME_CORRUPTED;\r
2048 }\r
2049\r
32492fee 2050 Char = FileName;\r
99c9b949
PA
2051 for (Index = 1; Index < PathCompLength; Index++) {\r
2052 if (CompressionId == 16) {\r
32492fee 2053 *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +\r
99c9b949
PA
2054 Index) << 8;\r
2055 Index++;\r
2056 } else {\r
32492fee 2057 *Char = 0;\r
99c9b949
PA
2058 }\r
2059\r
2060 if (Index < Length) {\r
32492fee 2061 *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));\r
99c9b949
PA
2062 }\r
2063\r
32492fee 2064 Char++;\r
99c9b949
PA
2065 }\r
2066\r
32492fee 2067 *Char = L'\0';\r
99c9b949
PA
2068 break;\r
2069 }\r
2070\r
2071 //\r
2072 // Find file from the read filename in symlink's file data.\r
2073 //\r
2074 Status = InternalFindFile (\r
2075 BlockIo,\r
2076 DiskIo,\r
2077 Volume,\r
2078 FileName,\r
2079 &PreviousFile,\r
2080 NULL,\r
2081 File\r
2082 );\r
2083 if (EFI_ERROR (Status)) {\r
2084 goto Error_Find_File;\r
2085 }\r
2086\r
2087 Next_Path_Component:\r
2088 Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;\r
2089 if (Data >= EndData) {\r
2090 break;\r
2091 }\r
2092\r
2093 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
2094 sizeof (UDF_FILE_INFO)) != 0) {\r
2095 CleanupFileInformation (&PreviousFile);\r
2096 }\r
2097\r
2098 CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));\r
2099 }\r
2100\r
2101 //\r
2102 // Unmap the symlink file.\r
2103 //\r
2104 FreePool (ReadFileInfo.FileData);\r
2105\r
2106 return EFI_SUCCESS;\r
2107\r
2108Error_Find_File:\r
2109 if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,\r
2110 sizeof (UDF_FILE_INFO)) != 0) {\r
2111 CleanupFileInformation (&PreviousFile);\r
2112 }\r
2113\r
2114 FreePool (ReadFileInfo.FileData);\r
2115\r
2116 return Status;\r
2117}\r
2118\r
99c9b949
PA
2119/**\r
2120 Clean up in-memory UDF file information.\r
2121\r
2122 @param[in] File File information pointer.\r
2123\r
2124**/\r
2125VOID\r
2126CleanupFileInformation (\r
2127 IN UDF_FILE_INFO *File\r
2128 )\r
2129{\r
2130 if (File->FileEntry != NULL) {\r
2131 FreePool (File->FileEntry);\r
2132 }\r
2133 if (File->FileIdentifierDesc != NULL) {\r
2134 FreePool ((VOID *)File->FileIdentifierDesc);\r
2135 }\r
2136\r
2137 ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));\r
2138}\r
2139\r
2140/**\r
2141 Find a file from its absolute path on an UDF volume.\r
2142\r
2143 @param[in] BlockIo BlockIo interface.\r
2144 @param[in] DiskIo DiskIo interface.\r
2145 @param[in] Volume UDF volume information structure.\r
2146 @param[in] File File information structure.\r
2147 @param[out] Size Size of the file.\r
2148\r
077f8c43 2149 @retval EFI_SUCCESS File size calculated and set in Size.\r
99c9b949
PA
2150 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
2151 @retval EFI_NO_MEDIA The device has no media.\r
2152 @retval EFI_DEVICE_ERROR The device reported an error.\r
2153 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2154 @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of\r
2155 resources.\r
2156\r
2157**/\r
2158EFI_STATUS\r
2159GetFileSize (\r
2160 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2161 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2162 IN UDF_VOLUME_INFO *Volume,\r
2163 IN UDF_FILE_INFO *File,\r
2164 OUT UINT64 *Size\r
2165 )\r
2166{\r
2167 EFI_STATUS Status;\r
2168 UDF_READ_FILE_INFO ReadFileInfo;\r
2169\r
880ec683 2170 ReadFileInfo.Flags = ReadFileGetFileSize;\r
99c9b949
PA
2171\r
2172 Status = ReadFile (\r
2173 BlockIo,\r
2174 DiskIo,\r
2175 Volume,\r
2176 &File->FileIdentifierDesc->Icb,\r
2177 File->FileEntry,\r
2178 &ReadFileInfo\r
2179 );\r
2180 if (EFI_ERROR (Status)) {\r
2181 return Status;\r
2182 }\r
2183\r
2184 *Size = ReadFileInfo.ReadLength;\r
2185\r
2186 return EFI_SUCCESS;\r
2187}\r
2188\r
2189/**\r
2190 Set information about a file on an UDF volume.\r
2191\r
2192 @param[in] File File pointer.\r
2193 @param[in] FileSize Size of the file.\r
2194 @param[in] FileName Filename of the file.\r
077f8c43 2195 @param[in, out] BufferSize Size of the returned file infomation.\r
99c9b949
PA
2196 @param[out] Buffer Data of the returned file information.\r
2197\r
2198 @retval EFI_SUCCESS File information set.\r
2199 @retval EFI_NO_MEDIA The device has no media.\r
2200 @retval EFI_DEVICE_ERROR The device reported an error.\r
2201 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2202 @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of\r
2203 resources.\r
2204\r
2205**/\r
2206EFI_STATUS\r
2207SetFileInfo (\r
2208 IN UDF_FILE_INFO *File,\r
2209 IN UINT64 FileSize,\r
2210 IN CHAR16 *FileName,\r
2211 IN OUT UINTN *BufferSize,\r
2212 OUT VOID *Buffer\r
2213 )\r
2214{\r
2215 UINTN FileInfoLength;\r
2216 EFI_FILE_INFO *FileInfo;\r
2217 UDF_FILE_ENTRY *FileEntry;\r
2218 UDF_EXTENDED_FILE_ENTRY *ExtendedFileEntry;\r
baaa3cee 2219 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
99c9b949
PA
2220\r
2221 //\r
2222 // Calculate the needed size for the EFI_FILE_INFO structure.\r
2223 //\r
12b83f56 2224 FileInfoLength = sizeof (EFI_FILE_INFO) + ((FileName != NULL) ?\r
99c9b949
PA
2225 StrSize (FileName) :\r
2226 sizeof (CHAR16));\r
2227 if (*BufferSize < FileInfoLength) {\r
2228 //\r
2229 // The given Buffer has no size enough for EFI_FILE_INFO structure.\r
2230 //\r
2231 *BufferSize = FileInfoLength;\r
2232 return EFI_BUFFER_TOO_SMALL;\r
2233 }\r
2234\r
2235 //\r
2236 // Buffer now contains room enough to store EFI_FILE_INFO structure.\r
2237 // Now, fill it in with all necessary information about the file.\r
2238 //\r
2239 FileInfo = (EFI_FILE_INFO *)Buffer;\r
2240 FileInfo->Size = FileInfoLength;\r
2241 FileInfo->Attribute &= ~EFI_FILE_VALID_ATTR;\r
2242 FileInfo->Attribute |= EFI_FILE_READ_ONLY;\r
2243\r
2244 if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {\r
2245 FileInfo->Attribute |= EFI_FILE_DIRECTORY;\r
2246 } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {\r
2247 FileInfo->Attribute |= EFI_FILE_ARCHIVE;\r
2248 }\r
2249\r
2250 if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {\r
2251 FileInfo->Attribute |= EFI_FILE_HIDDEN;\r
2252 }\r
2253\r
baaa3cee
PA
2254 DescriptorTag = File->FileEntry;\r
2255\r
2256 if (DescriptorTag->TagIdentifier == UdfFileEntry) {\r
99c9b949
PA
2257 FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;\r
2258\r
2259 //\r
2260 // Check if FE has the system attribute set.\r
2261 //\r
2262 if (FileEntry->IcbTag.Flags & (1 << 10)) {\r
2263 FileInfo->Attribute |= EFI_FILE_SYSTEM;\r
2264 }\r
2265\r
2266 FileInfo->FileSize = FileSize;\r
2267 FileInfo->PhysicalSize = FileSize;\r
2268\r
2269 FileInfo->CreateTime.Year = FileEntry->AccessTime.Year;\r
2270 FileInfo->CreateTime.Month = FileEntry->AccessTime.Month;\r
2271 FileInfo->CreateTime.Day = FileEntry->AccessTime.Day;\r
2272 FileInfo->CreateTime.Hour = FileEntry->AccessTime.Hour;\r
2273 FileInfo->CreateTime.Minute = FileEntry->AccessTime.Second;\r
2274 FileInfo->CreateTime.Second = FileEntry->AccessTime.Second;\r
2275 FileInfo->CreateTime.Nanosecond =\r
2276 FileEntry->AccessTime.HundredsOfMicroseconds;\r
2277\r
2278 FileInfo->LastAccessTime.Year =\r
2279 FileEntry->AccessTime.Year;\r
2280 FileInfo->LastAccessTime.Month =\r
2281 FileEntry->AccessTime.Month;\r
2282 FileInfo->LastAccessTime.Day =\r
2283 FileEntry->AccessTime.Day;\r
2284 FileInfo->LastAccessTime.Hour =\r
2285 FileEntry->AccessTime.Hour;\r
2286 FileInfo->LastAccessTime.Minute =\r
2287 FileEntry->AccessTime.Minute;\r
2288 FileInfo->LastAccessTime.Second =\r
2289 FileEntry->AccessTime.Second;\r
2290 FileInfo->LastAccessTime.Nanosecond =\r
2291 FileEntry->AccessTime.HundredsOfMicroseconds;\r
baaa3cee 2292 } else if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {\r
99c9b949
PA
2293 ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;\r
2294\r
2295 //\r
2296 // Check if EFE has the system attribute set.\r
2297 //\r
2298 if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {\r
2299 FileInfo->Attribute |= EFI_FILE_SYSTEM;\r
2300 }\r
2301\r
2302 FileInfo->FileSize = FileSize;\r
2303 FileInfo->PhysicalSize = FileSize;\r
2304\r
2305 FileInfo->CreateTime.Year = ExtendedFileEntry->CreationTime.Year;\r
2306 FileInfo->CreateTime.Month = ExtendedFileEntry->CreationTime.Month;\r
2307 FileInfo->CreateTime.Day = ExtendedFileEntry->CreationTime.Day;\r
2308 FileInfo->CreateTime.Hour = ExtendedFileEntry->CreationTime.Hour;\r
2309 FileInfo->CreateTime.Minute = ExtendedFileEntry->CreationTime.Second;\r
2310 FileInfo->CreateTime.Second = ExtendedFileEntry->CreationTime.Second;\r
2311 FileInfo->CreateTime.Nanosecond =\r
2312 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;\r
2313\r
2314 FileInfo->LastAccessTime.Year =\r
2315 ExtendedFileEntry->AccessTime.Year;\r
2316 FileInfo->LastAccessTime.Month =\r
2317 ExtendedFileEntry->AccessTime.Month;\r
2318 FileInfo->LastAccessTime.Day =\r
2319 ExtendedFileEntry->AccessTime.Day;\r
2320 FileInfo->LastAccessTime.Hour =\r
2321 ExtendedFileEntry->AccessTime.Hour;\r
2322 FileInfo->LastAccessTime.Minute =\r
2323 ExtendedFileEntry->AccessTime.Minute;\r
2324 FileInfo->LastAccessTime.Second =\r
2325 ExtendedFileEntry->AccessTime.Second;\r
2326 FileInfo->LastAccessTime.Nanosecond =\r
2327 ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;\r
2328 }\r
2329\r
2330 FileInfo->CreateTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
2331 FileInfo->CreateTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;\r
2332 FileInfo->LastAccessTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
2333 FileInfo->LastAccessTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;\r
2334\r
2335 CopyMem ((VOID *)&FileInfo->ModificationTime,\r
2336 (VOID *)&FileInfo->LastAccessTime,\r
2337 sizeof (EFI_TIME));\r
2338\r
2339 if (FileName != NULL) {\r
2340 StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);\r
2341 } else {\r
2342 FileInfo->FileName[0] = '\0';\r
2343 }\r
2344\r
2345 *BufferSize = FileInfoLength;\r
2346\r
2347 return EFI_SUCCESS;\r
2348}\r
2349\r
2350/**\r
2351 Get volume and free space size information of an UDF volume.\r
2352\r
2353 @param[in] BlockIo BlockIo interface.\r
2354 @param[in] DiskIo DiskIo interface.\r
2355 @param[in] Volume UDF volume information structure.\r
2356 @param[out] VolumeSize Volume size.\r
2357 @param[out] FreeSpaceSize Free space size.\r
2358\r
2359 @retval EFI_SUCCESS Volume and free space size calculated.\r
2360 @retval EFI_NO_MEDIA The device has no media.\r
2361 @retval EFI_DEVICE_ERROR The device reported an error.\r
2362 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2363 @retval EFI_OUT_OF_RESOURCES The volume and free space size were not\r
2364 calculated due to lack of resources.\r
2365\r
2366**/\r
2367EFI_STATUS\r
2368GetVolumeSize (\r
2369 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2370 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2371 IN UDF_VOLUME_INFO *Volume,\r
2372 OUT UINT64 *VolumeSize,\r
2373 OUT UINT64 *FreeSpaceSize\r
2374 )\r
2375{\r
baaa3cee
PA
2376 EFI_STATUS Status;\r
2377 UDF_LOGICAL_VOLUME_DESCRIPTOR *LogicalVolDesc;\r
2378 UDF_EXTENT_AD *ExtentAd;\r
2379 UINT64 Lsn;\r
2380 UINT32 LogicalBlockSize;\r
2381 UDF_LOGICAL_VOLUME_INTEGRITY *LogicalVolInt;\r
2382 UDF_DESCRIPTOR_TAG *DescriptorTag;\r
2383 UINTN Index;\r
2384 UINTN Length;\r
2385 UINT32 LsnsNo;\r
99c9b949 2386\r
baaa3cee 2387 LogicalVolDesc = &Volume->LogicalVolDesc;\r
99c9b949 2388\r
baaa3cee 2389 ExtentAd = &LogicalVolDesc->IntegritySequenceExtent;\r
99c9b949 2390\r
baaa3cee
PA
2391 if (ExtentAd->ExtentLength == 0) {\r
2392 return EFI_VOLUME_CORRUPTED;\r
2393 }\r
99c9b949 2394\r
baaa3cee
PA
2395 LogicalVolInt = AllocatePool (ExtentAd->ExtentLength);\r
2396 if (LogicalVolInt == NULL) {\r
2397 return EFI_OUT_OF_RESOURCES;\r
2398 }\r
99c9b949 2399\r
baaa3cee
PA
2400 //\r
2401 // Get location of Logical Volume Integrity Descriptor\r
2402 //\r
2403 Lsn = (UINT64)ExtentAd->ExtentLocation - Volume->MainVdsStartLocation;\r
99c9b949 2404\r
baaa3cee 2405 LogicalBlockSize = LogicalVolDesc->LogicalBlockSize;\r
99c9b949 2406\r
baaa3cee
PA
2407 //\r
2408 // Read disk block\r
2409 //\r
2410 Status = DiskIo->ReadDisk (\r
2411 DiskIo,\r
2412 BlockIo->Media->MediaId,\r
2413 MultU64x32 (Lsn, LogicalBlockSize),\r
2414 ExtentAd->ExtentLength,\r
2415 LogicalVolInt\r
2416 );\r
2417 if (EFI_ERROR (Status)) {\r
2418 goto Out_Free;\r
2419 }\r
99c9b949 2420\r
baaa3cee 2421 DescriptorTag = &LogicalVolInt->DescriptorTag;\r
99c9b949 2422\r
baaa3cee
PA
2423 //\r
2424 // Check if read block is a Logical Volume Integrity Descriptor\r
2425 //\r
2426 if (DescriptorTag->TagIdentifier != UdfLogicalVolumeIntegrityDescriptor) {\r
2427 Status = EFI_VOLUME_CORRUPTED;\r
2428 goto Out_Free;\r
2429 }\r
2430\r
2431 *VolumeSize = 0;\r
2432 *FreeSpaceSize = 0;\r
99c9b949 2433\r
baaa3cee
PA
2434 Length = LogicalVolInt->NumberOfPartitions;\r
2435 for (Index = 0; Index < Length; Index += sizeof (UINT32)) {\r
2436 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);\r
2437 //\r
2438 // Check if size is not specified\r
2439 //\r
2440 if (LsnsNo == 0xFFFFFFFFUL) {\r
2441 continue;\r
99c9b949 2442 }\r
baaa3cee
PA
2443 //\r
2444 // Accumulate free space size\r
2445 //\r
2446 *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);\r
2447 }\r
99c9b949 2448\r
baaa3cee
PA
2449 Length = LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2;\r
2450 for (; Index < Length; Index += sizeof (UINT32)) {\r
2451 LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);\r
2452 //\r
2453 // Check if size is not specified\r
2454 //\r
2455 if (LsnsNo == 0xFFFFFFFFUL) {\r
2456 continue;\r
2457 }\r
2458 //\r
2459 // Accumulate used volume space\r
2460 //\r
2461 *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);\r
99c9b949
PA
2462 }\r
2463\r
baaa3cee
PA
2464 Status = EFI_SUCCESS;\r
2465\r
2466Out_Free:\r
2467 //\r
2468 // Free Logical Volume Integrity Descriptor\r
2469 //\r
2470 FreePool (LogicalVolInt);\r
2471\r
2472 return Status;\r
99c9b949
PA
2473}\r
2474\r
2475/**\r
2476 Seek a file and read its data into memory on an UDF volume.\r
2477\r
2478 @param[in] BlockIo BlockIo interface.\r
2479 @param[in] DiskIo DiskIo interface.\r
2480 @param[in] Volume UDF volume information structure.\r
2481 @param[in] File File information structure.\r
2482 @param[in] FileSize Size of the file.\r
077f8c43
HW
2483 @param[in, out] FilePosition File position.\r
2484 @param[in, out] Buffer File data.\r
2485 @param[in, out] BufferSize Read size.\r
99c9b949
PA
2486\r
2487 @retval EFI_SUCCESS File seeked and read.\r
2488 @retval EFI_UNSUPPORTED Extended Allocation Descriptors not supported.\r
2489 @retval EFI_NO_MEDIA The device has no media.\r
2490 @retval EFI_DEVICE_ERROR The device reported an error.\r
2491 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
2492 @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack\r
2493 of resources.\r
2494\r
2495**/\r
2496EFI_STATUS\r
2497ReadFileData (\r
2498 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,\r
2499 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
2500 IN UDF_VOLUME_INFO *Volume,\r
2501 IN UDF_FILE_INFO *File,\r
2502 IN UINT64 FileSize,\r
2503 IN OUT UINT64 *FilePosition,\r
2504 IN OUT VOID *Buffer,\r
2505 IN OUT UINT64 *BufferSize\r
2506 )\r
2507{\r
2508 EFI_STATUS Status;\r
2509 UDF_READ_FILE_INFO ReadFileInfo;\r
2510\r
880ec683 2511 ReadFileInfo.Flags = ReadFileSeekAndRead;\r
99c9b949
PA
2512 ReadFileInfo.FilePosition = *FilePosition;\r
2513 ReadFileInfo.FileData = Buffer;\r
2514 ReadFileInfo.FileDataSize = *BufferSize;\r
2515 ReadFileInfo.FileSize = FileSize;\r
2516\r
2517 Status = ReadFile (\r
2518 BlockIo,\r
2519 DiskIo,\r
2520 Volume,\r
2521 &File->FileIdentifierDesc->Icb,\r
2522 File->FileEntry,\r
2523 &ReadFileInfo\r
2524 );\r
2525 if (EFI_ERROR (Status)) {\r
2526 return Status;\r
2527 }\r
2528\r
2529 *BufferSize = ReadFileInfo.FileDataSize;\r
2530 *FilePosition = ReadFileInfo.FilePosition;\r
2531\r
2532 return EFI_SUCCESS;\r
2533}\r
2534\r
2535/**\r
2536 Check if ControllerHandle supports an UDF file system.\r
2537\r
2538 @param[in] This Protocol instance pointer.\r
2539 @param[in] ControllerHandle Handle of device to test.\r
2540\r
2541 @retval EFI_SUCCESS UDF file system found.\r
2542 @retval EFI_UNSUPPORTED UDF file system not found.\r
2543\r
2544**/\r
2545EFI_STATUS\r
2546SupportUdfFileSystem (\r
2547 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2548 IN EFI_HANDLE ControllerHandle\r
2549 )\r
2550{\r
2551 EFI_STATUS Status;\r
2552 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2553 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
2554 EFI_DEVICE_PATH_PROTOCOL *LastDevicePathNode;\r
2555 EFI_GUID *VendorDefinedGuid;\r
99c9b949
PA
2556\r
2557 //\r
2558 // Open Device Path protocol on ControllerHandle\r
2559 //\r
2560 Status = gBS->OpenProtocol (\r
2561 ControllerHandle,\r
2562 &gEfiDevicePathProtocolGuid,\r
2563 (VOID **)&DevicePath,\r
2564 This->DriverBindingHandle,\r
2565 ControllerHandle,\r
2566 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2567 );\r
2568 if (EFI_ERROR (Status)) {\r
2569 return EFI_UNSUPPORTED;\r
2570 }\r
2571\r
2572 Status = EFI_UNSUPPORTED;\r
2573\r
2574 //\r
2575 // Get last Device Path node\r
2576 //\r
2577 LastDevicePathNode = NULL;\r
2578 DevicePathNode = DevicePath;\r
2579 while (!IsDevicePathEnd (DevicePathNode)) {\r
2580 LastDevicePathNode = DevicePathNode;\r
2581 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
2582 }\r
2583 //\r
2584 // Check if last Device Path node contains a Vendor-Defined Media Device Path\r
2585 // of an UDF file system.\r
2586 //\r
2587 if (LastDevicePathNode != NULL &&\r
2588 DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH &&\r
2589 DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP) {\r
2590 VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +\r
2591 OFFSET_OF (VENDOR_DEVICE_PATH, Guid));\r
3f92b104 2592 if (CompareGuid (VendorDefinedGuid, &gUdfDevPathGuid)) {\r
99c9b949
PA
2593 Status = EFI_SUCCESS;\r
2594 }\r
2595 }\r
2596\r
2597 //\r
2598 // Close Device Path protocol on ControllerHandle\r
2599 //\r
2600 gBS->CloseProtocol (\r
2601 ControllerHandle,\r
2602 &gEfiDevicePathProtocolGuid,\r
2603 This->DriverBindingHandle,\r
2604 ControllerHandle\r
2605 );\r
2606\r
2607 return Status;\r
2608}\r