In function FindFileEntry(): Instead of using the function parameter 'FileEntry', use a local variable to store the buffer allocated for disk read operation. For the below calling stack: UdfOpenVolume() -> FindRootDirectory() -> FindFileEntry() In FindFileEntry(), the call to 'DiskIo->ReadDisk()' is possible (e.g. media change for a CD/DVD ROM device) to trigger a re-install of the BlockIO(2) protocol which will further lead to a call of the BindingStop() & BingdingStart() of the UdfDxe driver. Meanwhile, for the above listed calling stack, the '**FileEntry' parameter passed into FindFileEntry() is '&PrivFsData->Root'. 'PrivFsData' is a driver-managed private data, it will be freed in BindingStop() and re-allocate in BingdingStart(). In such case, if '*FileEntry' is used to store the allocated buffer, the information will be lost if 'DiskIo->ReadDisk()' triggers a re-install of the BlockIO(2) protocol. The subsequent call of the FreePool API: FreePool (*FileEntry); will cause issues. This commit uses a local variable to store the allocated buffer. Cc: Ruiyu Ni <ruiyu.ni@intel.com> Cc: Star Zeng <star.zeng@intel.com> Cc: Eric Dong <eric.dong@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Paulo Alcantara <pcacjr@zytor.com>
		
			
				
	
	
		
			2609 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2609 lines
		
	
	
		
			76 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>
 | 
						|
 | 
						|
  This program and the accompanying materials are licensed and made available
 | 
						|
  under the terms and conditions of the BSD License which accompanies this
 | 
						|
  distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
 | 
						|
  WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
**/
 | 
						|
 | 
						|
