Coverage Report

Created: 2025-10-21 06:48

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