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