#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, so we don't have to double check here.
 | 
						|
    //
 | 
						|
    // Partition reference number can also be retrieved from
 | 
						|
    // LongAd->ExtentLocation.PartitionReferenceNumber, however the spec says
 | 
						|
    // it may be 0, so let's not rely on it.
 | 
						|
    //
 | 
						|
    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.
 | 
						|
 | 
						|
  @return The logical sector number of a given Long Allocation Descriptor.
 | 
						|
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
GetLongAdLsn (
 | 
						|
  IN UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN UDF_LONG_ALLOCATION_DESCRIPTOR  *LongAd
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_PARTITION_DESCRIPTOR *PartitionDesc;
 | 
						|
 | 
						|
  PartitionDesc = GetPdFromLongAd (Volume, LongAd);
 | 
						|
  ASSERT (PartitionDesc != NULL);
 | 
						|
 | 
						|
  return (UINT64)PartitionDesc->PartitionStartingLocation -
 | 
						|
    Volume->MainVdsStartLocation +
 | 
						|
    LongAd->ExtentLocation.LogicalBlockNumber;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
  Lsn = GetLongAdLsn (Volume, &LogicalVolDesc->LogicalVolumeContentsUse);
 | 
						|
 | 
						|
  //
 | 
						|
  // 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);
 | 
						|
 | 
						|
  ASSERT (*NewFileIdentifierDesc != NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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);
 | 
						|
 | 
						|
  ASSERT (*NewFileEntry != NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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.
 | 
						|
 | 
						|
  @param[in]  FileEntryData       (Extended) File Entry pointer.
 | 
						|
  @param[out] Data                Buffer contains the raw data of a given
 | 
						|
                                  (Extended) File Entry.
 | 
						|
  @param[out] Length              Length of the data in Buffer.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
GetFileEntryData (
 | 
						|
  IN   VOID    *FileEntryData,
 | 
						|
  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);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get Allocation Descriptors' data information from a given FE/EFE.
 | 
						|
 | 
						|
  @param[in]  FileEntryData       (Extended) File Entry pointer.
 | 
						|
  @param[out] AdsData             Buffer contains the Allocation Descriptors'
 | 
						|
                                  data from a given FE/EFE.
 | 
						|
  @param[out] Length              Length of the data in AdsData.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
GetAdsInformation (
 | 
						|
  IN   VOID    *FileEntryData,
 | 
						|
  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);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  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.
 | 
						|
 | 
						|
  @return The logical sector number of the given Allocation Descriptor.
 | 
						|
 | 
						|
**/
 | 
						|
UINT64
 | 
						|
GetAllocationDescriptorLsn (
 | 
						|
  IN UDF_FE_RECORDING_FLAGS          RecordingFlags,
 | 
						|
  IN UDF_VOLUME_INFO                 *Volume,
 | 
						|
  IN UDF_LONG_ALLOCATION_DESCRIPTOR  *ParentIcb,
 | 
						|
  IN VOID                            *Ad
 | 
						|
  )
 | 
						|
{
 | 
						|
  UDF_PARTITION_DESCRIPTOR *PartitionDesc;
 | 
						|
 | 
						|
  if (RecordingFlags == LongAdsSequence) {
 | 
						|
    return GetLongAdLsn (Volume, (UDF_LONG_ALLOCATION_DESCRIPTOR *)Ad);
 | 
						|
  } else if (RecordingFlags == ShortAdsSequence) {
 | 
						|
    PartitionDesc = GetPdFromLongAd (Volume, ParentIcb);
 | 
						|
    ASSERT (PartitionDesc != NULL);
 | 
						|
 | 
						|
    return GetShortAdLsn (
 | 
						|
      Volume,
 | 
						|
      PartitionDesc,
 | 
						|
      (UDF_SHORT_ALLOCATION_DESCRIPTOR *)Ad
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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);
 | 
						|
  Lsn           = GetAllocationDescriptorLsn (RecordingFlags,
 | 
						|
                                              Volume,
 | 
						|
                                              ParentIcb,
 | 
						|
                                              Ad);
 | 
						|
 | 
						|
  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;
 | 
						|
  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.
 | 
						|
    //
 | 
						|
    GetFileEntryData (FileEntryData, &Data, &Length);
 | 
						|
 | 
						|
    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.
 | 
						|
    //
 | 
						|
    GetAdsInformation (FileEntryData, &Data, &Length);
 | 
						|
    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) {
 | 
						|
        if (!DoFreeAed) {
 | 
						|
          DoFreeAed = TRUE;
 | 
						|
        } else {
 | 
						|
          FreePool (Data);
 | 
						|
        }
 | 
						|
 | 
						|
        Status = GetAedAdsData (
 | 
						|
          BlockIo,
 | 
						|
          DiskIo,
 | 
						|
          Volume,
 | 
						|
          ParentIcb,
 | 
						|
          RecordingFlags,
 | 
						|
          Ad,
 | 
						|
          &Data,
 | 
						|
          &Length
 | 
						|
          );
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
          goto Error_Get_Aed;
 | 
						|
        }
 | 
						|
        ASSERT (Data != NULL);
 | 
						|
 | 
						|
        AdOffset = 0;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      ExtentLength = GET_EXTENT_LENGTH (RecordingFlags, Ad);
 | 
						|
 | 
						|
      Lsn = GetAllocationDescriptorLsn (RecordingFlags,
 | 
						|
                                        Volume,
 | 
						|
                                        ParentIcb,
 | 
						|
                                        Ad);
 | 
						|
 | 
						|
      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);
 | 
						|
    DuplicateFid (Parent->FileIdentifierDesc, &File->FileIdentifierDesc);
 | 
						|
 | 
						|
    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;
 | 
						|
    }
 | 
						|
 | 
						|
    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, 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;
 | 
						|
 | 
						|
  Lsn               = GetLongAdLsn (Volume, Icb);
 | 
						|
  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'\\') {
 | 
						|
      *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.
 | 
						|
        //
 | 
						|
        DuplicateFe (BlockIo, Volume, Root->FileEntry, &File->FileEntry);
 | 
						|
        DuplicateFid (Root->FileIdentifierDesc, &File->FileIdentifierDesc);
 | 
						|
        Status = EFI_SUCCESS;
 | 
						|
      }
 | 
						|
    } 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);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get a filename (encoded in OSTA-compressed format) from a File Identifier
 | 
						|
  Descriptor on an UDF volume.
 | 
						|
 | 
						|
  @param[in]   FileIdentifierDesc  File Identifier Descriptor pointer.
 | 
						|
  @param[out]  FileName            Decoded filename.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Filename decoded and read.
 | 
						|
  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetFileNameFromFid (
 | 
						|
  IN   UDF_FILE_IDENTIFIER_DESCRIPTOR  *FileIdentifierDesc,
 | 
						|
  OUT  CHAR16                          *FileName
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8 *OstaCompressed;
 | 
						|
  UINT8 CompressionId;
 | 
						|
  UINT8 Length;
 | 
						|
  UINTN Index;
 | 
						|
 | 
						|
  OstaCompressed =
 | 
						|
    (UINT8 *)(
 | 
						|
      (UINT8 *)FileIdentifierDesc->Data +
 | 
						|
      FileIdentifierDesc->LengthOfImplementationUse
 | 
						|
      );
 | 
						|
 | 
						|
  CompressionId = OstaCompressed[0];
 | 
						|
  if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
 | 
						|
    return EFI_VOLUME_CORRUPTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Decode filename.
 | 
						|
  //
 | 
						|
  Length = FileIdentifierDesc->LengthOfFileIdentifier;
 | 
						|
  for (Index = 1; Index < Length; Index++) {
 | 
						|
    if (CompressionId == 16) {
 | 
						|
      *FileName = OstaCompressed[Index++] << 8;
 | 
						|
    } else {
 | 
						|
      *FileName = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Index < Length) {
 | 
						|
      *FileName |= (CHAR16)(OstaCompressed[Index]);
 | 
						|
    }
 | 
						|
 | 
						|
    FileName++;
 | 
						|
  }
 | 
						|
 | 
						|
  *FileName = L'\0';
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Resolve a symlink file on an UDF volume.
 | 
						|
 | 
						|
  @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;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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);
 | 
						|
      DuplicateFid (PreviousFile.FileIdentifierDesc,
 | 
						|
                    &File->FileIdentifierDesc);
 | 
						|
      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;
 | 
						|
      }
 | 
						|
 | 
						|
      Char = FileName;
 | 
						|
      for (Index = 1; Index < PathCompLength; Index++) {
 | 
						|
        if (CompressionId == 16) {
 | 
						|
          *Char = *(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier +
 | 
						|
                          Index) << 8;
 | 
						|
          Index++;
 | 
						|
        } else {
 | 
						|
          *Char = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        if (Index < Length) {
 | 
						|
          *Char |= (CHAR16)(*(UINT8 *)((UINT8 *)PathComp->ComponentIdentifier + Index));
 | 
						|
        }
 | 
						|
 | 
						|
        Char++;
 | 
						|
      }
 | 
						|
 | 
						|
      *Char = L'\0';
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 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;
 | 
						|
    }
 | 
						|
 | 
						|
    if (CompareMem ((VOID *)&PreviousFile, (VOID *)Parent,
 | 
						|
                    sizeof (UDF_FILE_INFO)) != 0) {
 | 
						|
      CleanupFileInformation (&PreviousFile);
 | 
						|
    }
 | 
						|
 | 
						|
    CopyMem ((VOID *)&PreviousFile, (VOID *)File, sizeof (UDF_FILE_INFO));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Unmap the symlink file.
 | 
						|
  //
 | 
						|
  FreePool (ReadFileInfo.FileData);
 | 
						|
 | 
						|
  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.Second;
 | 
						|
    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 and free space size information of an UDF volume.
 | 
						|
 | 
						|
  @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) {
 | 
						|
    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;
 | 
						|
  }
 | 
						|
 | 
						|
  *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;
 | 
						|
}
 |