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