REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the FatPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
		
			
				
	
	
		
			1415 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1415 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Functions for performing directory entry io.
 | 
						|
 | 
						|
Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Fat.h"
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Get a directory entry from disk for the Ofile.
 | 
						|
 | 
						|
  @param  Parent                - The parent of the OFile which need to update.
 | 
						|
  @param  IoMode                - Indicate whether to read directory entry or write directory entry.
 | 
						|
  @param  EntryPos              - The position of the directory entry to be accessed.
 | 
						|
  @param  Entry                 - The directory entry read or written.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - Access the directory entry successfully.
 | 
						|
  @return other                 - An error occurred when reading the directory entry.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
FatAccessEntry (
 | 
						|
  IN     FAT_OFILE  *Parent,
 | 
						|
  IN     IO_MODE    IoMode,
 | 
						|
  IN     UINTN      EntryPos,
 | 
						|
  IN OUT VOID       *Entry
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN  Position;
 | 
						|
  UINTN  BufferSize;
 | 
						|
 | 
						|
  Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY);
 | 
						|
  if (Position >= Parent->FileSize) {
 | 
						|
    //
 | 
						|
    // End of directory
 | 
						|
    //
 | 
						|
    ASSERT (IoMode == ReadData);
 | 
						|
    ((FAT_DIRECTORY_ENTRY *)Entry)->FileName[0] = EMPTY_ENTRY_MARK;
 | 
						|
    ((FAT_DIRECTORY_ENTRY *)Entry)->Attributes  = 0;
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  BufferSize = sizeof (FAT_DIRECTORY_ENTRY);
 | 
						|
  return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Save the directory entry to disk.
 | 
						|
 | 
						|
  @param  OFile                 - The parent OFile which needs to update.
 | 
						|
  @param  DirEnt                - The directory entry to be saved.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - Store the directory entry successfully.
 | 
						|
  @return other                 - An error occurred when writing the directory entry.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatStoreDirEnt (
 | 
						|
  IN FAT_OFILE   *OFile,
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  FAT_DIRECTORY_LFN  LfnEntry;
 | 
						|
  UINTN              EntryPos;
 | 
						|
  CHAR16             *LfnBufferPointer;
 | 
						|
  CHAR16             LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
 | 
						|
  UINT8              EntryCount;
 | 
						|
  UINT8              LfnOrdinal;
 | 
						|
 | 
						|
  EntryPos   = DirEnt->EntryPos;
 | 
						|
  EntryCount = DirEnt->EntryCount;
 | 
						|
  //
 | 
						|
  // Write directory entry
 | 
						|
  //
 | 
						|
  Status = FatAccessEntry (OFile, WriteData, EntryPos, &DirEnt->Entry);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (--EntryCount > 0) {
 | 
						|
    //
 | 
						|
    // Write LFN directory entry
 | 
						|
    //
 | 
						|
    SetMem (LfnBuffer, sizeof (CHAR16) * LFN_CHAR_TOTAL * EntryCount, 0xff);
 | 
						|
    Status = StrCpyS (
 | 
						|
               LfnBuffer,
 | 
						|
               ARRAY_SIZE (LfnBuffer),
 | 
						|
               DirEnt->FileString
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    LfnBufferPointer    = LfnBuffer;
 | 
						|
    LfnEntry.Attributes = FAT_ATTRIBUTE_LFN;
 | 
						|
    LfnEntry.Type       = 0;
 | 
						|
    LfnEntry.MustBeZero = 0;
 | 
						|
    LfnEntry.Checksum   = FatCheckSum (DirEnt->Entry.FileName);
 | 
						|
    for (LfnOrdinal = 1; LfnOrdinal <= EntryCount; LfnOrdinal++) {
 | 
						|
      LfnEntry.Ordinal = LfnOrdinal;
 | 
						|
      if (LfnOrdinal == EntryCount) {
 | 
						|
        LfnEntry.Ordinal |= FAT_LFN_LAST;
 | 
						|
      }
 | 
						|
 | 
						|
      CopyMem (LfnEntry.Name1, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR1_LEN);
 | 
						|
      LfnBufferPointer += LFN_CHAR1_LEN;
 | 
						|
      CopyMem (LfnEntry.Name2, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR2_LEN);
 | 
						|
      LfnBufferPointer += LFN_CHAR2_LEN;
 | 
						|
      CopyMem (LfnEntry.Name3, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR3_LEN);
 | 
						|
      LfnBufferPointer += LFN_CHAR3_LEN;
 | 
						|
      EntryPos--;
 | 
						|
      if (DirEnt->Invalid) {
 | 
						|
        LfnEntry.Ordinal = DELETE_ENTRY_MARK;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = FatAccessEntry (OFile, WriteData, EntryPos, &LfnEntry);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Determine whether the directory entry is "." or ".." entry.
 | 
						|
 | 
						|
  @param  DirEnt               - The corresponding directory entry.
 | 
						|
 | 
						|
  @retval TRUE                 - The directory entry is "." or ".." directory entry
 | 
						|
  @retval FALSE                - The directory entry is not "." or ".." directory entry
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
FatIsDotDirEnt (
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16  *FileString;
 | 
						|
 | 
						|
  FileString = DirEnt->FileString;
 | 
						|
  if ((StrCmp (FileString, L".") == 0) || (StrCmp (FileString, L"..") == 0)) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Set the OFile's cluster info in its directory entry.
 | 
						|
 | 
						|
  @param  OFile                 - The corresponding OFile.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
FatSetDirEntCluster (
 | 
						|
  IN FAT_OFILE  *OFile
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN       Cluster;
 | 
						|
  FAT_DIRENT  *DirEnt;
 | 
						|
 | 
						|
  DirEnt                        = OFile->DirEnt;
 | 
						|
  Cluster                       = OFile->FileCluster;
 | 
						|
  DirEnt->Entry.FileClusterHigh = (UINT16)(Cluster >> 16);
 | 
						|
  DirEnt->Entry.FileCluster     = (UINT16)Cluster;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Set the OFile's cluster and size info in its directory entry.
 | 
						|
 | 
						|
  @param  OFile                 - The corresponding OFile.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
FatUpdateDirEntClusterSizeInfo (
 | 
						|
  IN FAT_OFILE  *OFile
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (OFile->ODir == NULL);
 | 
						|
  OFile->DirEnt->Entry.FileSize = (UINT32)OFile->FileSize;
 | 
						|
  FatSetDirEntCluster (OFile);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
 | 
						|
 | 
						|
  @param  DirEnt1               - The destination directory entry.
 | 
						|
  @param  DirEnt2               - The source directory entry.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
FatCloneDirEnt (
 | 
						|
  IN  FAT_DIRENT  *DirEnt1,
 | 
						|
  IN  FAT_DIRENT  *DirEnt2
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8  *Entry1;
 | 
						|
  UINT8  *Entry2;
 | 
						|
 | 
						|
  Entry1 = (UINT8 *)&DirEnt1->Entry;
 | 
						|
  Entry2 = (UINT8 *)&DirEnt2->Entry;
 | 
						|
  CopyMem (
 | 
						|
    Entry1 + FAT_ENTRY_INFO_OFFSET,
 | 
						|
    Entry2 + FAT_ENTRY_INFO_OFFSET,
 | 
						|
    sizeof (FAT_DIRECTORY_ENTRY) - FAT_ENTRY_INFO_OFFSET
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Get the LFN for the directory entry.
 | 
						|
 | 
						|
  @param  Parent                - The parent directory.
 | 
						|
  @param  DirEnt                - The directory entry to get LFN.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
FatLoadLongNameEntry (
 | 
						|
  IN FAT_OFILE   *Parent,
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16             LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
 | 
						|
  CHAR16             *LfnBufferPointer;
 | 
						|
  CHAR8              *File8Dot3Name;
 | 
						|
  UINTN              EntryPos;
 | 
						|
  UINT8              LfnOrdinal;
 | 
						|
  UINT8              LfnChecksum;
 | 
						|
  FAT_DIRECTORY_LFN  LfnEntry;
 | 
						|
  EFI_STATUS         Status;
 | 
						|
 | 
						|
  EntryPos         = DirEnt->EntryPos;
 | 
						|
  File8Dot3Name    = DirEnt->Entry.FileName;
 | 
						|
  LfnBufferPointer = LfnBuffer;
 | 
						|
  //
 | 
						|
  // Computes checksum for LFN
 | 
						|
  //
 | 
						|
  LfnChecksum = FatCheckSum (File8Dot3Name);
 | 
						|
  LfnOrdinal  = 1;
 | 
						|
  do {
 | 
						|
    if (EntryPos == 0) {
 | 
						|
      LfnBufferPointer = LfnBuffer;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    EntryPos--;
 | 
						|
    Status = FatAccessEntry (Parent, ReadData, EntryPos, &LfnEntry);
 | 
						|
    if (EFI_ERROR (Status) ||
 | 
						|
        (LfnEntry.Attributes != FAT_ATTRIBUTE_LFN) ||
 | 
						|
        (LfnEntry.MustBeZero != 0) ||
 | 
						|
        (LfnEntry.Checksum != LfnChecksum) ||
 | 
						|
        ((LfnEntry.Ordinal & (~FAT_LFN_LAST)) != LfnOrdinal) ||
 | 
						|
        (LfnOrdinal > MAX_LFN_ENTRIES)
 | 
						|
        )
 | 
						|
    {
 | 
						|
      //
 | 
						|
      // The directory entry does not have a long file name or
 | 
						|
      // some error occurs when loading long file name for a directory entry,
 | 
						|
      // and then we load the long name from short name
 | 
						|
      //
 | 
						|
      LfnBufferPointer = LfnBuffer;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    CopyMem (LfnBufferPointer, LfnEntry.Name1, sizeof (CHAR16) * LFN_CHAR1_LEN);
 | 
						|
    LfnBufferPointer += LFN_CHAR1_LEN;
 | 
						|
    CopyMem (LfnBufferPointer, LfnEntry.Name2, sizeof (CHAR16) * LFN_CHAR2_LEN);
 | 
						|
    LfnBufferPointer += LFN_CHAR2_LEN;
 | 
						|
    CopyMem (LfnBufferPointer, LfnEntry.Name3, sizeof (CHAR16) * LFN_CHAR3_LEN);
 | 
						|
    LfnBufferPointer += LFN_CHAR3_LEN;
 | 
						|
    LfnOrdinal++;
 | 
						|
  } while ((LfnEntry.Ordinal & FAT_LFN_LAST) == 0);
 | 
						|
 | 
						|
  DirEnt->EntryCount = LfnOrdinal;
 | 
						|
  //
 | 
						|
  // Terminate current Lfnbuffer
 | 
						|
  //
 | 
						|
  *LfnBufferPointer = 0;
 | 
						|
  if (LfnBufferPointer == LfnBuffer) {
 | 
						|
    //
 | 
						|
    // Fail to get the long file name from long file name entry,
 | 
						|
    // get the file name from short name
 | 
						|
    //
 | 
						|
    FatGetFileNameViaCaseFlag (
 | 
						|
      DirEnt,
 | 
						|
      LfnBuffer,
 | 
						|
      ARRAY_SIZE (LfnBuffer)
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Add this directory entry node to the list of directory entries and hash table.
 | 
						|
 | 
						|
  @param  ODir                  - The parent OFile which needs to be updated.
 | 
						|
  @param  DirEnt                - The directory entry to be added.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
FatAddDirEnt (
 | 
						|
  IN FAT_ODIR    *ODir,
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (DirEnt->Link.BackLink == NULL) {
 | 
						|
    DirEnt->Link.BackLink = &ODir->ChildList;
 | 
						|
  }
 | 
						|
 | 
						|
  InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link);
 | 
						|
  FatInsertToHashTable (ODir, DirEnt);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Load from disk the next directory entry at current end of directory position.
 | 
						|
 | 
						|
  @param  OFile                 - The parent OFile.
 | 
						|
  @param  PtrDirEnt             - The directory entry that is loaded.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - Load the directory entry successfully.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  - Out of resource.
 | 
						|
  @return other                 - An error occurred when reading the directory entries.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
FatLoadNextDirEnt (
 | 
						|
  IN  FAT_OFILE   *OFile,
 | 
						|
  OUT FAT_DIRENT  **PtrDirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS           Status;
 | 
						|
  FAT_DIRENT           *DirEnt;
 | 
						|
  FAT_ODIR             *ODir;
 | 
						|
  FAT_DIRECTORY_ENTRY  Entry;
 | 
						|
 | 
						|
  ODir = OFile->ODir;
 | 
						|
  //
 | 
						|
  // Make sure the parent's directory has been opened
 | 
						|
  //
 | 
						|
  ASSERT (ODir != NULL);
 | 
						|
  //
 | 
						|
  // Assert we have not reached the end of directory
 | 
						|
  //
 | 
						|
  ASSERT (!ODir->EndOfDir);
 | 
						|
  DirEnt = NULL;
 | 
						|
 | 
						|
  for ( ; ;) {
 | 
						|
    //
 | 
						|
    // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
 | 
						|
    //
 | 
						|
    Status = FatAccessEntry (OFile, ReadData, ODir->CurrentEndPos, &Entry);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if (((UINT8)Entry.FileName[0] != DELETE_ENTRY_MARK) && ((Entry.Attributes & FAT_ATTRIBUTE_VOLUME_ID) == 0)) {
 | 
						|
      //
 | 
						|
      // We get a valid directory entry, then handle it
 | 
						|
      //
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    ODir->CurrentEndPos++;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Entry.FileName[0] != EMPTY_ENTRY_MARK) {
 | 
						|
    //
 | 
						|
    // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications
 | 
						|
    // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.
 | 
						|
    //
 | 
						|
    if (OFile->Volume->FatType != Fat32) {
 | 
						|
      Entry.FileClusterHigh = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // This is a valid directory entry
 | 
						|
    //
 | 
						|
    DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
 | 
						|
    if (DirEnt == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    DirEnt->Signature = FAT_DIRENT_SIGNATURE;
 | 
						|
    //
 | 
						|
    // Remember the directory's entry position on disk
 | 
						|
    //
 | 
						|
    DirEnt->EntryPos = (UINT16)ODir->CurrentEndPos;
 | 
						|
    CopyMem (&DirEnt->Entry, &Entry, sizeof (FAT_DIRECTORY_ENTRY));
 | 
						|
    FatLoadLongNameEntry (OFile, DirEnt);
 | 
						|
    if (DirEnt->FileString == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Add this directory entry to directory
 | 
						|
    //
 | 
						|
    FatAddDirEnt (ODir, DirEnt);
 | 
						|
    //
 | 
						|
    // Point to next directory entry
 | 
						|
    //
 | 
						|
    ODir->CurrentEndPos++;
 | 
						|
  } else {
 | 
						|
    ODir->EndOfDir = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  *PtrDirEnt = DirEnt;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
Done:
 | 
						|
  FatFreeDirEnt (DirEnt);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Get the directory entry's info into Buffer.
 | 
						|
 | 
						|
  @param  Volume                - FAT file system volume.
 | 
						|
  @param  DirEnt                - The corresponding directory entry.
 | 
						|
  @param  BufferSize            - Size of Buffer.
 | 
						|
  @param  Buffer                - Buffer containing file info.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - Get the file info successfully.
 | 
						|
  @retval EFI_BUFFER_TOO_SMALL  - The buffer is too small.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatGetDirEntInfo (
 | 
						|
  IN     FAT_VOLUME  *Volume,
 | 
						|
  IN     FAT_DIRENT  *DirEnt,
 | 
						|
  IN OUT UINTN       *BufferSize,
 | 
						|
  OUT VOID           *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                Size;
 | 
						|
  UINTN                NameSize;
 | 
						|
  UINTN                ResultSize;
 | 
						|
  UINTN                Cluster;
 | 
						|
  EFI_STATUS           Status;
 | 
						|
  EFI_FILE_INFO        *Info;
 | 
						|
  FAT_DIRECTORY_ENTRY  *Entry;
 | 
						|
  FAT_DATE_TIME        FatLastAccess;
 | 
						|
 | 
						|
  ASSERT_VOLUME_LOCKED (Volume);
 | 
						|
 | 
						|
  Size       = SIZE_OF_EFI_FILE_INFO;
 | 
						|
  NameSize   = StrSize (DirEnt->FileString);
 | 
						|
  ResultSize = Size + NameSize;
 | 
						|
 | 
						|
  Status = EFI_BUFFER_TOO_SMALL;
 | 
						|
  if (*BufferSize >= ResultSize) {
 | 
						|
    Status     = EFI_SUCCESS;
 | 
						|
    Entry      = &DirEnt->Entry;
 | 
						|
    Info       = Buffer;
 | 
						|
    Info->Size = ResultSize;
 | 
						|
    if ((Entry->Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
 | 
						|
      Cluster            = (Entry->FileClusterHigh << 16) | Entry->FileCluster;
 | 
						|
      Info->PhysicalSize = FatPhysicalDirSize (Volume, Cluster);
 | 
						|
      Info->FileSize     = Info->PhysicalSize;
 | 
						|
    } else {
 | 
						|
      Info->FileSize     = Entry->FileSize;
 | 
						|
      Info->PhysicalSize = FatPhysicalFileSize (Volume, Entry->FileSize);
 | 
						|
    }
 | 
						|
 | 
						|
    ZeroMem (&FatLastAccess.Time, sizeof (FatLastAccess.Time));
 | 
						|
    CopyMem (&FatLastAccess.Date, &Entry->FileLastAccess, sizeof (FatLastAccess.Date));
 | 
						|
    FatFatTimeToEfiTime (&FatLastAccess, &Info->LastAccessTime);
 | 
						|
    FatFatTimeToEfiTime (&Entry->FileCreateTime, &Info->CreateTime);
 | 
						|
    FatFatTimeToEfiTime (&Entry->FileModificationTime, &Info->ModificationTime);
 | 
						|
    Info->Attribute = Entry->Attributes & EFI_FILE_VALID_ATTR;
 | 
						|
    CopyMem ((CHAR8 *)Buffer + Size, DirEnt->FileString, NameSize);
 | 
						|
  }
 | 
						|
 | 
						|
  *BufferSize = ResultSize;
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Search the directory for the directory entry whose filename is FileNameString.
 | 
						|
 | 
						|
  @param  OFile                 - The parent OFile whose directory is to be searched.
 | 
						|
  @param  FileNameString        - The filename to be searched.
 | 
						|
  @param  PtrDirEnt             - pointer to the directory entry if found.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - Find the directory entry or not found.
 | 
						|
  @return other                 - An error occurred when reading the directory entries.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
FatSearchODir (
 | 
						|
  IN  FAT_OFILE   *OFile,
 | 
						|
  IN  CHAR16      *FileNameString,
 | 
						|
  OUT FAT_DIRENT  **PtrDirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN     PossibleShortName;
 | 
						|
  CHAR8       File8Dot3Name[FAT_NAME_LEN];
 | 
						|
  FAT_ODIR    *ODir;
 | 
						|
  FAT_DIRENT  *DirEnt;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  ODir = OFile->ODir;
 | 
						|
  ASSERT (ODir != NULL);
 | 
						|
  //
 | 
						|
  // Check if the file name is a valid short name
 | 
						|
  //
 | 
						|
  PossibleShortName = FatCheckIs8Dot3Name (FileNameString, File8Dot3Name);
 | 
						|
  //
 | 
						|
  // Search the hash table first
 | 
						|
  //
 | 
						|
  DirEnt = *FatLongNameHashSearch (ODir, FileNameString);
 | 
						|
  if ((DirEnt == NULL) && PossibleShortName) {
 | 
						|
    DirEnt = *FatShortNameHashSearch (ODir, File8Dot3Name);
 | 
						|
  }
 | 
						|
 | 
						|
  if (DirEnt == NULL) {
 | 
						|
    //
 | 
						|
    // We fail to get the directory entry from hash table; we then
 | 
						|
    // search the rest directory
 | 
						|
    //
 | 
						|
    while (!ODir->EndOfDir) {
 | 
						|
      Status = FatLoadNextDirEnt (OFile, &DirEnt);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
 | 
						|
      if (DirEnt != NULL) {
 | 
						|
        if (FatStriCmp (FileNameString, DirEnt->FileString) == 0) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (PossibleShortName && (CompareMem (File8Dot3Name, DirEnt->Entry.FileName, FAT_NAME_LEN) == 0)) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  *PtrDirEnt = DirEnt;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Set the OFile's current directory cursor to the list head.
 | 
						|
 | 
						|
  @param OFile                 - The directory OFile whose directory cursor is reset.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
FatResetODirCursor (
 | 
						|
  IN FAT_OFILE  *OFile
 | 
						|
  )
 | 
						|
{
 | 
						|
  FAT_ODIR  *ODir;
 | 
						|
 | 
						|
  ODir = OFile->ODir;
 | 
						|
  ASSERT (ODir != NULL);
 | 
						|
  ODir->CurrentCursor = &(ODir->ChildList);
 | 
						|
  ODir->CurrentPos    = 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Set the directory's cursor to the next and get the next directory entry.
 | 
						|
 | 
						|
  @param  OFile                 - The parent OFile.
 | 
						|
  @param PtrDirEnt             - The next directory entry.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - We get the next directory entry successfully.
 | 
						|
  @return other                 - An error occurred when get next directory entry.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatGetNextDirEnt (
 | 
						|
  IN  FAT_OFILE   *OFile,
 | 
						|
  OUT FAT_DIRENT  **PtrDirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  FAT_DIRENT  *DirEnt;
 | 
						|
  FAT_ODIR    *ODir;
 | 
						|
 | 
						|
  ODir = OFile->ODir;
 | 
						|
  ASSERT (ODir != NULL);
 | 
						|
  if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
 | 
						|
    //
 | 
						|
    // End of directory, we will try one more time
 | 
						|
    //
 | 
						|
    if (!ODir->EndOfDir) {
 | 
						|
      //
 | 
						|
      // Read directory from disk
 | 
						|
      //
 | 
						|
      Status = FatLoadNextDirEnt (OFile, &DirEnt);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
 | 
						|
    //
 | 
						|
    // End of directory, return NULL
 | 
						|
    //
 | 
						|
    DirEnt           = NULL;
 | 
						|
    ODir->CurrentPos = ODir->CurrentEndPos;
 | 
						|
  } else {
 | 
						|
    ODir->CurrentCursor = ODir->CurrentCursor->ForwardLink;
 | 
						|
    DirEnt              = DIRENT_FROM_LINK (ODir->CurrentCursor);
 | 
						|
    ODir->CurrentPos    = DirEnt->EntryPos + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  *PtrDirEnt = DirEnt;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Set the directory entry count according to the filename.
 | 
						|
 | 
						|
  @param  OFile                 - The corresponding OFile.
 | 
						|
  @param  DirEnt                - The directory entry to be set.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
FatSetEntryCount (
 | 
						|
  IN FAT_OFILE   *OFile,
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16  *FileString;
 | 
						|
  CHAR8   *File8Dot3Name;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get new entry count and set the 8.3 name
 | 
						|
  //
 | 
						|
  DirEnt->EntryCount = 1;
 | 
						|
  FileString         = DirEnt->FileString;
 | 
						|
  File8Dot3Name      = DirEnt->Entry.FileName;
 | 
						|
  SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');
 | 
						|
  if (StrCmp (FileString, L".") == 0) {
 | 
						|
    //
 | 
						|
    // "." entry
 | 
						|
    //
 | 
						|
    File8Dot3Name[0] = '.';
 | 
						|
    FatCloneDirEnt (DirEnt, OFile->DirEnt);
 | 
						|
  } else if (StrCmp (FileString, L"..") == 0) {
 | 
						|
    //
 | 
						|
    // ".." entry
 | 
						|
    //
 | 
						|
    File8Dot3Name[0] = '.';
 | 
						|
    File8Dot3Name[1] = '.';
 | 
						|
    FatCloneDirEnt (DirEnt, OFile->Parent->DirEnt);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Normal name
 | 
						|
    //
 | 
						|
    if (FatCheckIs8Dot3Name (FileString, File8Dot3Name)) {
 | 
						|
      //
 | 
						|
      // This file name is a valid 8.3 file name, we need to further check its case flag
 | 
						|
      //
 | 
						|
      FatSetCaseFlag (DirEnt);
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
 | 
						|
      //
 | 
						|
      FatCreate8Dot3Name (OFile, DirEnt);
 | 
						|
      DirEnt->EntryCount = (UINT8)(LFN_ENTRY_NUMBER (StrLen (FileString)) + DirEnt->EntryCount);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Append a zero cluster to the current OFile.
 | 
						|
 | 
						|
  @param  OFile        - The directory OFile which needs to be updated.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS  - Append a zero cluster to the OFile successfully.
 | 
						|
  @return other        - An error occurred when appending the zero cluster.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
FatExpandODir (
 | 
						|
  IN FAT_OFILE  *OFile
 | 
						|
  )
 | 
						|
{
 | 
						|
  return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Search the Root OFile for the possible volume label.
 | 
						|
 | 
						|
  @param  Root                  - The Root OFile.
 | 
						|
  @param  DirEnt                - The returned directory entry of volume label.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - The search process is completed successfully.
 | 
						|
  @return other                 - An error occurred when searching volume label.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
FatSeekVolumeId (
 | 
						|
  IN  FAT_OFILE   *Root,
 | 
						|
  OUT FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS           Status;
 | 
						|
  UINTN                EntryPos;
 | 
						|
  FAT_DIRECTORY_ENTRY  *Entry;
 | 
						|
 | 
						|
  EntryPos        = 0;
 | 
						|
  Entry           = &DirEnt->Entry;
 | 
						|
  DirEnt->Invalid = TRUE;
 | 
						|
  do {
 | 
						|
    Status = FatAccessEntry (Root, ReadData, EntryPos, Entry);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if (((UINT8)Entry->FileName[0] != DELETE_ENTRY_MARK) && (((Entry->Attributes) & (~FAT_ATTRIBUTE_ARCHIVE)) == FAT_ATTRIBUTE_VOLUME_ID)) {
 | 
						|
      DirEnt->EntryPos   = (UINT16)EntryPos;
 | 
						|
      DirEnt->EntryCount = 1;
 | 
						|
      DirEnt->Invalid    = FALSE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    EntryPos++;
 | 
						|
  } while (Entry->FileName[0] != EMPTY_ENTRY_MARK);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Use First Fit Algorithm to insert directory entry.
 | 
						|
  Only this function will erase "E5" entries in a directory.
 | 
						|
  In view of safest recovery, this function will only be triggered
 | 
						|
  when maximum directory entry number has reached.
 | 
						|
 | 
						|
  @param  OFile                 - The corresponding OFile.
 | 
						|
  @param  DirEnt                - The directory entry to be inserted.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - The directory entry has been successfully inserted.
 | 
						|
  @retval EFI_VOLUME_FULL       - The directory can not hold more directory entries.
 | 
						|
  @return Others                - Some error occurred when inserting new directory entries.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
FatFirstFitInsertDirEnt (
 | 
						|
  IN FAT_OFILE   *OFile,
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  FAT_ODIR    *ODir;
 | 
						|
  LIST_ENTRY  *CurrentEntry;
 | 
						|
  FAT_DIRENT  *CurrentDirEnt;
 | 
						|
  UINT32      CurrentPos;
 | 
						|
  UINT32      LabelPos;
 | 
						|
  UINT32      NewEntryPos;
 | 
						|
  UINT16      EntryCount;
 | 
						|
  FAT_DIRENT  LabelDirEnt;
 | 
						|
 | 
						|
  LabelPos = 0;
 | 
						|
  if (OFile->Parent == NULL) {
 | 
						|
    Status = FatSeekVolumeId (OFile, &LabelDirEnt);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!LabelDirEnt.Invalid) {
 | 
						|
      LabelPos = LabelDirEnt.EntryPos;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  EntryCount  = DirEnt->EntryCount;
 | 
						|
  NewEntryPos = EntryCount;
 | 
						|
  CurrentPos  = 0;
 | 
						|
  ODir        = OFile->ODir;
 | 
						|
  for (CurrentEntry = ODir->ChildList.ForwardLink;
 | 
						|
       CurrentEntry != &ODir->ChildList;
 | 
						|
       CurrentEntry = CurrentEntry->ForwardLink
 | 
						|
       )
 | 
						|
  {
 | 
						|
    CurrentDirEnt = DIRENT_FROM_LINK (CurrentEntry);
 | 
						|
    if (NewEntryPos + CurrentDirEnt->EntryCount <= CurrentDirEnt->EntryPos) {
 | 
						|
      if ((LabelPos > NewEntryPos) || (LabelPos <= CurrentPos)) {
 | 
						|
        //
 | 
						|
        // first fit succeeded
 | 
						|
        //
 | 
						|
        goto Done;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    CurrentPos  = CurrentDirEnt->EntryPos;
 | 
						|
    NewEntryPos = CurrentPos + EntryCount;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NewEntryPos >= ODir->CurrentEndPos) {
 | 
						|
    return EFI_VOLUME_FULL;
 | 
						|
  }
 | 
						|
 | 
						|
Done:
 | 
						|
  DirEnt->EntryPos      = (UINT16)NewEntryPos;
 | 
						|
  DirEnt->Link.BackLink = CurrentEntry;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Find the new directory entry position for the directory entry.
 | 
						|
 | 
						|
  @param  OFile                 - The corresponding OFile.
 | 
						|
  @param  DirEnt                - The directory entry whose new position is to be set.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - The new directory entry position is successfully found.
 | 
						|
  @retval EFI_VOLUME_FULL       - The directory has reach its maximum capacity.
 | 
						|
  @return other                 - An error occurred when reading the directory entry.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
FatNewEntryPos (
 | 
						|
  IN FAT_OFILE   *OFile,
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  FAT_ODIR    *ODir;
 | 
						|
  FAT_DIRENT  *TempDirEnt;
 | 
						|
  UINT32      NewEndPos;
 | 
						|
 | 
						|
  ODir = OFile->ODir;
 | 
						|
  ASSERT (ODir != NULL);
 | 
						|
  //
 | 
						|
  // Make sure the whole directory has been loaded
 | 
						|
  //
 | 
						|
  while (!ODir->EndOfDir) {
 | 
						|
    Status = FatLoadNextDirEnt (OFile, &TempDirEnt);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // We will append this entry to the end of directory
 | 
						|
  //
 | 
						|
  FatGetCurrentFatTime (&DirEnt->Entry.FileCreateTime);
 | 
						|
  CopyMem (&DirEnt->Entry.FileModificationTime, &DirEnt->Entry.FileCreateTime, sizeof (FAT_DATE_TIME));
 | 
						|
  CopyMem (&DirEnt->Entry.FileLastAccess, &DirEnt->Entry.FileCreateTime.Date, sizeof (FAT_DATE));
 | 
						|
  NewEndPos = ODir->CurrentEndPos + DirEnt->EntryCount;
 | 
						|
  if (NewEndPos * sizeof (FAT_DIRECTORY_ENTRY) > OFile->FileSize) {
 | 
						|
    if (NewEndPos >= (OFile->IsFixedRootDir ? OFile->Volume->RootEntries : FAT_MAX_DIRENTRY_COUNT)) {
 | 
						|
      //
 | 
						|
      // We try to use fist fit algorithm to insert this directory entry
 | 
						|
      //
 | 
						|
      return FatFirstFitInsertDirEnt (OFile, DirEnt);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // We should allocate a new cluster for this directory
 | 
						|
    //
 | 
						|
    Status = FatExpandODir (OFile);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // We append our directory entry at the end of directory file
 | 
						|
  //
 | 
						|
  ODir->CurrentEndPos = NewEndPos;
 | 
						|
  DirEnt->EntryPos    = (UINT16)(ODir->CurrentEndPos - 1);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Get the directory entry for the volume.
 | 
						|
 | 
						|
  @param  Volume                - FAT file system volume.
 | 
						|
  @param  Name                  - The file name of the volume.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - Update the volume with the directory entry successfully.
 | 
						|
  @return others                - An error occurred when getting volume label.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatGetVolumeEntry (
 | 
						|
  IN FAT_VOLUME  *Volume,
 | 
						|
  IN CHAR16      *Name
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  FAT_DIRENT  LabelDirEnt;
 | 
						|
 | 
						|
  *Name  = 0;
 | 
						|
  Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    if (!LabelDirEnt.Invalid) {
 | 
						|
      FatNameToStr (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, FALSE, Name);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Set the relevant directory entry into disk for the volume.
 | 
						|
 | 
						|
  @param  Volume              - FAT file system volume.
 | 
						|
  @param  Name                - The new file name of the volume.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS         - Update the Volume successfully.
 | 
						|
  @retval EFI_UNSUPPORTED     - The input label is not a valid volume label.
 | 
						|
  @return other               - An error occurred when setting volume label.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatSetVolumeEntry (
 | 
						|
  IN FAT_VOLUME  *Volume,
 | 
						|
  IN CHAR16      *Name
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  FAT_DIRENT  LabelDirEnt;
 | 
						|
  FAT_OFILE   *Root;
 | 
						|
 | 
						|
  Root   = Volume->Root;
 | 
						|
  Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (LabelDirEnt.Invalid) {
 | 
						|
    //
 | 
						|
    // If there is not the relevant directory entry, create a new one
 | 
						|
    //
 | 
						|
    ZeroMem (&LabelDirEnt, sizeof (FAT_DIRENT));
 | 
						|
    LabelDirEnt.EntryCount = 1;
 | 
						|
    Status                 = FatNewEntryPos (Root, &LabelDirEnt);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    LabelDirEnt.Entry.Attributes = FAT_ATTRIBUTE_VOLUME_ID;
 | 
						|
  }
 | 
						|
 | 
						|
  SetMem (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, ' ');
 | 
						|
  if (FatStrToFat (Name, FAT_NAME_LEN, LabelDirEnt.Entry.FileName)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  FatGetCurrentFatTime (&LabelDirEnt.Entry.FileModificationTime);
 | 
						|
  return FatStoreDirEnt (Root, &LabelDirEnt);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Create "." and ".." directory entries in the newly-created parent OFile.
 | 
						|
 | 
						|
  @param  OFile                 - The parent OFile.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - The dot directory entries are successfully created.
 | 
						|
  @return other                 - An error occurred when creating the directory entry.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatCreateDotDirEnts (
 | 
						|
  IN FAT_OFILE  *OFile
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  FAT_DIRENT  *DirEnt;
 | 
						|
 | 
						|
  Status = FatExpandODir (OFile);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  FatSetDirEntCluster (OFile);
 | 
						|
  //
 | 
						|
  // Create "."
 | 
						|
  //
 | 
						|
  Status = FatCreateDirEnt (OFile, L".", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Create ".."
 | 
						|
  //
 | 
						|
  Status = FatCreateDirEnt (OFile, L"..", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Create a directory entry in the parent OFile.
 | 
						|
 | 
						|
  @param  OFile                 - The parent OFile.
 | 
						|
  @param  FileName              - The filename of the newly-created directory entry.
 | 
						|
  @param  Attributes            - The attribute of the newly-created directory entry.
 | 
						|
  @param  PtrDirEnt             - The pointer to the newly-created directory entry.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - The directory entry is successfully created.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  - Not enough memory to create the directory entry.
 | 
						|
  @return other                 - An error occurred when creating the directory entry.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatCreateDirEnt (
 | 
						|
  IN  FAT_OFILE   *OFile,
 | 
						|
  IN  CHAR16      *FileName,
 | 
						|
  IN  UINT8       Attributes,
 | 
						|
  OUT FAT_DIRENT  **PtrDirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  FAT_DIRENT  *DirEnt;
 | 
						|
  FAT_ODIR    *ODir;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  ASSERT (OFile != NULL);
 | 
						|
  ODir = OFile->ODir;
 | 
						|
  ASSERT (ODir != NULL);
 | 
						|
  DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
 | 
						|
  if (DirEnt == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  DirEnt->Signature  = FAT_DIRENT_SIGNATURE;
 | 
						|
  DirEnt->FileString = AllocateCopyPool (StrSize (FileName), FileName);
 | 
						|
  if (DirEnt->FileString == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Determine how many directory entries we need
 | 
						|
  //
 | 
						|
  FatSetEntryCount (OFile, DirEnt);
 | 
						|
  //
 | 
						|
  // Determine the file's directory entry position
 | 
						|
  //
 | 
						|
  Status = FatNewEntryPos (OFile, DirEnt);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  FatAddDirEnt (ODir, DirEnt);
 | 
						|
  DirEnt->Entry.Attributes = Attributes;
 | 
						|
  *PtrDirEnt               = DirEnt;
 | 
						|
  DEBUG ((DEBUG_INFO, "FSOpen: Created new directory entry '%S'\n", DirEnt->FileString));
 | 
						|
  return FatStoreDirEnt (OFile, DirEnt);
 | 
						|
 | 
						|
Done:
 | 
						|
  FatFreeDirEnt (DirEnt);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Remove this directory entry node from the list of directory entries and hash table.
 | 
						|
 | 
						|
  @param  OFile                - The parent OFile.
 | 
						|
  @param  DirEnt               - The directory entry to be removed.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          - The directory entry is successfully removed.
 | 
						|
  @return other                - An error occurred when removing the directory entry.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatRemoveDirEnt (
 | 
						|
  IN FAT_OFILE   *OFile,
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  FAT_ODIR  *ODir;
 | 
						|
 | 
						|
  ODir = OFile->ODir;
 | 
						|
  if (ODir->CurrentCursor == &DirEnt->Link) {
 | 
						|
    //
 | 
						|
    // Move the directory cursor to its previous directory entry
 | 
						|
    //
 | 
						|
    ODir->CurrentCursor = ODir->CurrentCursor->BackLink;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Remove from directory entry list
 | 
						|
  //
 | 
						|
  RemoveEntryList (&DirEnt->Link);
 | 
						|
  //
 | 
						|
  // Remove from hash table
 | 
						|
  //
 | 
						|
  FatDeleteFromHashTable (ODir, DirEnt);
 | 
						|
  DirEnt->Entry.FileName[0] = DELETE_ENTRY_MARK;
 | 
						|
  DirEnt->Invalid           = TRUE;
 | 
						|
  return FatStoreDirEnt (OFile, DirEnt);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Open the directory entry to get the OFile.
 | 
						|
 | 
						|
  @param  Parent                - The parent OFile.
 | 
						|
  @param  DirEnt                - The directory entry to be opened.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           - The directory entry is successfully opened.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  - not enough memory to allocate a new OFile.
 | 
						|
  @return other                 - An error occurred when opening the directory entry.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatOpenDirEnt (
 | 
						|
  IN FAT_OFILE   *Parent,
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  FAT_OFILE   *OFile;
 | 
						|
  FAT_VOLUME  *Volume;
 | 
						|
 | 
						|
  if (DirEnt->OFile == NULL) {
 | 
						|
    //
 | 
						|
    // Open the directory entry
 | 
						|
    //
 | 
						|
    OFile = AllocateZeroPool (sizeof (FAT_OFILE));
 | 
						|
    if (OFile == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    OFile->Signature = FAT_OFILE_SIGNATURE;
 | 
						|
    InitializeListHead (&OFile->Opens);
 | 
						|
    InitializeListHead (&OFile->ChildHead);
 | 
						|
    OFile->Parent = Parent;
 | 
						|
    OFile->DirEnt = DirEnt;
 | 
						|
    if (Parent != NULL) {
 | 
						|
      //
 | 
						|
      // The newly created OFile is not root
 | 
						|
      //
 | 
						|
      Volume             = Parent->Volume;
 | 
						|
      OFile->FullPathLen = Parent->FullPathLen + 1 + StrLen (DirEnt->FileString);
 | 
						|
      OFile->FileCluster = ((DirEnt->Entry.FileClusterHigh) << 16) | (DirEnt->Entry.FileCluster);
 | 
						|
      InsertTailList (&Parent->ChildHead, &OFile->ChildLink);
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // The newly created OFile is root
 | 
						|
      //
 | 
						|
      Volume             = VOLUME_FROM_ROOT_DIRENT (DirEnt);
 | 
						|
      Volume->Root       = OFile;
 | 
						|
      OFile->FileCluster = Volume->RootCluster;
 | 
						|
      if (Volume->FatType  != Fat32) {
 | 
						|
        OFile->IsFixedRootDir = TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    OFile->FileCurrentCluster = OFile->FileCluster;
 | 
						|
    OFile->Volume             = Volume;
 | 
						|
    InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);
 | 
						|
 | 
						|
    OFile->FileSize = DirEnt->Entry.FileSize;
 | 
						|
    if ((DirEnt->Entry.Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
 | 
						|
      if (OFile->IsFixedRootDir) {
 | 
						|
        OFile->FileSize = Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY);
 | 
						|
      } else {
 | 
						|
        OFile->FileSize = FatPhysicalDirSize (Volume, OFile->FileCluster);
 | 
						|
      }
 | 
						|
 | 
						|
      FatRequestODir (OFile);
 | 
						|
      if (OFile->ODir == NULL) {
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    DirEnt->OFile = OFile;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Close the directory entry and free the OFile.
 | 
						|
 | 
						|
  @param  DirEnt               - The directory entry to be closed.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
FatCloseDirEnt (
 | 
						|
  IN FAT_DIRENT  *DirEnt
 | 
						|
  )
 | 
						|
{
 | 
						|
  FAT_OFILE   *OFile;
 | 
						|
  FAT_VOLUME  *Volume;
 | 
						|
 | 
						|
  OFile = DirEnt->OFile;
 | 
						|
  ASSERT (OFile != NULL);
 | 
						|
  Volume = OFile->Volume;
 | 
						|
 | 
						|
  if (OFile->ODir != NULL) {
 | 
						|
    FatDiscardODir (OFile);
 | 
						|
  }
 | 
						|
 | 
						|
  if (OFile->Parent == NULL) {
 | 
						|
    Volume->Root = NULL;
 | 
						|
  } else {
 | 
						|
    RemoveEntryList (&OFile->ChildLink);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (OFile);
 | 
						|
  DirEnt->OFile = NULL;
 | 
						|
  if (DirEnt->Invalid == TRUE) {
 | 
						|
    //
 | 
						|
    // Free directory entry itself
 | 
						|
    //
 | 
						|
    FatFreeDirEnt (DirEnt);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Traverse filename and open all OFiles that can be opened.
 | 
						|
  Update filename pointer to the component that can't be opened.
 | 
						|
  If more than one name component remains, returns an error;
 | 
						|
  otherwise, return the remaining name component so that the caller might choose to create it.
 | 
						|
 | 
						|
  @param  PtrOFile              - As input, the reference OFile; as output, the located OFile.
 | 
						|
  @param  FileName              - The file name relevant to the OFile.
 | 
						|
  @param  Attributes            - The attribute of the destination OFile.
 | 
						|
  @param  NewFileName           - The remaining file name.
 | 
						|
 | 
						|
  @retval EFI_NOT_FOUND         - The file name can't be opened and there is more than one
 | 
						|
                          components within the name left (this means the name can
 | 
						|
                          not be created either).
 | 
						|
  @retval EFI_INVALID_PARAMETER - The parameter is not valid.
 | 
						|
  @retval EFI_SUCCESS           - Open the file successfully.
 | 
						|
  @return other                 - An error occurred when locating the OFile.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FatLocateOFile (
 | 
						|
  IN OUT FAT_OFILE  **PtrOFile,
 | 
						|
  IN     CHAR16     *FileName,
 | 
						|
  IN     UINT8      Attributes,
 | 
						|
  OUT CHAR16        *NewFileName
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  FAT_VOLUME  *Volume;
 | 
						|
  CHAR16      ComponentName[EFI_PATH_STRING_LENGTH];
 | 
						|
  UINTN       FileNameLen;
 | 
						|
  BOOLEAN     DirIntended;
 | 
						|
  CHAR16      *Next;
 | 
						|
  FAT_OFILE   *OFile;
 | 
						|
  FAT_DIRENT  *DirEnt;
 | 
						|
 | 
						|
  DirEnt = NULL;
 | 
						|
 | 
						|
  FileNameLen = StrLen (FileName);
 | 
						|
  if (FileNameLen == 0) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  OFile  = *PtrOFile;
 | 
						|
  Volume = OFile->Volume;
 | 
						|
 | 
						|
  DirIntended = FALSE;
 | 
						|
  if (FileName[FileNameLen - 1] == PATH_NAME_SEPARATOR) {
 | 
						|
    DirIntended = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If name starts with path name separator, then move to root OFile
 | 
						|
  //
 | 
						|
  if (*FileName == PATH_NAME_SEPARATOR) {
 | 
						|
    OFile = Volume->Root;
 | 
						|
    FileName++;
 | 
						|
    FileNameLen--;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Per FAT Spec the file name should meet the following criteria:
 | 
						|
  //   C1. Length (FileLongName) <= 255
 | 
						|
  //   C2. Length (X:FileFullPath<NUL>) <= 260
 | 
						|
  // Here we check C2 first.
 | 
						|
  //
 | 
						|
  if (2 + OFile->FullPathLen + 1 + FileNameLen + 1 > EFI_PATH_STRING_LENGTH) {
 | 
						|
    //
 | 
						|
    // Full path length can not surpass 256
 | 
						|
    //
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Start at current location
 | 
						|
  //
 | 
						|
  Next = FileName;
 | 
						|
  for ( ; ;) {
 | 
						|
    //
 | 
						|
    // Get the next component name
 | 
						|
    //
 | 
						|
    FileName = Next;
 | 
						|
    Next     = FatGetNextNameComponent (FileName, ComponentName);
 | 
						|
 | 
						|
    //
 | 
						|
    // If end of the file name, we're done
 | 
						|
    //
 | 
						|
    if (ComponentName[0] == 0) {
 | 
						|
      if (DirIntended && (OFile->ODir == NULL)) {
 | 
						|
        return EFI_NOT_FOUND;
 | 
						|
      }
 | 
						|
 | 
						|
      NewFileName[0] = 0;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // If "dot", then current
 | 
						|
    //
 | 
						|
    if (StrCmp (ComponentName, L".") == 0) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // If "dot dot", then parent
 | 
						|
    //
 | 
						|
    if (StrCmp (ComponentName, L"..") == 0) {
 | 
						|
      if (OFile->Parent == NULL) {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      OFile = OFile->Parent;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!FatFileNameIsValid (ComponentName, NewFileName)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // We have a component name, try to open it
 | 
						|
    //
 | 
						|
    if (OFile->ODir == NULL) {
 | 
						|
      //
 | 
						|
      // This file isn't a directory, can't open it
 | 
						|
      //
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Search the compName in the directory
 | 
						|
    //
 | 
						|
    Status = FatSearchODir (OFile, NewFileName, &DirEnt);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if (DirEnt == NULL) {
 | 
						|
      //
 | 
						|
      // component name is not found in the directory
 | 
						|
      //
 | 
						|
      if (*Next != 0) {
 | 
						|
        return EFI_NOT_FOUND;
 | 
						|
      }
 | 
						|
 | 
						|
      if (DirIntended && ((Attributes & FAT_ATTRIBUTE_DIRECTORY) == 0)) {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // It's the last component name - return with the open
 | 
						|
      // path and the remaining name
 | 
						|
      //
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = FatOpenDirEnt (OFile, DirEnt);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    OFile = DirEnt->OFile;
 | 
						|
  }
 | 
						|
 | 
						|
  *PtrOFile = OFile;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |