__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout MdeModulePkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
		
			
				
	
	
		
			2987 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2987 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Handle on-disk format and volume structures in UDF/ECMA-167 file systems.
 | 
						|
 | 
						|
  Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
 | 
						|
  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
**/
 | 
						|
 | 
						|
#include "Udf.h"
 | 
						|
 | 
						|
//
 | 
						|
// Vendor-Defined Device Path GUID for UDF file system
 | 
						|
//
 | 
						|
EFI_GUID  gUdfDevPathGuid = EFI_UDF_DEVICE_PATH_GUID;
 | 
						|
 | 
						|
/**
 | 
						|
  Find the anchor volume descriptor pointer.
 | 
						|
 | 
						|
  @param[in]  BlockIo             BlockIo interface.
 | 
						|
  @param[in]  DiskIo              DiskIo interface.
 | 
						|
  @param[out] AnchorPoint         Anchor volume descriptor pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             Anchor volume descriptor pointer found.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.
 | 
						|
  @retval other                   Anchor volume descriptor pointer not found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FindAnchorVolumeDescriptorPointer (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL                 *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL                  *DiskIo,
 | 
						|
  OUT  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoint
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  UINT32              BlockSize;
 | 
						|
  EFI_LBA             EndLBA;
 | 
						|
  EFI_LBA             DescriptorLBAs[4];
 | 
						|
  UINTN               Index;
 | 
						|
  UDF_DESCRIPTOR_TAG  *DescriptorTag;
 | 
						|
 | 
						|
  BlockSize         = BlockIo->Media->BlockSize;
 | 
						|
  EndLBA            = BlockIo->Media->LastBlock;
 | 
						|
  DescriptorLBAs[0] = 256;
 | 
						|
  DescriptorLBAs[1] = EndLBA - 256;
 | 
						|
  DescriptorLBAs[2] = EndLBA;
 | 
						|
  DescriptorLBAs[3] = 512;
 | 
						|
 | 
						|
  for (Index = 0; Index < ARRAY_SIZE (DescriptorLBAs); Index++) {
 | 
						|
    Status = DiskIo->ReadDisk (
 | 
						|
                       DiskIo,
 | 
						|
                       BlockIo->Media->MediaId,
 | 
						|
                       MultU64x32 (DescriptorLBAs[Index], BlockSize),
 | 
						|
                       sizeof (UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER),
 | 
						|
                       (VOID *)AnchorPoint
 | 
						|
                       );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    DescriptorTag = &AnchorPoint->DescriptorTag;
 | 
						|
 | 
						|
    //
 | 
						|
    // Check if read LBA has a valid AVDP descriptor.
 | 
						|
    //
 | 
						|
    if (DescriptorTag->TagIdentifier == UdfAnchorVolumeDescriptorPointer) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // No AVDP found.
 | 
						|
  //
 | 
						|
  return EFI_VOLUME_CORRUPTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Save the content of Logical Volume Descriptors and Partitions Descriptors in
 | 
						|
  memory.
 | 
						|
 | 
						|
  @param[in]  BlockIo             BlockIo interface.
 | 
						|
  @param[in]  DiskIo              DiskIo interface.
 | 
						|
  @param[in]  AnchorPoint         Anchor volume descriptor pointer.
 | 
						|
  @param[out] Volume              UDF volume information structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The descriptors were saved.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    The descriptors were not saved due to lack of
 | 
						|
                                  resources.
 | 
						|
  @retval other                   The descriptors were not saved due to
 | 
						|
                                  ReadDisk error.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
StartMainVolumeDescriptorSequence (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL                 *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL                  *DiskIo,
 | 
						|
  IN   UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  *AnchorPoint,
 | 
						|
  OUT  UDF_VOLUME_INFO                       *Volume
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  UINT32              BlockSize;
 | 
						|
  UDF_EXTENT_AD       *ExtentAd;
 | 
						|
  EFI_LBA             SeqStartBlock;
 | 
						|
  EFI_LBA             SeqEndBlock;
 | 
						|
  BOOLEAN             StopSequence;
 | 
						|
  VOID                *Buffer;
 | 
						|
  UDF_DESCRIPTOR_TAG  *DescriptorTag;
 | 
						|
  UINT32              LogicalBlockSize;
 | 
						|
 | 
						|
  BlockSize = BlockIo->Media->BlockSize;
 | 
						|
  ExtentAd  = &AnchorPoint->MainVolumeDescriptorSequenceExtent;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate buffer for reading disk blocks
 | 
						|
  //
 | 
						|
  Buffer = AllocateZeroPool ((UINTN)BlockSize);
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The logical partition created by Partition driver is relative to the main
 | 
						|
  // VDS extent location, so we start the Main Volume Descriptor Sequence at
 | 
						|
  // LBA 0.
 | 
						|
  //
 | 
						|
  // We don't need to check again if we have valid Volume Descriptors here since
 | 
						|
  // Partition driver already did.
 | 
						|
  //
 | 
						|
  SeqStartBlock = 0;
 | 
						|
  SeqEndBlock   = SeqStartBlock + DivU64x32 (
 | 
						|
                                    (UINT64)ExtentAd->ExtentLength,
 | 
						|
                                    BlockSize
 | 
						|
                                    );
 | 
						|
  StopSequence = FALSE;
 | 
						|
  for ( ; SeqStartBlock < SeqEndBlock && !StopSequence; SeqStartBlock++) {
 | 
						|
    //
 | 
						|
    // Read disk block
 | 
						|
    //
 | 
						|
    Status = BlockIo->ReadBlocks (
 | 
						|
                        BlockIo,
 | 
						|
                        BlockIo->Media->MediaId,
 | 
						|
                        SeqStartBlock,
 | 
						|
                        BlockSize,
 | 
						|
                        Buffer
 | 
						|
                        );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto Out_Free;
 | 
						|
    }
 | 
						|
 | 
						|
    DescriptorTag = Buffer;
 | 
						|
 | 
						|
    switch (DescriptorTag->TagIdentifier) {
 | 
						|
      case UdfPartitionDescriptor:
 | 
						|
        //
 | 
						|
        // Save Partition Descriptor
 | 
						|
        //
 | 
						|
        CopyMem (&Volume->PartitionDesc, Buffer, sizeof (Volume->PartitionDesc));
 | 
						|
        break;
 | 
						|
 | 
						|
      case UdfLogicalVolumeDescriptor:
 | 
						|
        //
 | 
						|
        // Save Logical Volume Descriptor
 | 
						|
        //
 | 
						|
        CopyMem (&Volume->LogicalVolDesc, Buffer, sizeof (Volume->LogicalVolDesc));
 | 
						|
        break;
 | 
						|
 | 
						|
      case UdfTerminatingDescriptor:
 | 
						|
        StopSequence = TRUE;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        ;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Determine FE (File Entry) size
 | 
						|
  //
 | 
						|
  LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
 | 
						|
  if (LogicalBlockSize >= UDF_LOGICAL_SECTOR_SIZE) {
 | 
						|
    Volume->FileEntrySize = (UINTN)LogicalBlockSize;
 | 
						|
  } else {
 | 
						|
    Volume->FileEntrySize = UDF_LOGICAL_SECTOR_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
Out_Free:
 | 
						|
  //
 | 
						|
  // Free block read buffer
 | 
						|
  //
 | 
						|
  FreePool (Buffer);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return a Partition Descriptor given a Long Allocation Descriptor. This is
 | 
						|
  necessary to calculate the right extent (LongAd) offset which is added up
 | 
						|
  with partition's starting location.
 | 
						|
 | 
						|
  @param[in]  Volume              Volume information pointer.
 | 
						|
  @param[in]  LongAd              Long Allocation Descriptor pointer.
 | 
						|
 | 
						|
  @return A pointer to a Partition Descriptor.
 | 
						|
 | 
						|
**/
 | 
						|
UDF_PARTITION_DESCRIPTOR *
 | 
						|
