mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 02:40:26 +00:00 
			
		
		
		
	There are cases that the operands of an expression are all with rank less
than UINT64/INT64 and the result of the expression is explicitly cast to
UINT64/INT64 to fit the target size.
An example will be:
UINT32 a,b;
// a and b can be any unsigned int type with rank less than UINT64, like
// UINT8, UINT16, etc.
UINT64 c;
c = (UINT64) (a + b);
Some static code checkers may warn that the expression result might
overflow within the rank of "int" (integer promotions) and the result is
then cast to a bigger size.
The commit refines codes by the following rules:
1). When the expression is possible to overflow the range of unsigned int/
int:
c = (UINT64)a + b;
2). When the expression will not overflow within the rank of "int", remove
the explicit type casts:
c = a + b;
3). When the expression will be cast to pointer of possible greater size:
UINT32 a,b;
VOID *c;
c = (VOID *)(UINTN)(a + b); --> c = (VOID *)((UINTN)a + b);
4). When one side of a comparison expression contains only operands with
rank less than UINT32:
UINT8 a;
UINT16 b;
UINTN c;
if ((UINTN)(a + b) > c) {...} --> if (((UINT32)a + b) > c) {...}
For rule 4), if we remove the 'UINTN' type cast like:
if (a + b > c) {...}
The VS compiler will complain with warning C4018 (signed/unsigned
mismatch, level 3 warning) due to promoting 'a + b' to type 'int'.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
		
	
			
		
			
				
	
	
		
			528 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			528 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  FAT file system access routines for FAT recovery PEIM
 | 
						|
 | 
						|
Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
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 "FatLitePeim.h"
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check if there is a valid FAT in the corresponding Block device
 | 
						|
  of the volume and if yes, fill in the relevant fields for the
 | 
						|
  volume structure. Note there should be a valid Block device number
 | 
						|
  already set.
 | 
						|
 | 
						|
  @param  PrivateData            Global memory map for accessing global 
 | 
						|
                                 variables. 
 | 
						|
  @param  Volume                 On input, the BlockDeviceNumber field of the 
 | 
						|
                                 Volume  should be a valid value. On successful 
 | 
						|
                                 output, all  fields except the VolumeNumber 
 | 
						|
                                 field is initialized. 
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            A FAT is found and the volume structure is 
 | 
						|
                                 initialized. 
 | 
						|
  @retval EFI_NOT_FOUND          There is no FAT on the corresponding device. 
 | 
						|
  @retval EFI_DEVICE_ERROR       There is something error while accessing device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatGetBpbInfo (
 | 
						|
  IN      PEI_FAT_PRIVATE_DATA  *PrivateData,
 | 
						|
  IN OUT  PEI_FAT_VOLUME        *Volume
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  PEI_FAT_BOOT_SECTOR     Bpb;
 | 
						|
  PEI_FAT_BOOT_SECTOR_EX  BpbEx;
 | 
						|
  UINT32                  Sectors;
 | 
						|
  UINT32                  SectorsPerFat;
 | 
						|
  UINT32                  RootDirSectors;
 | 
						|
  UINT64                  FatLba;
 | 
						|
  UINT64                  RootLba;
 | 
						|
  UINT64                  FirstClusterLba;
 | 
						|
 | 
						|
  //
 | 
						|
  // Read in the BPB
 | 
						|
  //
 | 
						|
  Status = FatReadDisk (
 | 
						|
            PrivateData,
 | 
						|
            Volume->BlockDeviceNo,
 | 
						|
            0,
 | 
						|
            sizeof (PEI_FAT_BOOT_SECTOR_EX),
 | 
						|
            &BpbEx
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    (UINT8 *) (&Bpb),
 | 
						|
    (UINT8 *) (&BpbEx),
 | 
						|
    sizeof (PEI_FAT_BOOT_SECTOR)
 | 
						|
    );
 | 
						|
 | 
						|
  Volume->FatType = FatUnknown;
 | 
						|
 | 
						|
  Sectors         = Bpb.Sectors;
 | 
						|
  if (Sectors == 0) {
 | 
						|
    Sectors = Bpb.LargeSectors;
 | 
						|
  }
 | 
						|
 | 
						|
  SectorsPerFat = Bpb.SectorsPerFat;
 | 
						|
  if (SectorsPerFat == 0) {
 | 
						|
    SectorsPerFat   = BpbEx.LargeSectorsPerFat;
 | 
						|
    Volume->FatType = Fat32;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Filter out those not a FAT
 | 
						|
  //
 | 
						|
  if (Bpb.Ia32Jump[0] != 0xe9 && Bpb.Ia32Jump[0] != 0xeb && Bpb.Ia32Jump[0] != 0x49) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Bpb.ReservedSectors == 0 || Bpb.NoFats == 0 || Sectors == 0) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Bpb.SectorsPerCluster != 1 &&
 | 
						|
      Bpb.SectorsPerCluster != 2 &&
 | 
						|
      Bpb.SectorsPerCluster != 4 &&
 | 
						|
      Bpb.SectorsPerCluster != 8 &&
 | 
						|
      Bpb.SectorsPerCluster != 16 &&
 | 
						|
      Bpb.SectorsPerCluster != 32 &&
 | 
						|
      Bpb.SectorsPerCluster != 64 &&
 | 
						|
      Bpb.SectorsPerCluster != 128
 | 
						|
      ) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Volume->FatType == Fat32 && (SectorsPerFat == 0 || BpbEx.FsVersion != 0)) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Bpb.Media != 0xf0 &&
 | 
						|
      Bpb.Media != 0xf8 &&
 | 
						|
      Bpb.Media != 0xf9 &&
 | 
						|
      Bpb.Media != 0xfb &&
 | 
						|
      Bpb.Media != 0xfc &&
 | 
						|
      Bpb.Media != 0xfd &&
 | 
						|
      Bpb.Media != 0xfe &&
 | 
						|
      Bpb.Media != 0xff &&
 | 
						|
      //
 | 
						|
      // FujitsuFMR
 | 
						|
      //
 | 
						|
      Bpb.Media != 0x00 &&
 | 
						|
      Bpb.Media != 0x01 &&
 | 
						|
      Bpb.Media != 0xfa
 | 
						|
      ) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Volume->FatType != Fat32 && Bpb.RootEntries == 0) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If this is fat32, refuse to mount mirror-disabled volumes
 | 
						|
  //
 | 
						|
  if (Volume->FatType == Fat32 && ((BpbEx.ExtendedFlags & 0x80) != 0)) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Fill in the volume structure fields
 | 
						|
  // (Sectors & SectorsPerFat is computed earlier already)
 | 
						|
  //
 | 
						|
  Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster;
 | 
						|
  Volume->RootEntries = Bpb.RootEntries;
 | 
						|
  Volume->SectorSize  = Bpb.SectorSize;
 | 
						|
 | 
						|
  RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize;
 | 
						|
 | 
						|
  FatLba                  = Bpb.ReservedSectors;
 | 
						|
  RootLba                 = Bpb.NoFats * SectorsPerFat + FatLba;
 | 
						|
  FirstClusterLba         = RootLba + RootDirSectors;
 | 
						|
 | 
						|
  Volume->VolumeSize      = MultU64x32 (Sectors, Volume->SectorSize);
 | 
						|
  Volume->FatPos          = MultU64x32 (FatLba, Volume->SectorSize);
 | 
						|
  Volume->RootDirPos      = MultU64x32 (RootLba, Volume->SectorSize);
 | 
						|
  Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize);
 | 
						|
  Volume->MaxCluster      = (UINT32) (Sectors - FirstClusterLba) / Bpb.SectorsPerCluster;
 | 
						|
  Volume->RootDirCluster  = BpbEx.RootDirFirstCluster;
 | 
						|
 | 
						|
  //
 | 
						|
  // If this is not a fat32, determine if it's a fat16 or fat12
 | 
						|
  //
 | 
						|
  if (Volume->FatType != Fat32) {
 | 
						|
 | 
						|
    if (Volume->MaxCluster >= 65525) {
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
 | 
						|
    Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Gets the next cluster in the cluster chain
 | 
						|
 | 
						|
  @param  PrivateData            Global memory map for accessing global variables 
 | 
						|
  @param  Volume                 The volume 
 | 
						|
  @param  Cluster                The cluster 
 | 
						|
  @param  NextCluster            The cluster number of the next cluster 
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The address is got 
 | 
						|
  @retval EFI_INVALID_PARAMETER  ClusterNo exceeds the MaxCluster of the volume. 
 | 
						|
  @retval EFI_DEVICE_ERROR       Read disk error
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatGetNextCluster (
 | 
						|
  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
 | 
						|
  IN  PEI_FAT_VOLUME        *Volume,
 | 
						|
  IN  UINT32                Cluster,
 | 
						|
  OUT UINT32                *NextCluster
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT64      FatEntryPos;
 | 
						|
  UINT32      Dummy;
 | 
						|
 | 
						|
  *NextCluster = 0;
 | 
						|
 | 
						|
  if (Volume->FatType == Fat32) {
 | 
						|
    FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster);
 | 
						|
 | 
						|
    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster);
 | 
						|
    *NextCluster &= 0x0fffffff;
 | 
						|
 | 
						|
    //
 | 
						|
    // Pad high bits for our FAT_CLUSTER_... macro definitions to work
 | 
						|
    //
 | 
						|
    if ((*NextCluster) >= 0x0ffffff7) {
 | 
						|
      *NextCluster |= (-1 &~0xf);
 | 
						|
    }
 | 
						|
 | 
						|
  } else if (Volume->FatType == Fat16) {
 | 
						|
    FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster);
 | 
						|
 | 
						|
    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);
 | 
						|
 | 
						|
    //
 | 
						|
    // Pad high bits for our FAT_CLUSTER_... macro definitions to work
 | 
						|
    //
 | 
						|
    if ((*NextCluster) >= 0xfff7) {
 | 
						|
      *NextCluster |= (-1 &~0xf);
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy);
 | 
						|
 | 
						|
    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);
 | 
						|
 | 
						|
    if ((Cluster & 0x01) != 0) {
 | 
						|
      *NextCluster = (*NextCluster) >> 4;
 | 
						|
    } else {
 | 
						|
      *NextCluster = (*NextCluster) & 0x0fff;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Pad high bits for our FAT_CLUSTER_... macro definitions to work
 | 
						|
    //
 | 
						|
    if ((*NextCluster) >= 0x0ff7) {
 | 
						|
      *NextCluster |= (-1 &~0xf);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.
 | 
						|
 | 
						|
  @param  PrivateData            the global memory map 
 | 
						|
  @param  File                   the file 
 | 
						|
  @param  Pos                    the Position which is offset from the file's 
 | 
						|
                                 CurrentPos 
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            Success. 
 | 
						|
  @retval EFI_INVALID_PARAMETER  Pos is beyond file's size. 
 | 
						|
  @retval EFI_DEVICE_ERROR       Something error while accessing media.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatSetFilePos (
 | 
						|
  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
 | 
						|
  IN  PEI_FAT_FILE          *File,
 | 
						|
  IN  UINT32                Pos
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      AlignedPos;
 | 
						|
  UINT32      Offset;
 | 
						|
  UINT32      Cluster;
 | 
						|
  UINT32      PrevCluster;
 | 
						|
 | 
						|
  if (File->IsFixedRootDir) {
 | 
						|
 | 
						|
    if (Pos >= MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    File->CurrentPos += Pos;
 | 
						|
    File->StraightReadAmount = (UINT32) (MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos);
 | 
						|
 | 
						|
  } else {
 | 
						|
 | 
						|
    DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);
 | 
						|
    AlignedPos = (UINT32) File->CurrentPos - (UINT32) Offset;
 | 
						|
 | 
						|
    while
 | 
						|
    (
 | 
						|
      !FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster) &&
 | 
						|
      AlignedPos + File->Volume->ClusterSize <= File->CurrentPos + Pos
 | 
						|
    ) {
 | 
						|
      AlignedPos += File->Volume->ClusterSize;
 | 
						|
      Status = FatGetNextCluster (
 | 
						|
                PrivateData,
 | 
						|
                File->Volume,
 | 
						|
                File->CurrentCluster,
 | 
						|
                &File->CurrentCluster
 | 
						|
                );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return EFI_DEVICE_ERROR;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    File->CurrentPos += Pos;
 | 
						|
    //
 | 
						|
    // Calculate the amount of consecutive cluster occupied by the file.
 | 
						|
    // FatReadFile() will use it to read these blocks once.
 | 
						|
    //
 | 
						|
    File->StraightReadAmount  = 0;
 | 
						|
    Cluster                   = File->CurrentCluster;
 | 
						|
    while (!FAT_CLUSTER_FUNCTIONAL (Cluster)) {
 | 
						|
      File->StraightReadAmount += File->Volume->ClusterSize;
 | 
						|
      PrevCluster = Cluster;
 | 
						|
      Status      = FatGetNextCluster (PrivateData, File->Volume, Cluster, &Cluster);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return EFI_DEVICE_ERROR;
 | 
						|
      }
 | 
						|
 | 
						|
      if (Cluster != PrevCluster + 1) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);
 | 
						|
    File->StraightReadAmount -= (UINT32) Offset;
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Reads file data. Updates the file's CurrentPos.
 | 
						|
 | 
						|
  @param  PrivateData            Global memory map for accessing global variables 
 | 
						|
  @param  File                   The file. 
 | 
						|
  @param  Size                   The amount of data to read. 
 | 
						|
  @param  Buffer                 The buffer storing the data. 
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The data is read. 
 | 
						|
  @retval EFI_INVALID_PARAMETER  File is invalid. 
 | 
						|
  @retval EFI_DEVICE_ERROR       Something error while accessing media.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatReadFile (
 | 
						|
  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
 | 
						|
  IN  PEI_FAT_FILE          *File,
 | 
						|
  IN  UINTN                 Size,
 | 
						|
  OUT VOID                  *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  CHAR8       *BufferPtr;
 | 
						|
  UINT32      Offset;
 | 
						|
  UINT64      PhysicalAddr;
 | 
						|
  UINTN       Amount;
 | 
						|
 | 
						|
  BufferPtr = Buffer;
 | 
						|
 | 
						|
  if (File->IsFixedRootDir) {
 | 
						|
    //
 | 
						|
    // This is the fixed root dir in FAT12 and FAT16
 | 
						|
    //
 | 
						|
    if (File->CurrentPos + Size > File->Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = FatReadDisk (
 | 
						|
              PrivateData,
 | 
						|
              File->Volume->BlockDeviceNo,
 | 
						|
              File->Volume->RootDirPos + File->CurrentPos,
 | 
						|
              Size,
 | 
						|
              Buffer
 | 
						|
              );
 | 
						|
    File->CurrentPos += (UINT32) Size;
 | 
						|
    return Status;
 | 
						|
 | 
						|
  } else {
 | 
						|
 | 
						|
    if ((File->Attributes & FAT_ATTR_DIRECTORY) == 0) {
 | 
						|
      Size = Size < (File->FileSize - File->CurrentPos) ? Size : (File->FileSize - File->CurrentPos);
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // This is a normal cluster based file
 | 
						|
    //
 | 
						|
    while (Size != 0) {
 | 
						|
      DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);
 | 
						|
      PhysicalAddr  = File->Volume->FirstClusterPos + MultU64x32 (File->Volume->ClusterSize, File->CurrentCluster - 2);
 | 
						|
 | 
						|
      Amount        = File->StraightReadAmount;
 | 
						|
      Amount        = Size > Amount ? Amount : Size;
 | 
						|
      Status = FatReadDisk (
 | 
						|
                PrivateData,
 | 
						|
                File->Volume->BlockDeviceNo,
 | 
						|
                PhysicalAddr + Offset,
 | 
						|
                Amount,
 | 
						|
                BufferPtr
 | 
						|
                );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return EFI_DEVICE_ERROR;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Advance the file's current pos and current cluster
 | 
						|
      //
 | 
						|
      FatSetFilePos (PrivateData, File, (UINT32) Amount);
 | 
						|
 | 
						|
      BufferPtr += Amount;
 | 
						|
      Size -= Amount;
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  This function reads the next item in the parent directory and
 | 
						|
  initializes the output parameter SubFile (CurrentPos is initialized to 0).
 | 
						|
  The function updates the CurrentPos of the parent dir to after the item read.
 | 
						|
  If no more items were found, the function returns EFI_NOT_FOUND.
 | 
						|
 | 
						|
  @param  PrivateData            Global memory map for accessing global variables 
 | 
						|
  @param  ParentDir              The parent directory. 
 | 
						|
  @param  SubFile                The File structure containing the sub file that 
 | 
						|
                                 is caught. 
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The next sub file is obtained. 
 | 
						|
  @retval EFI_INVALID_PARAMETER  The ParentDir is not a directory. 
 | 
						|
  @retval EFI_NOT_FOUND          No more sub file exists. 
 | 
						|
  @retval EFI_DEVICE_ERROR       Something error while accessing media.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatReadNextDirectoryEntry (
 | 
						|
  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
 | 
						|
  IN  PEI_FAT_FILE          *ParentDir,
 | 
						|
  OUT PEI_FAT_FILE          *SubFile
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  FAT_DIRECTORY_ENTRY DirEntry;
 | 
						|
  CHAR16              *Pos;
 | 
						|
  CHAR16              BaseName[9];
 | 
						|
  CHAR16              Ext[4];
 | 
						|
 | 
						|
  ZeroMem ((UINT8 *) SubFile, sizeof (PEI_FAT_FILE));
 | 
						|
 | 
						|
  //
 | 
						|
  // Pick a valid directory entry
 | 
						|
  //
 | 
						|
  while (1) {
 | 
						|
    //
 | 
						|
    // Read one entry
 | 
						|
    //
 | 
						|
    Status = FatReadFile (PrivateData, ParentDir, 32, &DirEntry);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // We only search for *FILE* in root directory
 | 
						|
    // Long file name entry is *NOT* supported
 | 
						|
    //
 | 
						|
    if (((DirEntry.Attributes & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) || (DirEntry.Attributes == FAT_ATTR_LFN)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // if this is a terminator dir entry, just return EFI_NOT_FOUND
 | 
						|
    //
 | 
						|
    if (DirEntry.FileName[0] == EMPTY_ENTRY_MARK) {
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // If this not an invalid entry neither an empty entry, this is what we want.
 | 
						|
    // otherwise we will start a new loop to continue to find something meaningful
 | 
						|
    //
 | 
						|
    if ((UINT8) DirEntry.FileName[0] != DELETE_ENTRY_MARK) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // fill in the output parameter
 | 
						|
  //
 | 
						|
  EngFatToStr (8, DirEntry.FileName, BaseName);
 | 
						|
  EngFatToStr (3, DirEntry.FileName + 8, Ext);
 | 
						|
 | 
						|
  Pos = (UINT16 *) SubFile->FileName;
 | 
						|
  SetMem ((UINT8 *) Pos, FAT_MAX_FILE_NAME_LENGTH, 0);
 | 
						|
  CopyMem ((UINT8 *) Pos, (UINT8 *) BaseName, 2 * (StrLen (BaseName) + 1));
 | 
						|
 | 
						|
  if (Ext[0] != 0) {
 | 
						|
    Pos += StrLen (BaseName);
 | 
						|
    *Pos = '.';
 | 
						|
    Pos++;
 | 
						|
    CopyMem ((UINT8 *) Pos, (UINT8 *) Ext, 2 * (StrLen (Ext) + 1));
 | 
						|
  }
 | 
						|
 | 
						|
  SubFile->Attributes     = DirEntry.Attributes;
 | 
						|
  SubFile->CurrentCluster = DirEntry.FileCluster;
 | 
						|
  if (ParentDir->Volume->FatType == Fat32) {
 | 
						|
    SubFile->CurrentCluster |= DirEntry.FileClusterHigh << 16;
 | 
						|
  }
 | 
						|
 | 
						|
  SubFile->CurrentPos       = 0;
 | 
						|
  SubFile->FileSize         = DirEntry.FileSize;
 | 
						|
  SubFile->StartingCluster  = SubFile->CurrentCluster;
 | 
						|
  SubFile->Volume           = ParentDir->Volume;
 | 
						|
 | 
						|
  //
 | 
						|
  // in Pei phase, time parameters do not need to be filled for minimum use.
 | 
						|
  //
 | 
						|
  return Status;
 | 
						|
}
 |