GetPdFromLongAd (
 | 
						|
  IN UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN UDF_LONG_ALLOCATION_DESCRIPTOR  *LongAd
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc;
 | 
						|
  UINT16                         PartitionNum;
 | 
						|
 | 
						|
  LogicalVolDesc = &Volume->LogicalVolDesc;
 | 
						|
 | 
						|
  switch (LogicalVolDesc->DomainIdentifier.Suffix.Domain.UdfRevision) {
 | 
						|
    case 0x0102:
 | 
						|
    case 0x0150:
 | 
						|
    case 0x0200:
 | 
						|
    case 0x0201:
 | 
						|
    case 0x0250:
 | 
						|
    case 0x0260:
 | 
						|
      //
 | 
						|
      // UDF 1.02 specification:
 | 
						|
      //
 | 
						|
      // There shall be exactly one prevailing Logical Volume Descriptor recorded
 | 
						|
      // per Volume Set. The Partition Maps field shall contain only Type 1
 | 
						|
      // Partition Maps.
 | 
						|
      //
 | 
						|
      // UDF 1.50 through 2.60 specs say:
 | 
						|
      //
 | 
						|
      // For the purpose of interchange partition maps shall be limited to
 | 
						|
      // Partition Map type 1, except type 2 maps as described in the document.
 | 
						|
      //
 | 
						|
      // NOTE: Only one Type 1 (Physical) Partition is supported. It has been
 | 
						|
      // checked already in Partition driver for existence of a single Type 1
 | 
						|
      // Partition map. Hence, the 'PartitionReferenceNumber' field (the index
 | 
						|
      // used to access Partition Maps data within the Logical Volume Descriptor)
 | 
						|
      // in the Long Allocation Descriptor should be 0 to indicate there is only
 | 
						|
      // one partition.
 | 
						|
      //
 | 
						|
      if (LongAd->ExtentLocation.PartitionReferenceNumber != 0) {
 | 
						|
        return NULL;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Since only one partition, get the first one directly.
 | 
						|
      //
 | 
						|
      PartitionNum = *(UINT16 *)((UINTN)&LogicalVolDesc->PartitionMaps[4]);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      //
 | 
						|
      // Unsupported UDF revision
 | 
						|
      //
 | 
						|
      return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if partition number matches Partition Descriptor found in Main Volume
 | 
						|
  // Descriptor Sequence.
 | 
						|
  //
 | 
						|
  if (Volume->PartitionDesc.PartitionNumber == PartitionNum) {
 | 
						|
    return &Volume->PartitionDesc;
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return logical sector number of a given Long Allocation Descriptor.
 | 
						|
 | 
						|
  @param[in]   Volume             Volume information pointer.
 | 
						|
  @param[in]   LongAd             Long Allocation Descriptor pointer.
 | 
						|
  @param[out]  Lsn                Logical sector number pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             Logical sector number successfully returned.
 | 
						|
  @retval EFI_UNSUPPORTED         Logical sector number is not returned due to
 | 
						|
                                  unrecognized format.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetLongAdLsn (
 | 
						|
  IN  UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN  UDF_LONG_ALLOCATION_DESCRIPTOR  *LongAd,
 | 
						|
  OUT UINT64                          *Lsn
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_PARTITION_DESCRIPTOR  *PartitionDesc;
 | 
						|
 | 
						|
  PartitionDesc = GetPdFromLongAd (Volume, LongAd);
 | 
						|
  if (PartitionDesc == NULL) {
 | 
						|
    DEBUG ((
 | 
						|
      DEBUG_ERROR,
 | 
						|
      "%a: Fail to get the Partition Descriptor from the given Long Allocation Descriptor.\n",
 | 
						|
      __func__
 | 
						|
      ));
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  *Lsn = (UINT64)PartitionDesc->PartitionStartingLocation -
 | 
						|
         Volume->MainVdsStartLocation +
 | 
						|
         LongAd->ExtentLocation.LogicalBlockNumber;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return logical sector number of a given Short Allocation Descriptor.
 | 
						|
 | 
						|
  @param[in]  Volume              Volume pointer.
 | 
						|
  @param[in]  PartitionDesc       Partition Descriptor pointer.
 | 
						|
  @param[in]  ShortAd             Short Allocation Descriptor pointer.
 | 
						|
 | 
						|
  @return The logical sector number of a given Short Allocation Descriptor.
 | 
						|
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
GetShortAdLsn (
 | 
						|
  IN UDF_VOLUME_INFO                  *Volume,
 | 
						|
  IN UDF_PARTITION_DESCRIPTOR         *PartitionDesc,
 | 
						|
  IN UDF_SHORT_ALLOCATION_DESCRIPTOR  *ShortAd
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (UINT64)PartitionDesc->PartitionStartingLocation -
 | 
						|
         Volume->MainVdsStartLocation + ShortAd->ExtentPosition;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find File Set Descriptor of a given Logical Volume Descriptor.
 | 
						|
 | 
						|
  The found FSD will contain the extent (LogicalVolumeContentsUse) where our
 | 
						|
  root directory is.
 | 
						|
 | 
						|
  @param[in]  BlockIo             BlockIo interface.
 | 
						|
  @param[in]  DiskIo              DiskIo interface.
 | 
						|
  @param[in]  Volume              Volume information pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             File Set Descriptor pointer found.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.
 | 
						|
  @retval other                   File Set Descriptor pointer not found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FindFileSetDescriptor (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO        *Volume
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                     Status;
 | 
						|
  UINT64                         Lsn;
 | 
						|
  UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc;
 | 
						|
  UDF_DESCRIPTOR_TAG             *DescriptorTag;
 | 
						|
 | 
						|
  LogicalVolDesc = &Volume->LogicalVolDesc;
 | 
						|
  Status         = GetLongAdLsn (Volume, &LogicalVolDesc->LogicalVolumeContentsUse, &Lsn);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // As per UDF 2.60 specification:
 | 
						|
  //
 | 
						|
  // There shall be exactly one File Set Descriptor recorded per Logical
 | 
						|
  // Volume.
 | 
						|
  //
 | 
						|
  // Read disk block
 | 
						|
  //
 | 
						|
  Status = DiskIo->ReadDisk (
 | 
						|
                     DiskIo,
 | 
						|
                     BlockIo->Media->MediaId,
 | 
						|
                     MultU64x32 (Lsn, LogicalVolDesc->LogicalBlockSize),
 | 
						|
                     sizeof (Volume->FileSetDesc),
 | 
						|
                     &Volume->FileSetDesc
 | 
						|
                     );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DescriptorTag = &Volume->FileSetDesc.DescriptorTag;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if read block is a File Set Descriptor
 | 
						|
  //
 | 
						|
  if (DescriptorTag->TagIdentifier != UdfFileSetDescriptor) {
 | 
						|
    return EFI_VOLUME_CORRUPTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read Volume and File Structure on an UDF file system.
 | 
						|
 | 
						|
  @param[in]   BlockIo            BlockIo interface.
 | 
						|
  @param[in]   DiskIo             DiskIo interface.
 | 
						|
  @param[out]  Volume             Volume information pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             Volume and File Structure were read.
 | 
						|
  @retval other                   Volume and File Structure were not read.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadVolumeFileStructure (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,
 | 
						|
  OUT  UDF_VOLUME_INFO        *Volume
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  UDF_ANCHOR_VOLUME_DESCRIPTOR_POINTER  AnchorPoint;
 | 
						|
  UDF_EXTENT_AD                         *ExtentAd;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find Anchor Volume Descriptor Pointer
 | 
						|
  //
 | 
						|
  Status = FindAnchorVolumeDescriptorPointer (
 | 
						|
             BlockIo,
 | 
						|
             DiskIo,
 | 
						|
             &AnchorPoint
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Save Main VDS start block number
 | 
						|
  //
 | 
						|
  ExtentAd = &AnchorPoint.MainVolumeDescriptorSequenceExtent;
 | 
						|
 | 
						|
  Volume->MainVdsStartLocation = (UINT64)ExtentAd->ExtentLocation;
 | 
						|
 | 
						|
  //
 | 
						|
  // Start Main Volume Descriptor Sequence.
 | 
						|
  //
 | 
						|
  Status = StartMainVolumeDescriptorSequence (
 | 
						|
             BlockIo,
 | 
						|
             DiskIo,
 | 
						|
             &AnchorPoint,
 | 
						|
             Volume
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Calculate length of a given File Identifier Descriptor.
 | 
						|
 | 
						|
  @param[in]  FileIdentifierDesc  File Identifier Descriptor pointer.
 | 
						|
 | 
						|
  @return The length of a given File Identifier Descriptor.
 | 
						|
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
GetFidDescriptorLength (
 | 
						|
  IN UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (UINT64)(
 | 
						|
                  (INTN)((OFFSET_OF (UDF_FILE_IDENTIFIER_DESCRIPTOR, Data[0]) + 3 +
 | 
						|
                          FileIdentifierDesc->LengthOfFileIdentifier +
 | 
						|
                          FileIdentifierDesc->LengthOfImplementationUse) >> 2) << 2
 | 
						|
                  );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Duplicate a given File Identifier Descriptor.
 | 
						|
 | 
						|
  @param[in]  FileIdentifierDesc     File Identifier Descriptor pointer.
 | 
						|
  @param[out] NewFileIdentifierDesc  The duplicated File Identifier Descriptor.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DuplicateFid (
 | 
						|
  IN   UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc,
 | 
						|
  OUT  UDF_FILE_IDENTIFIER_DESCRIPTOR  **NewFileIdentifierDesc
 | 
						|
  )
 | 
						|
{
 | 
						|
  *NewFileIdentifierDesc =
 | 
						|
    (UDF_FILE_IDENTIFIER_DESCRIPTOR *)AllocateCopyPool (
 | 
						|
                                        (UINTN)GetFidDescriptorLength (FileIdentifierDesc),
 | 
						|
                                        FileIdentifierDesc
 | 
						|
                                        );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Duplicate either a given File Entry or a given Extended File Entry.
 | 
						|
 | 
						|
  @param[in]  BlockIo             BlockIo interface.
 | 
						|
  @param[in]  Volume              Volume information pointer.
 | 
						|
  @param[in]  FileEntry           (Extended) File Entry pointer.
 | 
						|
  @param[out] NewFileEntry        The duplicated (Extended) File Entry.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
DuplicateFe (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,
 | 
						|
  IN   UDF_VOLUME_INFO        *Volume,
 | 
						|
  IN   VOID                   *FileEntry,
 | 
						|
  OUT  VOID                   **NewFileEntry
 | 
						|
  )
 | 
						|
{
 | 
						|
  *NewFileEntry = AllocateCopyPool (Volume->FileEntrySize, FileEntry);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get raw data + length of a given File Entry or Extended File Entry.
 | 
						|
 | 
						|
  The file's recorded data can contain either real file content (inline) or
 | 
						|
  a sequence of extents (or Allocation Descriptors) which tells where file's
 | 
						|
  content is stored in.
 | 
						|
 | 
						|
  NOTE: The FE/EFE can be thought it was an inode.
 | 
						|
 | 
						|
  @attention This is boundary function that may receive untrusted input.
 | 
						|
  @attention The input is from FileSystem.
 | 
						|
 | 
						|
  The (Extended) File Entry is external input, so this routine will do basic
 | 
						|
  validation for (Extended) File Entry and report status.
 | 
						|
 | 
						|
  @param[in]  FileEntryData       (Extended) File Entry pointer.
 | 
						|
  @param[in]  FileEntrySize       Size of the (Extended) File Entry specified
 | 
						|
                                  by FileEntryData.
 | 
						|
  @param[out] Data                Buffer contains the raw data of a given
 | 
						|
                                  (Extended) File Entry.
 | 
						|
  @param[out] Length              Length of the data in Buffer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             Raw data and size of the FE/EFE was read.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetFileEntryData (
 | 
						|
  IN   VOID    *FileEntryData,
 | 
						|
  IN   UINTN   FileEntrySize,
 | 
						|
  OUT  VOID    **Data,
 | 
						|
  OUT  UINT64  *Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_DESCRIPTOR_TAG       *DescriptorTag;
 | 
						|
  UDF_EXTENDED_FILE_ENTRY  *ExtendedFileEntry;
 | 
						|
  UDF_FILE_ENTRY           *FileEntry;
 | 
						|
 | 
						|
  DescriptorTag = FileEntryData;
 | 
						|
 | 
						|
  if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
 | 
						|
    ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;
 | 
						|
 | 
						|
    *Length = ExtendedFileEntry->InformationLength;
 | 
						|
    *Data   = (VOID *)((UINT8 *)ExtendedFileEntry->Data +
 | 
						|
                       ExtendedFileEntry->LengthOfExtendedAttributes);
 | 
						|
  } else if (DescriptorTag->TagIdentifier == UdfFileEntry) {
 | 
						|
    FileEntry = (UDF_FILE_ENTRY *)FileEntryData;
 | 
						|
 | 
						|
    *Length = FileEntry->InformationLength;
 | 
						|
    *Data   = (VOID *)((UINT8 *)FileEntry->Data +
 | 
						|
                       FileEntry->LengthOfExtendedAttributes);
 | 
						|
  }
 | 
						|
 | 
						|
  if ((*Length > FileEntrySize) ||
 | 
						|
      ((UINTN)FileEntryData > (UINTN)(*Data)) ||
 | 
						|
      ((UINTN)(*Data) - (UINTN)FileEntryData > FileEntrySize - *Length))
 | 
						|
  {
 | 
						|
    return EFI_VOLUME_CORRUPTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get Allocation Descriptors' data information from a given FE/EFE.
 | 
						|
 | 
						|
  @attention This is boundary function that may receive untrusted input.
 | 
						|
  @attention The input is from FileSystem.
 | 
						|
 | 
						|
  The (Extended) File Entry is external input, so this routine will do basic
 | 
						|
  validation for (Extended) File Entry and report status.
 | 
						|
 | 
						|
  @param[in]  FileEntryData       (Extended) File Entry pointer.
 | 
						|
  @param[in]  FileEntrySize       Size of the (Extended) File Entry specified
 | 
						|
                                  by FileEntryData.
 | 
						|
  @param[out] AdsData             Buffer contains the Allocation Descriptors'
 | 
						|
                                  data from a given FE/EFE.
 | 
						|
  @param[out] Length              Length of the data in AdsData.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The data and size of Allocation Descriptors
 | 
						|
                                  were read from the FE/EFE.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetAdsInformation (
 | 
						|
  IN   VOID    *FileEntryData,
 | 
						|
  IN   UINTN   FileEntrySize,
 | 
						|
  OUT  VOID    **AdsData,
 | 
						|
  OUT  UINT64  *Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_DESCRIPTOR_TAG       *DescriptorTag;
 | 
						|
  UDF_EXTENDED_FILE_ENTRY  *ExtendedFileEntry;
 | 
						|
  UDF_FILE_ENTRY           *FileEntry;
 | 
						|
 | 
						|
  DescriptorTag = FileEntryData;
 | 
						|
 | 
						|
  if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
 | 
						|
    ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)FileEntryData;
 | 
						|
 | 
						|
    *Length  = ExtendedFileEntry->LengthOfAllocationDescriptors;
 | 
						|
    *AdsData = (VOID *)((UINT8 *)ExtendedFileEntry->Data +
 | 
						|
                        ExtendedFileEntry->LengthOfExtendedAttributes);
 | 
						|
  } else if (DescriptorTag->TagIdentifier == UdfFileEntry) {
 | 
						|
    FileEntry = (UDF_FILE_ENTRY *)FileEntryData;
 | 
						|
 | 
						|
    *Length  = FileEntry->LengthOfAllocationDescriptors;
 | 
						|
    *AdsData = (VOID *)((UINT8 *)FileEntry->Data +
 | 
						|
                        FileEntry->LengthOfExtendedAttributes);
 | 
						|
  }
 | 
						|
 | 
						|
  if ((*Length > FileEntrySize) ||
 | 
						|
      ((UINTN)FileEntryData > (UINTN)(*AdsData)) ||
 | 
						|
      ((UINTN)(*AdsData) - (UINTN)FileEntryData > FileEntrySize - *Length))
 | 
						|
  {
 | 
						|
    return EFI_VOLUME_CORRUPTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read next Long Allocation Descriptor from a given file's data.
 | 
						|
 | 
						|
  @param[in]     Data             File's data pointer.
 | 
						|
  @param[in,out] Offset           Starting offset of the File's data to read.
 | 
						|
  @param[in]     Length           Length of the data to read.
 | 
						|
  @param[out]    FoundLongAd      Long Allocation Descriptor pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             A Long Allocation Descriptor was found.
 | 
						|
  @retval EFI_DEVICE_ERROR        No more Long Allocation Descriptors.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetLongAdFromAds (
 | 
						|
  IN      VOID                            *Data,
 | 
						|
  IN OUT  UINT64                          *Offset,
 | 
						|
  IN      UINT64                          Length,
 | 
						|
  OUT     UDF_LONG_ALLOCATION_DESCRIPTOR  **FoundLongAd
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_LONG_ALLOCATION_DESCRIPTOR  *LongAd;
 | 
						|
  UDF_EXTENT_FLAGS                ExtentFlags;
 | 
						|
 | 
						|
  for ( ; ;) {
 | 
						|
    if (*Offset >= Length) {
 | 
						|
      //
 | 
						|
      // No more Long Allocation Descriptors.
 | 
						|
      //
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    LongAd =
 | 
						|
      (UDF_LONG_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);
 | 
						|
 | 
						|
    //
 | 
						|
    // If it's either an indirect AD (Extended Alllocation Descriptor) or an
 | 
						|
    // allocated AD, then return it.
 | 
						|
    //
 | 
						|
    ExtentFlags = GET_EXTENT_FLAGS (LongAdsSequence, LongAd);
 | 
						|
    if ((ExtentFlags == ExtentIsNextExtent) ||
 | 
						|
        (ExtentFlags == ExtentRecordedAndAllocated))
 | 
						|
    {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // This AD is either not recorded but allocated, or not recorded and not
 | 
						|
    // allocated. Skip it.
 | 
						|
    //
 | 
						|
    *Offset += AD_LENGTH (LongAdsSequence);
 | 
						|
  }
 | 
						|
 | 
						|
  *FoundLongAd = LongAd;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read next Short Allocation Descriptor from a given file's data.
 | 
						|
 | 
						|
  @param[in]     Data             File's data pointer.
 | 
						|
  @param[in,out] Offset           Starting offset of the File's data to read.
 | 
						|
  @param[in]     Length           Length of the data to read.
 | 
						|
  @param[out]    FoundShortAd     Short Allocation Descriptor pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             A Short Allocation Descriptor was found.
 | 
						|
  @retval EFI_DEVICE_ERROR        No more Short Allocation Descriptors.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetShortAdFromAds (
 | 
						|
  IN      VOID                             *Data,
 | 
						|
  IN OUT  UINT64                           *Offset,
 | 
						|
  IN      UINT64                           Length,
 | 
						|
  OUT     UDF_SHORT_ALLOCATION_DESCRIPTOR  **FoundShortAd
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_SHORT_ALLOCATION_DESCRIPTOR  *ShortAd;
 | 
						|
  UDF_EXTENT_FLAGS                 ExtentFlags;
 | 
						|
 | 
						|
  for ( ; ;) {
 | 
						|
    if (*Offset >= Length) {
 | 
						|
      //
 | 
						|
      // No more Short Allocation Descriptors.
 | 
						|
      //
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    ShortAd =
 | 
						|
      (UDF_SHORT_ALLOCATION_DESCRIPTOR *)((UINT8 *)Data + *Offset);
 | 
						|
 | 
						|
    //
 | 
						|
    // If it's either an indirect AD (Extended Alllocation Descriptor) or an
 | 
						|
    // allocated AD, then return it.
 | 
						|
    //
 | 
						|
    ExtentFlags = GET_EXTENT_FLAGS (ShortAdsSequence, ShortAd);
 | 
						|
    if ((ExtentFlags == ExtentIsNextExtent) ||
 | 
						|
        (ExtentFlags == ExtentRecordedAndAllocated))
 | 
						|
    {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // This AD is either not recorded but allocated, or not recorded and not
 | 
						|
    // allocated. Skip it.
 | 
						|
    //
 | 
						|
    *Offset += AD_LENGTH (ShortAdsSequence);
 | 
						|
  }
 | 
						|
 | 
						|
  *FoundShortAd = ShortAd;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get either a Short Allocation Descriptor or a Long Allocation Descriptor from
 | 
						|
  file's data.
 | 
						|
 | 
						|
  @param[in]     RecordingFlags   Flag to indicate the type of descriptor.
 | 
						|
  @param[in]     Data             File's data pointer.
 | 
						|
  @param[in,out] Offset           Starting offset of the File's data to read.
 | 
						|
  @param[in]     Length           Length of the data to read.
 | 
						|
  @param[out]    FoundAd          Allocation Descriptor pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             A Short Allocation Descriptor was found.
 | 
						|
  @retval EFI_DEVICE_ERROR        No more Allocation Descriptors.
 | 
						|
                                  Invalid type of descriptor was given.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetAllocationDescriptor (
 | 
						|
  IN      UDF_FE_RECORDING_FLAGS  RecordingFlags,
 | 
						|
  IN      VOID                    *Data,
 | 
						|
  IN OUT  UINT64                  *Offset,
 | 
						|
  IN      UINT64                  Length,
 | 
						|
  OUT     VOID                    **FoundAd
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (RecordingFlags == LongAdsSequence) {
 | 
						|
    return GetLongAdFromAds (
 | 
						|
             Data,
 | 
						|
             Offset,
 | 
						|
             Length,
 | 
						|
             (UDF_LONG_ALLOCATION_DESCRIPTOR **)FoundAd
 | 
						|
             );
 | 
						|
  } else if (RecordingFlags == ShortAdsSequence) {
 | 
						|
    return GetShortAdFromAds (
 | 
						|
             Data,
 | 
						|
             Offset,
 | 
						|
             Length,
 | 
						|
             (UDF_SHORT_ALLOCATION_DESCRIPTOR **)FoundAd
 | 
						|
             );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Code should never reach here.
 | 
						|
  //
 | 
						|
  ASSERT (FALSE);
 | 
						|
  return EFI_DEVICE_ERROR;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return logical sector number of either Short or Long Allocation Descriptor.
 | 
						|
 | 
						|
  @param[in]  RecordingFlags      Flag to indicate the type of descriptor.
 | 
						|
  @param[in]  Volume              Volume information pointer.
 | 
						|
  @param[in]  ParentIcb           Long Allocation Descriptor pointer.
 | 
						|
  @param[in]  Ad                  Allocation Descriptor pointer.
 | 
						|
  @param[out] Lsn                 Logical sector number pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             Logical sector number of the given Allocation
 | 
						|
                                  Descriptor successfully returned.
 | 
						|
  @retval EFI_UNSUPPORTED         Logical sector number of the given Allocation
 | 
						|
                                  Descriptor is not returned due to unrecognized
 | 
						|
                                  format.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetAllocationDescriptorLsn (
 | 
						|
  IN  UDF_FE_RECORDING_FLAGS          RecordingFlags,
 | 
						|
  IN  UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN  UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,
 | 
						|
  IN  VOID                            *Ad,
 | 
						|
  OUT UINT64                          *Lsn
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_PARTITION_DESCRIPTOR  *PartitionDesc;
 | 
						|
 | 
						|
  if (RecordingFlags == LongAdsSequence) {
 | 
						|
    return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad, Lsn);
 | 
						|
  } else if (RecordingFlags == ShortAdsSequence) {
 | 
						|
    PartitionDesc = GetPdFromLongAd (Volume, ParentIcb);
 | 
						|
    if (PartitionDesc == NULL) {
 | 
						|
      return EFI_UNSUPPORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    *Lsn = GetShortAdLsn (
 | 
						|
             Volume,
 | 
						|
             PartitionDesc,
 | 
						|
             (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad
 | 
						|
             );
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Code should never reach here.
 | 
						|
  //
 | 
						|
  ASSERT (FALSE);
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return offset + length of a given indirect Allocation Descriptor (AED).
 | 
						|
 | 
						|
  @param[in]  BlockIo             BlockIo interface.
 | 
						|
  @param[in]  DiskIo              DiskIo interface.
 | 
						|
  @param[in]  Volume              Volume information pointer.
 | 
						|
  @param[in]  ParentIcb           Long Allocation Descriptor pointer.
 | 
						|
  @param[in]  RecordingFlags      Flag to indicate the type of descriptor.
 | 
						|
  @param[in]  Ad                  Allocation Descriptor pointer.
 | 
						|
  @param[out] Offset              Offset of a given indirect Allocation
 | 
						|
                                  Descriptor.
 | 
						|
  @param[out] Length              Length of a given indirect Allocation
 | 
						|
                                  Descriptor.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The offset and length were returned.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    The offset and length were not returned due
 | 
						|
                                  to lack of resources.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.
 | 
						|
  @retval other                   The offset and length were not returned.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetAedAdsOffset (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,
 | 
						|
  IN   UDF_FE_RECORDING_FLAGS          RecordingFlags,
 | 
						|
  IN   VOID                            *Ad,
 | 
						|
  OUT  UINT64                          *Offset,
 | 
						|
  OUT  UINT64                          *Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
  UINT32                            ExtentLength;
 | 
						|
  UINT64                            Lsn;
 | 
						|
  VOID                              *Data;
 | 
						|
  UINT32                            LogicalBlockSize;
 | 
						|
  UDF_ALLOCATION_EXTENT_DESCRIPTOR  *AllocExtDesc;
 | 
						|
  UDF_DESCRIPTOR_TAG                *DescriptorTag;
 | 
						|
 | 
						|
  ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
 | 
						|
  Status       = GetAllocationDescriptorLsn (
 | 
						|
                   RecordingFlags,
 | 
						|
                   Volume,
 | 
						|
                   ParentIcb,
 | 
						|
                   Ad,
 | 
						|
                   &Lsn
 | 
						|
                   );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Data = AllocatePool (ExtentLength);
 | 
						|
  if (Data == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read extent.
 | 
						|
  //
 | 
						|
  Status = DiskIo->ReadDisk (
 | 
						|
                     DiskIo,
 | 
						|
                     BlockIo->Media->MediaId,
 | 
						|
                     MultU64x32 (Lsn, LogicalBlockSize),
 | 
						|
                     ExtentLength,
 | 
						|
                     Data
 | 
						|
                     );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  AllocExtDesc = (UDF_ALLOCATION_EXTENT_DESCRIPTOR *)Data;
 | 
						|
 | 
						|
  DescriptorTag = &AllocExtDesc->DescriptorTag;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if read extent contains a valid tag identifier for AED.
 | 
						|
  //
 | 
						|
  if (DescriptorTag->TagIdentifier != UdfAllocationExtentDescriptor) {
 | 
						|
    Status = EFI_VOLUME_CORRUPTED;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get AED's block offset and its length.
 | 
						|
  //
 | 
						|
  *Offset = MultU64x32 (Lsn, LogicalBlockSize) +
 | 
						|
            sizeof (UDF_ALLOCATION_EXTENT_DESCRIPTOR);
 | 
						|
  *Length = AllocExtDesc->LengthOfAllocationDescriptors;
 | 
						|
 | 
						|
Exit:
 | 
						|
  FreePool (Data);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read Allocation Extent Descriptor into memory.
 | 
						|
 | 
						|
  @param[in]  BlockIo             BlockIo interface.
 | 
						|
  @param[in]  DiskIo              DiskIo interface.
 | 
						|
  @param[in]  Volume              Volume information pointer.
 | 
						|
  @param[in]  ParentIcb           Long Allocation Descriptor pointer.
 | 
						|
  @param[in]  RecordingFlags      Flag to indicate the type of descriptor.
 | 
						|
  @param[in]  Ad                  Allocation Descriptor pointer.
 | 
						|
  @param[out] Data                Buffer that contains the Allocation Extent
 | 
						|
                                  Descriptor.
 | 
						|
  @param[out] Length              Length of Data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The Allocation Extent Descriptor was read.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    The Allocation Extent Descriptor was not read
 | 
						|
                                  due to lack of resources.
 | 
						|
  @retval other                   Fail to read the disk.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetAedAdsData (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,
 | 
						|
  IN   UDF_FE_RECORDING_FLAGS          RecordingFlags,
 | 
						|
  IN   VOID                            *Ad,
 | 
						|
  OUT  VOID                            **Data,
 | 
						|
  OUT  UINT64                          *Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT64      Offset;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get AED's offset + length.
 | 
						|
  //
 | 
						|
  Status = GetAedAdsOffset (
 | 
						|
             BlockIo,
 | 
						|
             DiskIo,
 | 
						|
             Volume,
 | 
						|
             ParentIcb,
 | 
						|
             RecordingFlags,
 | 
						|
             Ad,
 | 
						|
             &Offset,
 | 
						|
             Length
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate buffer to read in AED's data.
 | 
						|
  //
 | 
						|
  *Data = AllocatePool ((UINTN)(*Length));
 | 
						|
  if (*Data == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  return DiskIo->ReadDisk (
 | 
						|
                   DiskIo,
 | 
						|
                   BlockIo->Media->MediaId,
 | 
						|
                   Offset,
 | 
						|
                   (UINTN)(*Length),
 | 
						|
                   *Data
 | 
						|
                   );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function used to serialise reads of Allocation Descriptors.
 | 
						|
 | 
						|
  @param[in]      RecordingFlags  Flag to indicate the type of descriptor.
 | 
						|
  @param[in]      Ad              Allocation Descriptor pointer.
 | 
						|
  @param[in, out] Buffer          Buffer to hold the next Allocation Descriptor.
 | 
						|
  @param[in]      Length          Length of Buffer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             Buffer was grown to hold the next Allocation
 | 
						|
                                  Descriptor.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    Buffer was not grown due to lack of resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GrowUpBufferToNextAd (
 | 
						|
  IN      UDF_FE_RECORDING_FLAGS  RecordingFlags,
 | 
						|
  IN      VOID                    *Ad,
 | 
						|
  IN OUT  VOID                    **Buffer,
 | 
						|
  IN      UINT64                  Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32  ExtentLength;
 | 
						|
 | 
						|
  ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
 | 
						|
 | 
						|
  if (*Buffer == NULL) {
 | 
						|
    *Buffer = AllocatePool (ExtentLength);
 | 
						|
    if (*Buffer == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    *Buffer = ReallocatePool ((UINTN)Length, (UINTN)(Length + ExtentLength), *Buffer);
 | 
						|
    if (*Buffer == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read data or size of either a File Entry or an Extended File Entry.
 | 
						|
 | 
						|
  @param[in]      BlockIo         BlockIo interface.
 | 
						|
  @param[in]      DiskIo          DiskIo interface.
 | 
						|
  @param[in]      Volume          Volume information pointer.
 | 
						|
  @param[in]      ParentIcb       Long Allocation Descriptor pointer.
 | 
						|
  @param[in]      FileEntryData   FE/EFE structure pointer.
 | 
						|
  @param[in, out] ReadFileInfo    Read file information pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             Data or size of a FE/EFE was read.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    Data or size of a FE/EFE was not read due to
 | 
						|
                                  lack of resources.
 | 
						|
  @retval EFI_INVALID_PARAMETER   The read file flag given in ReadFileInfo is
 | 
						|
                                  invalid.
 | 
						|
  @retval EFI_UNSUPPORTED         The FE recording flag given in FileEntryData
 | 
						|
                                  is not supported.
 | 
						|
  @retval other                   Data or size of a FE/EFE was not read.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadFile (
 | 
						|
  IN      EFI_BLOCK_IO_PROTOCOL           *BlockIo,
 | 
						|
  IN      EFI_DISK_IO_PROTOCOL            *DiskIo,
 | 
						|
  IN      UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN      UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,
 | 
						|
  IN      VOID                            *FileEntryData,
 | 
						|
  IN OUT  UDF_READ_FILE_INFO              *ReadFileInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINT32                  LogicalBlockSize;
 | 
						|
  VOID                    *Data;
 | 
						|
  VOID                    *DataBak;
 | 
						|
  UINT64                  Length;
 | 
						|
  VOID                    *Ad;
 | 
						|
  UINT64                  AdOffset;
 | 
						|
  UINT64                  Lsn;
 | 
						|
  BOOLEAN                 DoFreeAed;
 | 
						|
  UINT64                  FilePosition;
 | 
						|
  UINT64                  Offset;
 | 
						|
  UINT64                  DataOffset;
 | 
						|
  UINT64                  BytesLeft;
 | 
						|
  UINT64                  DataLength;
 | 
						|
  BOOLEAN                 FinishedSeeking;
 | 
						|
  UINT32                  ExtentLength;
 | 
						|
  UDF_FE_RECORDING_FLAGS  RecordingFlags;
 | 
						|
 | 
						|
  LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
 | 
						|
  DoFreeAed        = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // set BytesLeft to suppress incorrect compiler/analyzer warnings
 | 
						|
  //
 | 
						|
  BytesLeft       = 0;
 | 
						|
  DataOffset      = 0;
 | 
						|
  FilePosition    = 0;
 | 
						|
  FinishedSeeking = FALSE;
 | 
						|
  Data            = NULL;
 | 
						|
 | 
						|
  switch (ReadFileInfo->Flags) {
 | 
						|
    case ReadFileGetFileSize:
 | 
						|
    case ReadFileAllocateAndRead:
 | 
						|
      //
 | 
						|
      // Initialise ReadFileInfo structure for either getting file size, or
 | 
						|
      // reading file's recorded data.
 | 
						|
      //
 | 
						|
      ReadFileInfo->ReadLength = 0;
 | 
						|
      ReadFileInfo->FileData   = NULL;
 | 
						|
      break;
 | 
						|
    case ReadFileSeekAndRead:
 | 
						|
      //
 | 
						|
      // About to seek a file and/or read its data.
 | 
						|
      //
 | 
						|
      Length = ReadFileInfo->FileSize - ReadFileInfo->FilePosition;
 | 
						|
      if (ReadFileInfo->FileDataSize > Length) {
 | 
						|
        //
 | 
						|
        // About to read beyond the EOF -- truncate it.
 | 
						|
        //
 | 
						|
        ReadFileInfo->FileDataSize = Length;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Initialise data to start seeking and/or reading a file.
 | 
						|
      //
 | 
						|
      BytesLeft       = ReadFileInfo->FileDataSize;
 | 
						|
      DataOffset      = 0;
 | 
						|
      FilePosition    = 0;
 | 
						|
      FinishedSeeking = FALSE;
 | 
						|
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  RecordingFlags = GET_FE_RECORDING_FLAGS (FileEntryData);
 | 
						|
  switch (RecordingFlags) {
 | 
						|
    case InlineData:
 | 
						|
      //
 | 
						|
      // There are no extents for this FE/EFE. All data is inline.
 | 
						|
      //
 | 
						|
      Status = GetFileEntryData (FileEntryData, Volume->FileEntrySize, &Data, &Length);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
 | 
						|
      if (ReadFileInfo->Flags == ReadFileGetFileSize) {
 | 
						|
        ReadFileInfo->ReadLength = Length;
 | 
						|
      } else if (ReadFileInfo->Flags == ReadFileAllocateAndRead) {
 | 
						|
        //
 | 
						|
        // Allocate buffer for starting read data.
 | 
						|
        //
 | 
						|
        ReadFileInfo->FileData = AllocatePool ((UINTN)Length);
 | 
						|
        if (ReadFileInfo->FileData == NULL) {
 | 
						|
          return EFI_OUT_OF_RESOURCES;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Read all inline data into ReadFileInfo->FileData
 | 
						|
        //
 | 
						|
        CopyMem (ReadFileInfo->FileData, Data, (UINTN)Length);
 | 
						|
        ReadFileInfo->ReadLength = Length;
 | 
						|
      } else if (ReadFileInfo->Flags == ReadFileSeekAndRead) {
 | 
						|
        //
 | 
						|
        // If FilePosition is non-zero, seek file to FilePosition, read
 | 
						|
        // FileDataSize bytes and then updates FilePosition.
 | 
						|
        //
 | 
						|
        CopyMem (
 | 
						|
          ReadFileInfo->FileData,
 | 
						|
          (VOID *)((UINT8 *)Data + ReadFileInfo->FilePosition),
 | 
						|
          (UINTN)ReadFileInfo->FileDataSize
 | 
						|
          );
 | 
						|
 | 
						|
        ReadFileInfo->FilePosition += ReadFileInfo->FileDataSize;
 | 
						|
      } else {
 | 
						|
        ASSERT (FALSE);
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
      break;
 | 
						|
 | 
						|
    case LongAdsSequence:
 | 
						|
    case ShortAdsSequence:
 | 
						|
      //
 | 
						|
      // This FE/EFE contains a run of Allocation Descriptors. Get data + size
 | 
						|
      // for start reading them out.
 | 
						|
      //
 | 
						|
      Status = GetAdsInformation (FileEntryData, Volume->FileEntrySize, &Data, &Length);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
 | 
						|
      AdOffset = 0;
 | 
						|
 | 
						|
      for ( ; ;) {
 | 
						|
        //
 | 
						|
        // Read AD.
 | 
						|
        //
 | 
						|
        Status = GetAllocationDescriptor (
 | 
						|
                   RecordingFlags,
 | 
						|
                   Data,
 | 
						|
                   &AdOffset,
 | 
						|
                   Length,
 | 
						|
                   &Ad
 | 
						|
                   );
 | 
						|
        if (Status == EFI_DEVICE_ERROR) {
 | 
						|
          Status = EFI_SUCCESS;
 | 
						|
          goto Done;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // Check if AD is an indirect AD. If so, read Allocation Extent
 | 
						|
        // Descriptor and its extents (ADs).
 | 
						|
        //
 | 
						|
        if (GET_EXTENT_FLAGS (RecordingFlags, Ad) == ExtentIsNextExtent) {
 | 
						|
          DataBak = Data;
 | 
						|
          Status  = GetAedAdsData (
 | 
						|
                      BlockIo,
 | 
						|
                      DiskIo,
 | 
						|
                      Volume,
 | 
						|
                      ParentIcb,
 | 
						|
                      RecordingFlags,
 | 
						|
                      Ad,
 | 
						|
                      &Data,
 | 
						|
                      &Length
 | 
						|
                      );
 | 
						|
 | 
						|
          if (!DoFreeAed) {
 | 
						|
            DoFreeAed = TRUE;
 | 
						|
          } else {
 | 
						|
            FreePool (DataBak);
 | 
						|
          }
 | 
						|
 | 
						|
          if (EFI_ERROR (Status)) {
 | 
						|
            goto Error_Get_Aed;
 | 
						|
          }
 | 
						|
 | 
						|
          ASSERT (Data != NULL);
 | 
						|
 | 
						|
          AdOffset = 0;
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
 | 
						|
        ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
 | 
						|
 | 
						|
        Status = GetAllocationDescriptorLsn (
 | 
						|
                   RecordingFlags,
 | 
						|
                   Volume,
 | 
						|
                   ParentIcb,
 | 
						|
                   Ad,
 | 
						|
                   &Lsn
 | 
						|
                   );
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
          goto Done;
 | 
						|
        }
 | 
						|
 | 
						|
        switch (ReadFileInfo->Flags) {
 | 
						|
          case ReadFileGetFileSize:
 | 
						|
            ReadFileInfo->ReadLength += ExtentLength;
 | 
						|
            break;
 | 
						|
          case ReadFileAllocateAndRead:
 | 
						|
            //
 | 
						|
            // Increase FileData (if necessary) to read next extent.
 | 
						|
            //
 | 
						|
            Status = GrowUpBufferToNextAd (
 | 
						|
                       RecordingFlags,
 | 
						|
                       Ad,
 | 
						|
                       &ReadFileInfo->FileData,
 | 
						|
                       ReadFileInfo->ReadLength
 | 
						|
                       );
 | 
						|
            if (EFI_ERROR (Status)) {
 | 
						|
              goto Error_Alloc_Buffer_To_Next_Ad;
 | 
						|
            }
 | 
						|
 | 
						|
            //
 | 
						|
            // Read extent's data into FileData.
 | 
						|
            //
 | 
						|
            Status = DiskIo->ReadDisk (
 | 
						|
                               DiskIo,
 | 
						|
                               BlockIo->Media->MediaId,
 | 
						|
                               MultU64x32 (Lsn, LogicalBlockSize),
 | 
						|
                               ExtentLength,
 | 
						|
                               (VOID *)((UINT8 *)ReadFileInfo->FileData +
 | 
						|
                                        ReadFileInfo->ReadLength)
 | 
						|
                               );
 | 
						|
            if (EFI_ERROR (Status)) {
 | 
						|
              goto Error_Read_Disk_Blk;
 | 
						|
            }
 | 
						|
 | 
						|
            ReadFileInfo->ReadLength += ExtentLength;
 | 
						|
            break;
 | 
						|
          case ReadFileSeekAndRead:
 | 
						|
            //
 | 
						|
            // Seek file first before reading in its data.
 | 
						|
            //
 | 
						|
            if (FinishedSeeking) {
 | 
						|
              Offset = 0;
 | 
						|
              goto Skip_File_Seek;
 | 
						|
            }
 | 
						|
 | 
						|
            if (FilePosition + ExtentLength < ReadFileInfo->FilePosition) {
 | 
						|
              FilePosition += ExtentLength;
 | 
						|
              goto Skip_Ad;
 | 
						|
            }
 | 
						|
 | 
						|
            if (FilePosition + ExtentLength > ReadFileInfo->FilePosition) {
 | 
						|
              Offset = ReadFileInfo->FilePosition - FilePosition;
 | 
						|
            } else {
 | 
						|
              Offset = 0;
 | 
						|
            }
 | 
						|
 | 
						|
            //
 | 
						|
            // Done with seeking file. Start reading its data.
 | 
						|
            //
 | 
						|
            FinishedSeeking = TRUE;
 | 
						|
 | 
						|
Skip_File_Seek:
 | 
						|
            //
 | 
						|
            // Make sure we don't read more data than really wanted.
 | 
						|
            //
 | 
						|
            if (ExtentLength - Offset > BytesLeft) {
 | 
						|
              DataLength = BytesLeft;
 | 
						|
            } else {
 | 
						|
              DataLength = ExtentLength - Offset;
 | 
						|
            }
 | 
						|
 | 
						|
            //
 | 
						|
            // Read extent's data into FileData.
 | 
						|
            //
 | 
						|
            Status = DiskIo->ReadDisk (
 | 
						|
                               DiskIo,
 | 
						|
                               BlockIo->Media->MediaId,
 | 
						|
                               Offset + MultU64x32 (Lsn, LogicalBlockSize),
 | 
						|
                               (UINTN)DataLength,
 | 
						|
                               (VOID *)((UINT8 *)ReadFileInfo->FileData +
 | 
						|
                                        DataOffset)
 | 
						|
                               );
 | 
						|
            if (EFI_ERROR (Status)) {
 | 
						|
              goto Error_Read_Disk_Blk;
 | 
						|
            }
 | 
						|
 | 
						|
            //
 | 
						|
            // Update current file's position.
 | 
						|
            //
 | 
						|
            DataOffset                 += DataLength;
 | 
						|
            ReadFileInfo->FilePosition += DataLength;
 | 
						|
 | 
						|
            BytesLeft -= DataLength;
 | 
						|
            if (BytesLeft == 0) {
 | 
						|
              //
 | 
						|
              // There is no more file data to read.
 | 
						|
              //
 | 
						|
              Status = EFI_SUCCESS;
 | 
						|
              goto Done;
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
Skip_Ad:
 | 
						|
        //
 | 
						|
        // Point to the next AD (extent).
 | 
						|
        //
 | 
						|
        AdOffset += AD_LENGTH (RecordingFlags);
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
    case ExtendedAdsSequence:
 | 
						|
      // FIXME: Not supported. Got no volume with it, yet.
 | 
						|
      ASSERT (FALSE);
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      //
 | 
						|
      // A flag value reserved by the ECMA-167 standard (3rd Edition - June
 | 
						|
      // 1997); 14.6 ICB Tag; 14.6.8 Flags (RBP 18); was found.
 | 
						|
      //
 | 
						|
      Status = EFI_UNSUPPORTED;
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
Done:
 | 
						|
  if (DoFreeAed) {
 | 
						|
    FreePool (Data);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
 | 
						|
Error_Read_Disk_Blk:
 | 
						|
Error_Alloc_Buffer_To_Next_Ad:
 | 
						|
  if (ReadFileInfo->Flags != ReadFileSeekAndRead) {
 | 
						|
    FreePool (ReadFileInfo->FileData);
 | 
						|
  }
 | 
						|
 | 
						|
  if (DoFreeAed) {
 | 
						|
    FreePool (Data);
 | 
						|
  }
 | 
						|
 | 
						|
Error_Get_Aed:
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find a file by its filename from a given Parent file.
 | 
						|
 | 
						|
  @param[in]  BlockIo             BlockIo interface.
 | 
						|
  @param[in]  DiskIo              DiskIo interface.
 | 
						|
  @param[in]  Volume              Volume information pointer.
 | 
						|
  @param[in]  FileName            File name string.
 | 
						|
  @param[in]  Parent              Parent directory file.
 | 
						|
  @param[in]  Icb                 Long Allocation Descriptor pointer.
 | 
						|
  @param[out] File                Found file.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The file was found.
 | 
						|
  @retval EFI_INVALID_PARAMETER   One or more input parameters are invalid.
 | 
						|
  @retval EFI_NOT_FOUND           The file was not found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
InternalFindFile (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN   CHAR16                          *FileName,
 | 
						|
  IN   UDF_FILE_INFO                   *Parent,
 | 
						|
  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *Icb,
 | 
						|
  OUT  UDF_FILE_INFO                   *File
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc;
 | 
						|
  UDF_READ_DIRECTORY_INFO         ReadDirInfo;
 | 
						|
  BOOLEAN                         Found;
 | 
						|
  CHAR16                          FoundFileName[UDF_FILENAME_LENGTH];
 | 
						|
  VOID                            *CompareFileEntry;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if both Parent->FileIdentifierDesc and Icb are NULL.
 | 
						|
  //
 | 
						|
  if ((Parent->FileIdentifierDesc == NULL) && (Icb == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if parent file is really directory.
 | 
						|
  //
 | 
						|
  if (FE_ICB_FILE_TYPE (Parent->FileEntry) != UdfFileEntryDirectory) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If FileName is current file or working directory, just duplicate Parent's
 | 
						|
  // FE/EFE and FID descriptors.
 | 
						|
  //
 | 
						|
  if (StrCmp (FileName, L".") == 0) {
 | 
						|
    if (Parent->FileIdentifierDesc == NULL) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    DuplicateFe (BlockIo, Volume, Parent->FileEntry, &File->FileEntry);
 | 
						|
    if (File->FileEntry == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);
 | 
						|
    if (File->FileIdentifierDesc == NULL) {
 | 
						|
      FreePool (File->FileEntry);
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Start directory listing.
 | 
						|
  //
 | 
						|
  ZeroMem ((VOID *)&ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
 | 
						|
  Found = FALSE;
 | 
						|
 | 
						|
  for ( ; ;) {
 | 
						|
    Status = ReadDirectoryEntry (
 | 
						|
               BlockIo,
 | 
						|
               DiskIo,
 | 
						|
               Volume,
 | 
						|
               (Parent->FileIdentifierDesc != NULL) ?
 | 
						|
               &Parent->FileIdentifierDesc->Icb :
 | 
						|
               Icb,
 | 
						|
               Parent->FileEntry,
 | 
						|
               &ReadDirInfo,
 | 
						|
               &FileIdentifierDesc
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      if (Status == EFI_DEVICE_ERROR) {
 | 
						|
        Status = EFI_NOT_FOUND;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // After calling function ReadDirectoryEntry(), if 'FileIdentifierDesc' is
 | 
						|
    // NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the code
 | 
						|
    // reaches here, 'FileIdentifierDesc' must be not NULL.
 | 
						|
    //
 | 
						|
    // The ASSERT here is for addressing a false positive NULL pointer
 | 
						|
    // dereference issue raised from static analysis.
 | 
						|
    //
 | 
						|
    ASSERT (FileIdentifierDesc != NULL);
 | 
						|
 | 
						|
    if (FileIdentifierDesc->FileCharacteristics & PARENT_FILE) {
 | 
						|
      //
 | 
						|
      // This FID contains the location (FE/EFE) of the parent directory of this
 | 
						|
      // directory (Parent), and if FileName is either ".." or "\\", then it's
 | 
						|
      // the expected FID.
 | 
						|
      //
 | 
						|
      if ((StrCmp (FileName, L"..") == 0) || (StrCmp (FileName, L"\\") == 0)) {
 | 
						|
        Found = TRUE;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      Status = GetFileNameFromFid (FileIdentifierDesc, ARRAY_SIZE (FoundFileName), FoundFileName);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      if (StrCmp (FileName, FoundFileName) == 0) {
 | 
						|
        //
 | 
						|
        // FID has been found. Prepare to find its respective FE/EFE.
 | 
						|
        //
 | 
						|
        Found = TRUE;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool ((VOID *)FileIdentifierDesc);
 | 
						|
  }
 | 
						|
 | 
						|
  if (ReadDirInfo.DirectoryData != NULL) {
 | 
						|
    //
 | 
						|
    // Free all allocated resources for the directory listing.
 | 
						|
    //
 | 
						|
    FreePool (ReadDirInfo.DirectoryData);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Found) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
 | 
						|
    File->FileIdentifierDesc = FileIdentifierDesc;
 | 
						|
 | 
						|
    //
 | 
						|
    // If the requested file is root directory, then the FE/EFE was already
 | 
						|
    // retrieved in UdfOpenVolume() function, thus no need to find it again.
 | 
						|
    //
 | 
						|
    // Otherwise, find FE/EFE from the respective FID.
 | 
						|
    //
 | 
						|
    if (StrCmp (FileName, L"\\") != 0) {
 | 
						|
      Status = FindFileEntry (
 | 
						|
                 BlockIo,
 | 
						|
                 DiskIo,
 | 
						|
                 Volume,
 | 
						|
                 &FileIdentifierDesc->Icb,
 | 
						|
                 &CompareFileEntry
 | 
						|
                 );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        goto Error_Find_Fe;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Make sure that both Parent's FE/EFE and found FE/EFE are not equal.
 | 
						|
      //
 | 
						|
      if (CompareMem (
 | 
						|
            (VOID *)Parent->FileEntry,
 | 
						|
            (VOID *)CompareFileEntry,
 | 
						|
            Volume->FileEntrySize
 | 
						|
            ) != 0)
 | 
						|
      {
 | 
						|
        File->FileEntry = CompareFileEntry;
 | 
						|
      } else {
 | 
						|
        FreePool ((VOID *)FileIdentifierDesc);
 | 
						|
        FreePool ((VOID *)CompareFileEntry);
 | 
						|
        Status = EFI_NOT_FOUND;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
 | 
						|
Error_Find_Fe:
 | 
						|
  FreePool ((VOID *)FileIdentifierDesc);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read volume information on a medium which contains a valid UDF file system.
 | 
						|
 | 
						|
  @param[in]   BlockIo  BlockIo interface.
 | 
						|
  @param[in]   DiskIo   DiskIo interface.
 | 
						|
  @param[out]  Volume   UDF volume information structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          Volume information read.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The volume was not read due to lack of resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadUdfVolumeInformation (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,
 | 
						|
  OUT  UDF_VOLUME_INFO        *Volume
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read all necessary UDF volume information and keep it private to the driver
 | 
						|
  //
 | 
						|
  Status = ReadVolumeFileStructure (
 | 
						|
             BlockIo,
 | 
						|
             DiskIo,
 | 
						|
             Volume
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Find File Set Descriptor
 | 
						|
  //
 | 
						|
  Status = FindFileSetDescriptor (BlockIo, DiskIo, Volume);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find the root directory on an UDF volume.
 | 
						|
 | 
						|
  @param[in]   BlockIo  BlockIo interface.
 | 
						|
  @param[in]   DiskIo   DiskIo interface.
 | 
						|
  @param[in]   Volume   UDF volume information structure.
 | 
						|
  @param[out]  File     Root directory file.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          Root directory found.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The root directory was not found due to lack of
 | 
						|
                               resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FindRootDirectory (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO        *Volume,
 | 
						|
  OUT  UDF_FILE_INFO          *File
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS     Status;
 | 
						|
  UDF_FILE_INFO  Parent;
 | 
						|
 | 
						|
  Status = FindFileEntry (
 | 
						|
             BlockIo,
 | 
						|
             DiskIo,
 | 
						|
             Volume,
 | 
						|
             &Volume->FileSetDesc.RootDirectoryIcb,
 | 
						|
             &File->FileEntry
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Parent.FileEntry          = File->FileEntry;
 | 
						|
  Parent.FileIdentifierDesc = NULL;
 | 
						|
 | 
						|
  Status = FindFile (
 | 
						|
             BlockIo,
 | 
						|
             DiskIo,
 | 
						|
             Volume,
 | 
						|
             L"\\",
 | 
						|
             NULL,
 | 
						|
             &Parent,
 | 
						|
             &Volume->FileSetDesc.RootDirectoryIcb,
 | 
						|
             File
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    FreePool (File->FileEntry);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find either a File Entry or a Extended File Entry from a given ICB.
 | 
						|
 | 
						|
  @param[in]   BlockIo    BlockIo interface.
 | 
						|
  @param[in]   DiskIo     DiskIo interface.
 | 
						|
  @param[in]   Volume     UDF volume information structure.
 | 
						|
  @param[in]   Icb        ICB of the FID.
 | 
						|
  @param[out]  FileEntry  File Entry or Extended File Entry.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          File Entry or Extended File Entry found.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The FE/EFE entry was not found due to lack of
 | 
						|
                               resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FindFileEntry (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *Icb,
 | 
						|
  OUT  VOID                            **FileEntry
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  UINT64              Lsn;
 | 
						|
  UINT32              LogicalBlockSize;
 | 
						|
  UDF_DESCRIPTOR_TAG  *DescriptorTag;
 | 
						|
  VOID                *ReadBuffer;
 | 
						|
 | 
						|
  Status = GetLongAdLsn (Volume, Icb, &Lsn);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  LogicalBlockSize = Volume->LogicalVolDesc.LogicalBlockSize;
 | 
						|
 | 
						|
  ReadBuffer = AllocateZeroPool (Volume->FileEntrySize);
 | 
						|
  if (ReadBuffer == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Read extent.
 | 
						|
  //
 | 
						|
  Status = DiskIo->ReadDisk (
 | 
						|
                     DiskIo,
 | 
						|
                     BlockIo->Media->MediaId,
 | 
						|
                     MultU64x32 (Lsn, LogicalBlockSize),
 | 
						|
                     Volume->FileEntrySize,
 | 
						|
                     ReadBuffer
 | 
						|
                     );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Error_Read_Disk_Blk;
 | 
						|
  }
 | 
						|
 | 
						|
  DescriptorTag = ReadBuffer;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if the read extent contains a valid Tag Identifier for the expected
 | 
						|
  // FE/EFE.
 | 
						|
  //
 | 
						|
  if ((DescriptorTag->TagIdentifier != UdfFileEntry) &&
 | 
						|
      (DescriptorTag->TagIdentifier != UdfExtendedFileEntry))
 | 
						|
  {
 | 
						|
    Status = EFI_VOLUME_CORRUPTED;
 | 
						|
    goto Error_Invalid_Fe;
 | 
						|
  }
 | 
						|
 | 
						|
  *FileEntry = ReadBuffer;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
Error_Invalid_Fe:
 | 
						|
Error_Read_Disk_Blk:
 | 
						|
  FreePool (ReadBuffer);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find a file given its absolute path on an UDF volume.
 | 
						|
 | 
						|
  @param[in]   BlockIo   BlockIo interface.
 | 
						|
  @param[in]   DiskIo    DiskIo interface.
 | 
						|
  @param[in]   Volume    UDF volume information structure.
 | 
						|
  @param[in]   FilePath  File's absolute path.
 | 
						|
  @param[in]   Root      Root directory file.
 | 
						|
  @param[in]   Parent    Parent directory file.
 | 
						|
  @param[in]   Icb       ICB of Parent.
 | 
						|
  @param[out]  File      Found file.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          FilePath was found.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The FilePath file was not found due to lack of
 | 
						|
                               resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FindFile (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL           *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL            *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN   CHAR16                          *FilePath,
 | 
						|
  IN   UDF_FILE_INFO                   *Root,
 | 
						|
  IN   UDF_FILE_INFO                   *Parent,
 | 
						|
  IN   UDF_LONG_ALLOCATION_DESCRIPTOR  *Icb,
 | 
						|
  OUT  UDF_FILE_INFO                   *File
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS     Status;
 | 
						|
  CHAR16         FileName[UDF_FILENAME_LENGTH];
 | 
						|
  CHAR16         *FileNamePointer;
 | 
						|
  UDF_FILE_INFO  PreviousFile;
 | 
						|
  VOID           *FileEntry;
 | 
						|
 | 
						|
  Status = EFI_NOT_FOUND;
 | 
						|
 | 
						|
  CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
 | 
						|
  while (*FilePath != L'\0') {
 | 
						|
    FileNamePointer = FileName;
 | 
						|
    while (*FilePath != L'\0' && *FilePath != L'\\') {
 | 
						|
      if ((((UINTN)FileNamePointer - (UINTN)FileName) / sizeof (CHAR16)) >=
 | 
						|
          (ARRAY_SIZE (FileName) - 1))
 | 
						|
      {
 | 
						|
        return EFI_NOT_FOUND;
 | 
						|
      }
 | 
						|
 | 
						|
      *FileNamePointer++ = *FilePath++;
 | 
						|
    }
 | 
						|
 | 
						|
    *FileNamePointer = L'\0';
 | 
						|
    if (FileName[0] == L'\0') {
 | 
						|
      //
 | 
						|
      // Open root directory.
 | 
						|
      //
 | 
						|
      if (Root == NULL) {
 | 
						|
        //
 | 
						|
        // There is no file found for the root directory yet. So, find only its
 | 
						|
        // FID by now.
 | 
						|
        //
 | 
						|
        // See UdfOpenVolume() function.
 | 
						|
        //
 | 
						|
        Status = InternalFindFile (
 | 
						|
                   BlockIo,
 | 
						|
                   DiskIo,
 | 
						|
                   Volume,
 | 
						|
                   L"\\",
 | 
						|
                   &PreviousFile,
 | 
						|
                   Icb,
 | 
						|
                   File
 | 
						|
                   );
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // We've already a file pointer (Root) for the root directory. Duplicate
 | 
						|
        // its FE/EFE and FID descriptors.
 | 
						|
        //
 | 
						|
        Status = EFI_SUCCESS;
 | 
						|
        DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);
 | 
						|
        if (File->FileEntry == NULL) {
 | 
						|
          Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        } else {
 | 
						|
          //
 | 
						|
          // File->FileEntry is not NULL.
 | 
						|
          //
 | 
						|
          DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);
 | 
						|
          if (File->FileIdentifierDesc == NULL) {
 | 
						|
            FreePool (File->FileEntry);
 | 
						|
            Status = EFI_OUT_OF_RESOURCES;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // No root directory. Find filename from the current directory.
 | 
						|
      //
 | 
						|
      Status = InternalFindFile (
 | 
						|
                 BlockIo,
 | 
						|
                 DiskIo,
 | 
						|
                 Volume,
 | 
						|
                 FileName,
 | 
						|
                 &PreviousFile,
 | 
						|
                 Icb,
 | 
						|
                 File
 | 
						|
                 );
 | 
						|
    }
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // If the found file is a symlink, then find its respective FE/EFE and
 | 
						|
    // FID descriptors.
 | 
						|
    //
 | 
						|
    if (FE_ICB_FILE_TYPE (File->FileEntry) == UdfFileEntrySymlink) {
 | 
						|
      FreePool ((VOID *)File->FileIdentifierDesc);
 | 
						|
 | 
						|
      FileEntry = File->FileEntry;
 | 
						|
 | 
						|
      Status = ResolveSymlink (
 | 
						|
                 BlockIo,
 | 
						|
                 DiskIo,
 | 
						|
                 Volume,
 | 
						|
                 &PreviousFile,
 | 
						|
                 FileEntry,
 | 
						|
                 File
 | 
						|
                 );
 | 
						|
 | 
						|
      FreePool (FileEntry);
 | 
						|
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (CompareMem (
 | 
						|
          (VOID *)&PreviousFile,
 | 
						|
          (VOID *)Parent,
 | 
						|
          sizeof (UDF_FILE_INFO)
 | 
						|
          ) != 0)
 | 
						|
    {
 | 
						|
      CleanupFileInformation (&PreviousFile);
 | 
						|
    }
 | 
						|
 | 
						|
    CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
 | 
						|
    if ((*FilePath != L'\0') && (*FilePath == L'\\')) {
 | 
						|
      FilePath++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read a directory entry at a time on an UDF volume.
 | 
						|
 | 
						|
  @param[in]      BlockIo        BlockIo interface.
 | 
						|
  @param[in]      DiskIo         DiskIo interface.
 | 
						|
  @param[in]      Volume         UDF volume information structure.
 | 
						|
  @param[in]      ParentIcb      ICB of the parent file.
 | 
						|
  @param[in]      FileEntryData  FE/EFE of the parent file.
 | 
						|
  @param[in, out] ReadDirInfo    Next read directory listing structure
 | 
						|
                                 information.
 | 
						|
  @param[out]     FoundFid       File Identifier Descriptor pointer.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          Directory entry read.
 | 
						|
  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The directory entry was not read due to lack of
 | 
						|
                               resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadDirectoryEntry (
 | 
						|
  IN      EFI_BLOCK_IO_PROTOCOL           *BlockIo,
 | 
						|
  IN      EFI_DISK_IO_PROTOCOL            *DiskIo,
 | 
						|
  IN      UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN      UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,
 | 
						|
  IN      VOID                            *FileEntryData,
 | 
						|
  IN OUT  UDF_READ_DIRECTORY_INFO         *ReadDirInfo,
 | 
						|
  OUT     UDF_FILE_IDENTIFIER_DESCRIPTOR  **FoundFid
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  UDF_READ_FILE_INFO              ReadFileInfo;
 | 
						|
  UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc;
 | 
						|
 | 
						|
  if (ReadDirInfo->DirectoryData == NULL) {
 | 
						|
    //
 | 
						|
    // The directory's recorded data has not been read yet. So let's cache it
 | 
						|
    // into memory and the next calls won't need to read it again.
 | 
						|
    //
 | 
						|
    ReadFileInfo.Flags = ReadFileAllocateAndRead;
 | 
						|
 | 
						|
    Status = ReadFile (
 | 
						|
               BlockIo,
 | 
						|
               DiskIo,
 | 
						|
               Volume,
 | 
						|
               ParentIcb,
 | 
						|
               FileEntryData,
 | 
						|
               &ReadFileInfo
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Fill in ReadDirInfo structure with the read directory's data information.
 | 
						|
    //
 | 
						|
    ReadDirInfo->DirectoryData   = ReadFileInfo.FileData;
 | 
						|
    ReadDirInfo->DirectoryLength = ReadFileInfo.ReadLength;
 | 
						|
  }
 | 
						|
 | 
						|
  do {
 | 
						|
    if (ReadDirInfo->FidOffset >= ReadDirInfo->DirectoryLength) {
 | 
						|
      //
 | 
						|
      // There are no longer FIDs for this directory. By returning
 | 
						|
      // EFI_DEVICE_ERROR to the callee will indicate end of directory
 | 
						|
      // listening.
 | 
						|
      //
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Get FID for this entry.
 | 
						|
    //
 | 
						|
    FileIdentifierDesc = GET_FID_FROM_ADS (
 | 
						|
                           ReadDirInfo->DirectoryData,
 | 
						|
                           ReadDirInfo->FidOffset
 | 
						|
                           );
 | 
						|
    //
 | 
						|
    // Update FidOffset to point to next FID.
 | 
						|
    //
 | 
						|
    ReadDirInfo->FidOffset += GetFidDescriptorLength (FileIdentifierDesc);
 | 
						|
  } while (FileIdentifierDesc->FileCharacteristics & DELETED_FILE);
 | 
						|
 | 
						|
  DuplicateFid (FileIdentifierDesc, FoundFid);
 | 
						|
  if (*FoundFid == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get a filename (encoded in OSTA-compressed format) from a File Identifier
 | 
						|
  Descriptor on an UDF volume.
 | 
						|
 | 
						|
  @attention This is boundary function that may receive untrusted input.
 | 
						|
  @attention The input is from FileSystem.
 | 
						|
 | 
						|
  The File Identifier Descriptor is external input, so this routine will do
 | 
						|
  basic validation for File Identifier Descriptor and report status.
 | 
						|
 | 
						|
  @param[in]   FileIdentifierDesc  File Identifier Descriptor pointer.
 | 
						|
  @param[in]   CharMax             The maximum number of FileName Unicode char,
 | 
						|
                                   including terminating null char.
 | 
						|
  @param[out]  FileName            Decoded filename.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Filename decoded and read.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | 
						|
  @retval EFI_BUFFER_TOO_SMALL  The string buffer FileName cannot hold the
 | 
						|
                                decoded filename.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetFileNameFromFid (
 | 
						|
  IN   UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc,
 | 
						|
  IN   UINTN                           CharMax,
 | 
						|
  OUT  CHAR16                          *FileName
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8   *OstaCompressed;
 | 
						|
  UINT8   CompressionId;
 | 
						|
  UINT8   Length;
 | 
						|
  UINTN   Index;
 | 
						|
  CHAR16  *FileNameBak;
 | 
						|
 | 
						|
  if (CharMax == 0) {
 | 
						|
    return EFI_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
 | 
						|
  OstaCompressed =
 | 
						|
    (UINT8 *)(
 | 
						|
              (UINT8 *)FileIdentifierDesc->Data +
 | 
						|
              FileIdentifierDesc->LengthOfImplementationUse
 | 
						|
              );
 | 
						|
 | 
						|
  CompressionId = OstaCompressed[0];
 | 
						|
  if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
 | 
						|
    return EFI_VOLUME_CORRUPTED;
 | 
						|
  }
 | 
						|
 | 
						|
  FileNameBak = FileName;
 | 
						|
 | 
						|
  //
 | 
						|
  // Decode filename.
 | 
						|
  //
 | 
						|
  Length = FileIdentifierDesc->LengthOfFileIdentifier;
 | 
						|
  if (CompressionId == 16) {
 | 
						|
    if (((UINTN)Length >> 1) > CharMax) {
 | 
						|
      return EFI_BUFFER_TOO_SMALL;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    if ((Length != 0) && ((UINTN)Length - 1 > CharMax)) {
 | 
						|
      return EFI_BUFFER_TOO_SMALL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 1; Index < Length; Index++) {
 | 
						|
    if (CompressionId == 16) {
 | 
						|
      *FileName = OstaCompressed[Index++] << 8;
 | 
						|
    } else {
 | 
						|
      *FileName = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Index < Length) {
 | 
						|
      *FileName |= (CHAR16)(OstaCompressed[Index]);
 | 
						|
    }
 | 
						|
 | 
						|
    FileName++;
 | 
						|
  }
 | 
						|
 | 
						|
  Index = ((UINTN)FileName - (UINTN)FileNameBak) / sizeof (CHAR16);
 | 
						|
  if (Index > CharMax - 1) {
 | 
						|
    Index = CharMax - 1;
 | 
						|
  }
 | 
						|
 | 
						|
  FileNameBak[Index] = L'\0';
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Resolve a symlink file on an UDF volume.
 | 
						|
 | 
						|
  @attention This is boundary function that may receive untrusted input.
 | 
						|
  @attention The input is from FileSystem.
 | 
						|
 | 
						|
  The Path Component is external input, so this routine will do basic
 | 
						|
  validation for Path Component and report status.
 | 
						|
 | 
						|
  @param[in]   BlockIo        BlockIo interface.
 | 
						|
  @param[in]   DiskIo         DiskIo interface.
 | 
						|
  @param[in]   Volume         UDF volume information structure.
 | 
						|
  @param[in]   Parent         Parent file.
 | 
						|
  @param[in]   FileEntryData  FE/EFE structure pointer.
 | 
						|
  @param[out]  File           Resolved file.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          Symlink file resolved.
 | 
						|
  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The symlink file was not resolved due to lack of
 | 
						|
                               resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ResolveSymlink (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO        *Volume,
 | 
						|
  IN   UDF_FILE_INFO          *Parent,
 | 
						|
  IN   VOID                   *FileEntryData,
 | 
						|
  OUT  UDF_FILE_INFO          *File
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  UDF_READ_FILE_INFO  ReadFileInfo;
 | 
						|
  UINT8               *Data;
 | 
						|
  UINT64              Length;
 | 
						|
  UINT8               *EndData;
 | 
						|
  UDF_PATH_COMPONENT  *PathComp;
 | 
						|
  UINT8               PathCompLength;
 | 
						|
  CHAR16              FileName[UDF_FILENAME_LENGTH];
 | 
						|
  CHAR16              *Char;
 | 
						|
  UINTN               Index;
 | 
						|
  UINT8               CompressionId;
 | 
						|
  UDF_FILE_INFO       PreviousFile;
 | 
						|
  BOOLEAN             NotParent;
 | 
						|
  BOOLEAN             NotFile;
 | 
						|
 | 
						|
  ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));
 | 
						|
 | 
						|
  //
 | 
						|
  // Symlink files on UDF volumes do not contain so much data other than
 | 
						|
  // Path Components which resolves to real filenames, so it's OK to read in
 | 
						|
  // all its data here -- usually the data will be inline with the FE/EFE for
 | 
						|
  // lower filenames.
 | 
						|
  //
 | 
						|
  ReadFileInfo.Flags = ReadFileAllocateAndRead;
 | 
						|
 | 
						|
  Status = ReadFile (
 | 
						|
             BlockIo,
 | 
						|
             DiskIo,
 | 
						|
             Volume,
 | 
						|
             &Parent->FileIdentifierDesc->Icb,
 | 
						|
             FileEntryData,
 | 
						|
             &ReadFileInfo
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Length = ReadFileInfo.ReadLength;
 | 
						|
 | 
						|
  Data    = (UINT8 *)ReadFileInfo.FileData;
 | 
						|
  EndData = Data + Length;
 | 
						|
 | 
						|
  CopyMem ((VOID *)&PreviousFile, (VOID *)Parent, sizeof (UDF_FILE_INFO));
 | 
						|
 | 
						|
  for ( ; ;) {
 | 
						|
    PathComp = (UDF_PATH_COMPONENT *)Data;
 | 
						|
 | 
						|
    PathCompLength = PathComp->LengthOfComponentIdentifier;
 | 
						|
 | 
						|
    switch (PathComp->ComponentType) {
 | 
						|
      case 1:
 | 
						|
      //
 | 
						|
      // This Path Component specifies the root directory hierarchy subject to
 | 
						|
      // agreement between the originator and recipient of the medium. Skip it.
 | 
						|
      //
 | 
						|
      // Fall through.
 | 
						|
      //
 | 
						|
      case 2:
 | 
						|
        //
 | 
						|
        // "\\." of the current directory. Read next Path Component.
 | 
						|
        //
 | 
						|
        goto Next_Path_Component;
 | 
						|
      case 3:
 | 
						|
        //
 | 
						|
        // ".." (parent directory). Go to it.
 | 
						|
        //
 | 
						|
        CopyMem ((VOID *)FileName, L"..", 6);
 | 
						|
        break;
 | 
						|
      case 4:
 | 
						|
        //
 | 
						|
        // "." (current file). Duplicate both FE/EFE and FID of this file.
 | 
						|
        //
 | 
						|
        DuplicateFe (BlockIo, Volume, PreviousFile.FileEntry, &File->FileEntry);
 | 
						|
        if (File->FileEntry == NULL) {
 | 
						|
          Status = EFI_OUT_OF_RESOURCES;
 | 
						|
          goto Error_Find_File;
 | 
						|
        }
 | 
						|
 | 
						|
        DuplicateFid (
 | 
						|
          PreviousFile.FileIdentifierDesc,
 | 
						|
          &File->FileIdentifierDesc
 | 
						|
          );
 | 
						|
        if (File->FileIdentifierDesc == NULL) {
 | 
						|
          FreePool (File->FileEntry);
 | 
						|
          Status = EFI_OUT_OF_RESOURCES;
 | 
						|
          goto Error_Find_File;
 | 
						|
        }
 | 
						|
 | 
						|
        goto Next_Path_Component;
 | 
						|
      case 5:
 | 
						|
        //
 | 
						|
        // This Path Component identifies an object, either a file or a
 | 
						|
        // directory or an alias.
 | 
						|
        //
 | 
						|
        // Decode it from the compressed data in ComponentIdentifier and find
 | 
						|
        // respective path.
 | 
						|
        //
 | 
						|
        CompressionId = PathComp->ComponentIdentifier[0];
 | 
						|
        if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
 | 
						|
          return EFI_VOLUME_CORRUPTED;
 | 
						|
        }
 | 
						|
 | 
						|
        if ((UINTN)PathComp->ComponentIdentifier + PathCompLength > (UINTN)EndData) {
 | 
						|
          return EFI_VOLUME_CORRUPTED;
 | 
						|
        }
 | 
						|
 | 
						|
        Char = FileName;
 | 
						|
        for (Index = 1; Index < PathCompLength; Index++) {
 | 
						|
          if (CompressionId == 16) {
 | 
						|
            *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +
 | 
						|
                               Index) << 8;
 | 
						|
            Index++;
 | 
						|
          } else {
 | 
						|
            if (Index > ARRAY_SIZE (FileName)) {
 | 
						|
              return EFI_UNSUPPORTED;
 | 
						|
            }
 | 
						|
 | 
						|
            *Char = 0;
 | 
						|
          }
 | 
						|
 | 
						|
          if (Index < Length) {
 | 
						|
            *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));
 | 
						|
          }
 | 
						|
 | 
						|
          Char++;
 | 
						|
        }
 | 
						|
 | 
						|
        Index = ((UINTN)Char - (UINTN)FileName) / sizeof (CHAR16);
 | 
						|
        if (Index > ARRAY_SIZE (FileName) - 1) {
 | 
						|
          Index = ARRAY_SIZE (FileName) - 1;
 | 
						|
        }
 | 
						|
 | 
						|
        FileName[Index] = L'\0';
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        //
 | 
						|
        // According to the ECMA-167 standard (3rd Edition - June 1997), Section
 | 
						|
        // 14.16.1.1, all other values are reserved.
 | 
						|
        //
 | 
						|
        Status = EFI_VOLUME_CORRUPTED;
 | 
						|
        goto Error_Find_File;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Find file from the read filename in symlink's file data.
 | 
						|
    //
 | 
						|
    Status = InternalFindFile (
 | 
						|
               BlockIo,
 | 
						|
               DiskIo,
 | 
						|
               Volume,
 | 
						|
               FileName,
 | 
						|
               &PreviousFile,
 | 
						|
               NULL,
 | 
						|
               File
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto Error_Find_File;
 | 
						|
    }
 | 
						|
 | 
						|
Next_Path_Component:
 | 
						|
    Data += sizeof (UDF_PATH_COMPONENT) + PathCompLength;
 | 
						|
    if (Data >= EndData) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Check the content in the file info pointed by File.
 | 
						|
    //
 | 
						|
    if ((File->FileEntry == NULL) || (File->FileIdentifierDesc == NULL)) {
 | 
						|
      Status = EFI_VOLUME_CORRUPTED;
 | 
						|
      goto Error_Find_File;
 | 
						|
    }
 | 
						|
 | 
						|
    NotParent = (CompareMem (
 | 
						|
                   (VOID *)&PreviousFile,
 | 
						|
                   (VOID *)Parent,
 | 
						|
                   sizeof (UDF_FILE_INFO)
 | 
						|
                   ) != 0);
 | 
						|
    NotFile = (CompareMem (
 | 
						|
                 (VOID *)&PreviousFile,
 | 
						|
                 (VOID *)File,
 | 
						|
                 sizeof (UDF_FILE_INFO)
 | 
						|
                 ) != 0);
 | 
						|
 | 
						|
    if (NotParent && NotFile) {
 | 
						|
      CleanupFileInformation (&PreviousFile);
 | 
						|
    }
 | 
						|
 | 
						|
    if (NotFile) {
 | 
						|
      CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Unmap the symlink file.
 | 
						|
  //
 | 
						|
  FreePool (ReadFileInfo.FileData);
 | 
						|
 | 
						|
  //
 | 
						|
  // Check the content in the resolved file info.
 | 
						|
  //
 | 
						|
  if ((File->FileEntry == NULL) || (File->FileIdentifierDesc == NULL)) {
 | 
						|
    return EFI_VOLUME_CORRUPTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
Error_Find_File:
 | 
						|
  if (CompareMem (
 | 
						|
        (VOID *)&PreviousFile,
 | 
						|
        (VOID *)Parent,
 | 
						|
        sizeof (UDF_FILE_INFO)
 | 
						|
        ) != 0)
 | 
						|
  {
 | 
						|
    CleanupFileInformation (&PreviousFile);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (ReadFileInfo.FileData);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clean up in-memory UDF file information.
 | 
						|
 | 
						|
  @param[in] File File information pointer.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
CleanupFileInformation (
 | 
						|
  IN UDF_FILE_INFO  *File
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (File->FileEntry != NULL) {
 | 
						|
    FreePool (File->FileEntry);
 | 
						|
  }
 | 
						|
 | 
						|
  if (File->FileIdentifierDesc != NULL) {
 | 
						|
    FreePool ((VOID *)File->FileIdentifierDesc);
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem ((VOID *)File, sizeof (UDF_FILE_INFO));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find a file from its absolute path on an UDF volume.
 | 
						|
 | 
						|
  @param[in]   BlockIo  BlockIo interface.
 | 
						|
  @param[in]   DiskIo   DiskIo interface.
 | 
						|
  @param[in]   Volume   UDF volume information structure.
 | 
						|
  @param[in]   File     File information structure.
 | 
						|
  @param[out]  Size     Size of the file.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          File size calculated and set in Size.
 | 
						|
  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The file size was not calculated due to lack of
 | 
						|
                               resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetFileSize (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO        *Volume,
 | 
						|
  IN   UDF_FILE_INFO          *File,
 | 
						|
  OUT  UINT64                 *Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  UDF_READ_FILE_INFO  ReadFileInfo;
 | 
						|
 | 
						|
  ReadFileInfo.Flags = ReadFileGetFileSize;
 | 
						|
 | 
						|
  Status = ReadFile (
 | 
						|
             BlockIo,
 | 
						|
             DiskIo,
 | 
						|
             Volume,
 | 
						|
             &File->FileIdentifierDesc->Icb,
 | 
						|
             File->FileEntry,
 | 
						|
             &ReadFileInfo
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  *Size = ReadFileInfo.ReadLength;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set information about a file on an UDF volume.
 | 
						|
 | 
						|
  @param[in]      File        File pointer.
 | 
						|
  @param[in]      FileSize    Size of the file.
 | 
						|
  @param[in]      FileName    Filename of the file.
 | 
						|
  @param[in, out] BufferSize  Size of the returned file infomation.
 | 
						|
  @param[out]     Buffer      Data of the returned file information.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          File information set.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The file information was not set due to lack of
 | 
						|
                               resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
SetFileInfo (
 | 
						|
  IN      UDF_FILE_INFO  *File,
 | 
						|
  IN      UINT64         FileSize,
 | 
						|
  IN      CHAR16         *FileName,
 | 
						|
  IN OUT  UINTN          *BufferSize,
 | 
						|
  OUT     VOID           *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                    FileInfoLength;
 | 
						|
  EFI_FILE_INFO            *FileInfo;
 | 
						|
  UDF_FILE_ENTRY           *FileEntry;
 | 
						|
  UDF_EXTENDED_FILE_ENTRY  *ExtendedFileEntry;
 | 
						|
  UDF_DESCRIPTOR_TAG       *DescriptorTag;
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate the needed size for the EFI_FILE_INFO structure.
 | 
						|
  //
 | 
						|
  FileInfoLength = sizeof (EFI_FILE_INFO) + ((FileName != NULL) ?
 | 
						|
                                             StrSize (FileName) :
 | 
						|
                                             sizeof (CHAR16));
 | 
						|
  if (*BufferSize < FileInfoLength) {
 | 
						|
    //
 | 
						|
    // The given Buffer has no size enough for EFI_FILE_INFO structure.
 | 
						|
    //
 | 
						|
    *BufferSize = FileInfoLength;
 | 
						|
    return EFI_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Buffer now contains room enough to store EFI_FILE_INFO structure.
 | 
						|
  // Now, fill it in with all necessary information about the file.
 | 
						|
  //
 | 
						|
  FileInfo             = (EFI_FILE_INFO *)Buffer;
 | 
						|
  FileInfo->Size       = FileInfoLength;
 | 
						|
  FileInfo->Attribute &= ~EFI_FILE_VALID_ATTR;
 | 
						|
  FileInfo->Attribute |= EFI_FILE_READ_ONLY;
 | 
						|
 | 
						|
  if (IS_FID_DIRECTORY_FILE (File->FileIdentifierDesc)) {
 | 
						|
    FileInfo->Attribute |= EFI_FILE_DIRECTORY;
 | 
						|
  } else if (IS_FID_NORMAL_FILE (File->FileIdentifierDesc)) {
 | 
						|
    FileInfo->Attribute |= EFI_FILE_ARCHIVE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IS_FID_HIDDEN_FILE (File->FileIdentifierDesc)) {
 | 
						|
    FileInfo->Attribute |= EFI_FILE_HIDDEN;
 | 
						|
  }
 | 
						|
 | 
						|
  DescriptorTag = File->FileEntry;
 | 
						|
 | 
						|
  if (DescriptorTag->TagIdentifier == UdfFileEntry) {
 | 
						|
    FileEntry = (UDF_FILE_ENTRY *)File->FileEntry;
 | 
						|
 | 
						|
    //
 | 
						|
    // Check if FE has the system attribute set.
 | 
						|
    //
 | 
						|
    if (FileEntry->IcbTag.Flags & (1 << 10)) {
 | 
						|
      FileInfo->Attribute |= EFI_FILE_SYSTEM;
 | 
						|
    }
 | 
						|
 | 
						|
    FileInfo->FileSize     = FileSize;
 | 
						|
    FileInfo->PhysicalSize = FileSize;
 | 
						|
 | 
						|
    FileInfo->CreateTime.Year       = FileEntry->AccessTime.Year;
 | 
						|
    FileInfo->CreateTime.Month      = FileEntry->AccessTime.Month;
 | 
						|
    FileInfo->CreateTime.Day        = FileEntry->AccessTime.Day;
 | 
						|
    FileInfo->CreateTime.Hour       = FileEntry->AccessTime.Hour;
 | 
						|
    FileInfo->CreateTime.Minute     = FileEntry->AccessTime.Minute;
 | 
						|
    FileInfo->CreateTime.Second     = FileEntry->AccessTime.Second;
 | 
						|
    FileInfo->CreateTime.Nanosecond =
 | 
						|
      FileEntry->AccessTime.HundredsOfMicroseconds;
 | 
						|
 | 
						|
    FileInfo->LastAccessTime.Year =
 | 
						|
      FileEntry->AccessTime.Year;
 | 
						|
    FileInfo->LastAccessTime.Month =
 | 
						|
      FileEntry->AccessTime.Month;
 | 
						|
    FileInfo->LastAccessTime.Day =
 | 
						|
      FileEntry->AccessTime.Day;
 | 
						|
    FileInfo->LastAccessTime.Hour =
 | 
						|
      FileEntry->AccessTime.Hour;
 | 
						|
    FileInfo->LastAccessTime.Minute =
 | 
						|
      FileEntry->AccessTime.Minute;
 | 
						|
    FileInfo->LastAccessTime.Second =
 | 
						|
      FileEntry->AccessTime.Second;
 | 
						|
    FileInfo->LastAccessTime.Nanosecond =
 | 
						|
      FileEntry->AccessTime.HundredsOfMicroseconds;
 | 
						|
  } else if (DescriptorTag->TagIdentifier == UdfExtendedFileEntry) {
 | 
						|
    ExtendedFileEntry = (UDF_EXTENDED_FILE_ENTRY *)File->FileEntry;
 | 
						|
 | 
						|
    //
 | 
						|
    // Check if EFE has the system attribute set.
 | 
						|
    //
 | 
						|
    if (ExtendedFileEntry->IcbTag.Flags & (1 << 10)) {
 | 
						|
      FileInfo->Attribute |= EFI_FILE_SYSTEM;
 | 
						|
    }
 | 
						|
 | 
						|
    FileInfo->FileSize     = FileSize;
 | 
						|
    FileInfo->PhysicalSize = FileSize;
 | 
						|
 | 
						|
    FileInfo->CreateTime.Year       = ExtendedFileEntry->CreationTime.Year;
 | 
						|
    FileInfo->CreateTime.Month      = ExtendedFileEntry->CreationTime.Month;
 | 
						|
    FileInfo->CreateTime.Day        = ExtendedFileEntry->CreationTime.Day;
 | 
						|
    FileInfo->CreateTime.Hour       = ExtendedFileEntry->CreationTime.Hour;
 | 
						|
    FileInfo->CreateTime.Minute     = ExtendedFileEntry->CreationTime.Second;
 | 
						|
    FileInfo->CreateTime.Second     = ExtendedFileEntry->CreationTime.Second;
 | 
						|
    FileInfo->CreateTime.Nanosecond =
 | 
						|
      ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
 | 
						|
 | 
						|
    FileInfo->LastAccessTime.Year =
 | 
						|
      ExtendedFileEntry->AccessTime.Year;
 | 
						|
    FileInfo->LastAccessTime.Month =
 | 
						|
      ExtendedFileEntry->AccessTime.Month;
 | 
						|
    FileInfo->LastAccessTime.Day =
 | 
						|
      ExtendedFileEntry->AccessTime.Day;
 | 
						|
    FileInfo->LastAccessTime.Hour =
 | 
						|
      ExtendedFileEntry->AccessTime.Hour;
 | 
						|
    FileInfo->LastAccessTime.Minute =
 | 
						|
      ExtendedFileEntry->AccessTime.Minute;
 | 
						|
    FileInfo->LastAccessTime.Second =
 | 
						|
      ExtendedFileEntry->AccessTime.Second;
 | 
						|
    FileInfo->LastAccessTime.Nanosecond =
 | 
						|
      ExtendedFileEntry->AccessTime.HundredsOfMicroseconds;
 | 
						|
  }
 | 
						|
 | 
						|
  FileInfo->CreateTime.TimeZone     = EFI_UNSPECIFIED_TIMEZONE;
 | 
						|
  FileInfo->CreateTime.Daylight     = EFI_TIME_ADJUST_DAYLIGHT;
 | 
						|
  FileInfo->LastAccessTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
 | 
						|
  FileInfo->LastAccessTime.Daylight = EFI_TIME_ADJUST_DAYLIGHT;
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    (VOID *)&FileInfo->ModificationTime,
 | 
						|
    (VOID *)&FileInfo->LastAccessTime,
 | 
						|
    sizeof (EFI_TIME)
 | 
						|
    );
 | 
						|
 | 
						|
  if (FileName != NULL) {
 | 
						|
    StrCpyS (FileInfo->FileName, StrLen (FileName) + 1, FileName);
 | 
						|
  } else {
 | 
						|
    FileInfo->FileName[0] = '\0';
 | 
						|
  }
 | 
						|
 | 
						|
  *BufferSize = FileInfoLength;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get volume label of an UDF volume.
 | 
						|
 | 
						|
  @attention This is boundary function that may receive untrusted input.
 | 
						|
  @attention The input is from FileSystem.
 | 
						|
 | 
						|
  The File Set Descriptor is external input, so this routine will do basic
 | 
						|
  validation for File Set Descriptor and report status.
 | 
						|
 | 
						|
  @param[in]   Volume   Volume information pointer.
 | 
						|
  @param[in]   CharMax  The maximum number of Unicode char in String,
 | 
						|
                        including terminating null char.
 | 
						|
  @param[out]  String   String buffer pointer to store the volume label.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Volume label is returned.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | 
						|
  @retval EFI_BUFFER_TOO_SMALL  The string buffer String cannot hold the
 | 
						|
                                volume label.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetVolumeLabel (
 | 
						|
  IN   UDF_VOLUME_INFO  *Volume,
 | 
						|
  IN   UINTN            CharMax,
 | 
						|
  OUT  CHAR16           *String
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_FILE_SET_DESCRIPTOR  *FileSetDesc;
 | 
						|
  UINTN                    Index;
 | 
						|
  UINT8                    *OstaCompressed;
 | 
						|
  UINT8                    CompressionId;
 | 
						|
  CHAR16                   *StringBak;
 | 
						|
 | 
						|
  FileSetDesc = &Volume->FileSetDesc;
 | 
						|
 | 
						|
  OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];
 | 
						|
 | 
						|
  CompressionId = OstaCompressed[0];
 | 
						|
  if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
 | 
						|
    return EFI_VOLUME_CORRUPTED;
 | 
						|
  }
 | 
						|
 | 
						|
  StringBak = String;
 | 
						|
  for (Index = 1; Index < 128; Index++) {
 | 
						|
    if (CompressionId == 16) {
 | 
						|
      if ((Index >> 1) > CharMax) {
 | 
						|
        return EFI_BUFFER_TOO_SMALL;
 | 
						|
      }
 | 
						|
 | 
						|
      *String = *(UINT8 *)(OstaCompressed + Index) << 8;
 | 
						|
      Index++;
 | 
						|
    } else {
 | 
						|
      if (Index > CharMax) {
 | 
						|
        return EFI_BUFFER_TOO_SMALL;
 | 
						|
      }
 | 
						|
 | 
						|
      *String = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Index < 128) {
 | 
						|
      *String |= (CHAR16)(*(UINT8 *)(OstaCompressed + Index));
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Unlike FID Identifiers, Logical Volume Identifier is stored in a
 | 
						|
    // NULL-terminated OSTA compressed format, so we must check for the NULL
 | 
						|
    // character.
 | 
						|
    //
 | 
						|
    if (*String == L'\0') {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    String++;
 | 
						|
  }
 | 
						|
 | 
						|
  Index = ((UINTN)String - (UINTN)StringBak) / sizeof (CHAR16);
 | 
						|
  if (Index > CharMax - 1) {
 | 
						|
    Index = CharMax - 1;
 | 
						|
  }
 | 
						|
 | 
						|
  StringBak[Index] = L'\0';
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get volume and free space size information of an UDF volume.
 | 
						|
 | 
						|
  @attention This is boundary function that may receive untrusted input.
 | 
						|
  @attention The input is from FileSystem.
 | 
						|
 | 
						|
  The Logical Volume Descriptor and the Logical Volume Integrity Descriptor are
 | 
						|
  external inputs, so this routine will do basic validation for both descriptors
 | 
						|
  and report status.
 | 
						|
 | 
						|
  @param[in]   BlockIo        BlockIo interface.
 | 
						|
  @param[in]   DiskIo         DiskIo interface.
 | 
						|
  @param[in]   Volume         UDF volume information structure.
 | 
						|
  @param[out]  VolumeSize     Volume size.
 | 
						|
  @param[out]  FreeSpaceSize  Free space size.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          Volume and free space size calculated.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The volume and free space size were not
 | 
						|
                               calculated due to lack of resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetVolumeSize (
 | 
						|
  IN   EFI_BLOCK_IO_PROTOCOL  *BlockIo,
 | 
						|
  IN   EFI_DISK_IO_PROTOCOL   *DiskIo,
 | 
						|
  IN   UDF_VOLUME_INFO        *Volume,
 | 
						|
  OUT  UINT64                 *VolumeSize,
 | 
						|
  OUT  UINT64                 *FreeSpaceSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                     Status;
 | 
						|
  UDF_LOGICAL_VOLUME_DESCRIPTOR  *LogicalVolDesc;
 | 
						|
  UDF_EXTENT_AD                  *ExtentAd;
 | 
						|
  UINT64                         Lsn;
 | 
						|
  UINT32                         LogicalBlockSize;
 | 
						|
  UDF_LOGICAL_VOLUME_INTEGRITY   *LogicalVolInt;
 | 
						|
  UDF_DESCRIPTOR_TAG             *DescriptorTag;
 | 
						|
  UINTN                          Index;
 | 
						|
  UINTN                          Length;
 | 
						|
  UINT32                         LsnsNo;
 | 
						|
 | 
						|
  LogicalVolDesc = &Volume->LogicalVolDesc;
 | 
						|
 | 
						|
  ExtentAd = &LogicalVolDesc->IntegritySequenceExtent;
 | 
						|
 | 
						|
  if ((ExtentAd->ExtentLength == 0) ||
 | 
						|
      (ExtentAd->ExtentLength < sizeof (UDF_LOGICAL_VOLUME_INTEGRITY)))
 | 
						|
  {
 | 
						|
    return EFI_VOLUME_CORRUPTED;
 | 
						|
  }
 | 
						|
 | 
						|
  LogicalVolInt = AllocatePool (ExtentAd->ExtentLength);
 | 
						|
  if (LogicalVolInt == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get location of Logical Volume Integrity Descriptor
 | 
						|
  //
 | 
						|
  Lsn = (UINT64)ExtentAd->ExtentLocation - Volume->MainVdsStartLocation;
 | 
						|
 | 
						|
  LogicalBlockSize = LogicalVolDesc->LogicalBlockSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read disk block
 | 
						|
  //
 | 
						|
  Status = DiskIo->ReadDisk (
 | 
						|
                     DiskIo,
 | 
						|
                     BlockIo->Media->MediaId,
 | 
						|
                     MultU64x32 (Lsn, LogicalBlockSize),
 | 
						|
                     ExtentAd->ExtentLength,
 | 
						|
                     LogicalVolInt
 | 
						|
                     );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Out_Free;
 | 
						|
  }
 | 
						|
 | 
						|
  DescriptorTag = &LogicalVolInt->DescriptorTag;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if read block is a Logical Volume Integrity Descriptor
 | 
						|
  //
 | 
						|
  if (DescriptorTag->TagIdentifier != UdfLogicalVolumeIntegrityDescriptor) {
 | 
						|
    Status = EFI_VOLUME_CORRUPTED;
 | 
						|
    goto Out_Free;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((LogicalVolInt->NumberOfPartitions > MAX_UINT32 / sizeof (UINT32) / 2) ||
 | 
						|
      (LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2 >
 | 
						|
       ExtentAd->ExtentLength - sizeof (UDF_LOGICAL_VOLUME_INTEGRITY)))
 | 
						|
  {
 | 
						|
    Status = EFI_VOLUME_CORRUPTED;
 | 
						|
    goto Out_Free;
 | 
						|
  }
 | 
						|
 | 
						|
  *VolumeSize    = 0;
 | 
						|
  *FreeSpaceSize = 0;
 | 
						|
 | 
						|
  Length = LogicalVolInt->NumberOfPartitions;
 | 
						|
  for (Index = 0; Index < Length; Index += sizeof (UINT32)) {
 | 
						|
    LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
 | 
						|
    //
 | 
						|
    // Check if size is not specified
 | 
						|
    //
 | 
						|
    if (LsnsNo == 0xFFFFFFFFUL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Accumulate free space size
 | 
						|
    //
 | 
						|
    *FreeSpaceSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
 | 
						|
  }
 | 
						|
 | 
						|
  Length = LogicalVolInt->NumberOfPartitions * sizeof (UINT32) * 2;
 | 
						|
  for ( ; Index < Length; Index += sizeof (UINT32)) {
 | 
						|
    LsnsNo = *(UINT32 *)((UINT8 *)LogicalVolInt->Data + Index);
 | 
						|
    //
 | 
						|
    // Check if size is not specified
 | 
						|
    //
 | 
						|
    if (LsnsNo == 0xFFFFFFFFUL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Accumulate used volume space
 | 
						|
    //
 | 
						|
    *VolumeSize += MultU64x32 ((UINT64)LsnsNo, LogicalBlockSize);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
Out_Free:
 | 
						|
  //
 | 
						|
  // Free Logical Volume Integrity Descriptor
 | 
						|
  //
 | 
						|
  FreePool (LogicalVolInt);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Seek a file and read its data into memory on an UDF volume.
 | 
						|
 | 
						|
  @param[in]      BlockIo       BlockIo interface.
 | 
						|
  @param[in]      DiskIo        DiskIo interface.
 | 
						|
  @param[in]      Volume        UDF volume information structure.
 | 
						|
  @param[in]      File          File information structure.
 | 
						|
  @param[in]      FileSize      Size of the file.
 | 
						|
  @param[in, out] FilePosition  File position.
 | 
						|
  @param[in, out] Buffer        File data.
 | 
						|
  @param[in, out] BufferSize    Read size.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          File seeked and read.
 | 
						|
  @retval EFI_UNSUPPORTED      Extended Allocation Descriptors not supported.
 | 
						|
  @retval EFI_NO_MEDIA         The device has no media.
 | 
						|
  @retval EFI_DEVICE_ERROR     The device reported an error.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES The file's recorded data was not read due to lack
 | 
						|
                               of resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadFileData (
 | 
						|
  IN      EFI_BLOCK_IO_PROTOCOL  *BlockIo,
 | 
						|
  IN      EFI_DISK_IO_PROTOCOL   *DiskIo,
 | 
						|
  IN      UDF_VOLUME_INFO        *Volume,
 | 
						|
  IN      UDF_FILE_INFO          *File,
 | 
						|
  IN      UINT64                 FileSize,
 | 
						|
  IN OUT  UINT64                 *FilePosition,
 | 
						|
  IN OUT  VOID                   *Buffer,
 | 
						|
  IN OUT  UINT64                 *BufferSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  UDF_READ_FILE_INFO  ReadFileInfo;
 | 
						|
 | 
						|
  ReadFileInfo.Flags        = ReadFileSeekAndRead;
 | 
						|
  ReadFileInfo.FilePosition = *FilePosition;
 | 
						|
  ReadFileInfo.FileData     = Buffer;
 | 
						|
  ReadFileInfo.FileDataSize = *BufferSize;
 | 
						|
  ReadFileInfo.FileSize     = FileSize;
 | 
						|
 | 
						|
  Status = ReadFile (
 | 
						|
             BlockIo,
 | 
						|
             DiskIo,
 | 
						|
             Volume,
 | 
						|
             &File->FileIdentifierDesc->Icb,
 | 
						|
             File->FileEntry,
 | 
						|
             &ReadFileInfo
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  *BufferSize   = ReadFileInfo.FileDataSize;
 | 
						|
  *FilePosition = ReadFileInfo.FilePosition;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if ControllerHandle supports an UDF file system.
 | 
						|
 | 
						|
  @param[in]  This                Protocol instance pointer.
 | 
						|
  @param[in]  ControllerHandle    Handle of device to test.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             UDF file system found.
 | 
						|
  @retval EFI_UNSUPPORTED         UDF file system not found.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
SupportUdfFileSystem (
 | 
						|
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
 | 
						|
  IN EFI_HANDLE                   ControllerHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *LastDevicePathNode;
 | 
						|
  EFI_GUID                  *VendorDefinedGuid;
 | 
						|
 | 
						|
  //
 | 
						|
  // Open Device Path protocol on ControllerHandle
 | 
						|
  //
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  ControllerHandle,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  (VOID **)&DevicePath,
 | 
						|
                  This->DriverBindingHandle,
 | 
						|
                  ControllerHandle,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_UNSUPPORTED;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get last Device Path node
 | 
						|
  //
 | 
						|
  LastDevicePathNode = NULL;
 | 
						|
  DevicePathNode     = DevicePath;
 | 
						|
  while (!IsDevicePathEnd (DevicePathNode)) {
 | 
						|
    LastDevicePathNode = DevicePathNode;
 | 
						|
    DevicePathNode     = NextDevicePathNode (DevicePathNode);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if last Device Path node contains a Vendor-Defined Media Device Path
 | 
						|
  // of an UDF file system.
 | 
						|
  //
 | 
						|
  if ((LastDevicePathNode != NULL) &&
 | 
						|
      (DevicePathType (LastDevicePathNode) == MEDIA_DEVICE_PATH) &&
 | 
						|
      (DevicePathSubType (LastDevicePathNode) == MEDIA_VENDOR_DP))
 | 
						|
  {
 | 
						|
    VendorDefinedGuid = (EFI_GUID *)((UINTN)LastDevicePathNode +
 | 
						|
                                     OFFSET_OF (VENDOR_DEVICE_PATH, Guid));
 | 
						|
    if (CompareGuid (VendorDefinedGuid, &gUdfDevPathGuid)) {
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Close Device Path protocol on ControllerHandle
 | 
						|
  //
 | 
						|
  gBS->CloseProtocol (
 | 
						|
         ControllerHandle,
 | 
						|
         &gEfiDevicePathProtocolGuid,
 | 
						|
         This->DriverBindingHandle,
 | 
						|
         ControllerHandle
 | 
						|
         );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |