Преглед на файлове

Add EDK II Prime FatPkg New Feature: Support both Unicode Collation and Unicode Collation 2 Protocols Support both Component Name and Component Name 2 Protocol.

(based on FatPkg commit e51cd032db84a6fb1f44a0605f80d96f5fdf4bc6)

[jordan.l.justen@intel.com: Use script to relicense to 2-clause BSD]
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Acked-by: Mark Doran <mark.doran@intel.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Qing Huang преди 16 години
родител
ревизия
b9ec93308b

+ 355 - 0
FatPkg/EnhancedFatDxe/ComponentName.c

@@ -0,0 +1,355 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  ComponentName.c
+
+Abstract:
+
+--*/
+
+#include "Fat.h"
+
+//
+// EFI Component Name Functions
+//
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 3066 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+FatComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  );
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 3066 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+FatComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  );
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gFatComponentName = {
+  FatComponentNameGetDriverName,
+  FatComponentNameGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gFatComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) FatComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) FatComponentNameGetControllerName,
+  "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFatDriverNameTable[] = {
+  {
+    "eng;en",
+    L"FAT File System Driver"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFatControllerNameTable[] = {
+  {
+    "eng;en",
+    L"FAT File System"
+  },
+  {
+    NULL,
+    NULL
+  }
+};
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the driver.
+
+  This function retrieves the user readable name of a driver in the form of a
+  Unicode string. If the driver specified by This has a user readable name in
+  the language specified by Language, then a pointer to the driver name is
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+  by This does not support the language specified by Language,
+  then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language. This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified
+                                in RFC 3066 or ISO 639-2 language code format.
+
+  @param  DriverName[out]       A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                driver specified by This in the language
+                                specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by
+                                This and the language specified by Language was
+                                returned in DriverName.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+FatComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mFatDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gFatComponentName)
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by a driver.
+
+  This function retrieves the user readable name of the controller specified by
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the
+  driver specified by This has a user readable name in the language specified by
+  Language, then a pointer to the controller name is returned in ControllerName,
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently
+  managing the controller specified by ControllerHandle and ChildHandle,
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  The handle of a controller that the driver
+                                specified by This is managing.  This handle
+                                specifies the controller whose name is to be
+                                returned.
+
+  @param  ChildHandle[in]       The handle of the child controller to retrieve
+                                the name of.  This is an optional parameter that
+                                may be NULL.  It will be NULL for device
+                                drivers.  It will also be NULL for a bus drivers
+                                that wish to retrieve the name of the bus
+                                controller.  It will not be NULL for a bus
+                                driver that wishes to retrieve the name of a
+                                child controller.
+
+  @param  Language[in]          A pointer to a Null-terminated ASCII string
+                                array indicating the language.  This is the
+                                language of the driver name that the caller is
+                                requesting, and it must match one of the
+                                languages specified in SupportedLanguages. The
+                                number of languages supported by a driver is up
+                                to the driver writer. Language is specified in
+                                RFC 3066 or ISO 639-2 language code format.
+
+  @param  ControllerName[out]   A pointer to the Unicode string to return.
+                                This Unicode string is the name of the
+                                controller specified by ControllerHandle and
+                                ChildHandle in the language specified by
+                                Language from the point of view of the driver
+                                specified by This.
+
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in
+                                the language specified by Language for the
+                                driver specified by This was returned in
+                                DriverName.
+
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                EFI_HANDLE.
+
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently
+                                managing the controller specified by
+                                ControllerHandle and ChildHandle.
+
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support
+                                the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+FatComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Make sure this driver is currently managing ControllHandle
+  //
+  Status = EfiTestManagedDevice (
+             ControllerHandle,
+             gFatDriverBinding.DriverBindingHandle,
+             &gEfiDiskIoProtocolGuid
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mFatControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gFatComponentName)
+           );
+}

+ 50 - 0
FatPkg/EnhancedFatDxe/Data.c

@@ -0,0 +1,50 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  Data.c
+
+Abstract:
+
+  Global data in the FAT Filesystem driver
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+//
+// Globals
+//
+//
+// FatFsLock - Global lock for synchronizing all requests.
+//
+EFI_LOCK FatFsLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_CALLBACK);
+
+//
+// Filesystem interface functions
+//
+EFI_FILE                        FatFileInterface = {
+  EFI_FILE_PROTOCOL_REVISION,
+  FatOpen,
+  FatClose,
+  FatDelete,
+  FatRead,
+  FatWrite,
+  FatGetPosition,
+  FatSetPosition,
+  FatGetInfo,
+  FatSetInfo,
+  FatFlush
+};

+ 80 - 0
FatPkg/EnhancedFatDxe/Debug.c

@@ -0,0 +1,80 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  debug.c
+
+Abstract:
+
+  Debug functions for fat driver
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+VOID
+FatDumpFatTable (
+  IN FAT_VOLUME   *Volume
+  )
+/*++
+
+Routine Description:
+
+  Dump all the FAT Entry of the FAT table in the volume
+
+Arguments:
+
+  Volume - The volume whose FAT info will be dumped
+
+Returns:
+
+  None
+
+--*/
+{
+  UINTN   EntryValue;
+  UINTN   MaxIndex;
+  UINTN   Index;
+  CHAR16  *Pointer;
+
+  MaxIndex = Volume->MaxCluster + 2;
+
+  Print (L"Dump of Fat Table, MaxCluster %x\n", MaxIndex);
+  for (Index = 0; Index < MaxIndex; Index++) {
+    EntryValue = FatGetFatEntry (Volume, Index);
+    if (EntryValue != FAT_CLUSTER_FREE) {
+      Pointer = NULL;
+      switch (EntryValue) {
+      case FAT_CLUSTER_RESERVED:
+        Pointer = L"RESREVED";
+        break;
+
+      case FAT_CLUSTER_BAD:
+        Pointer = L"BAD";
+        break;
+      }
+
+      if (FAT_END_OF_FAT_CHAIN (EntryValue)) {
+        Pointer = L"LAST";
+      }
+
+      if (Pointer != NULL) {
+        Print (L"Entry %x = %s\n", Index, Pointer);
+      } else {
+        Print (L"Entry %x = %x\n", Index, EntryValue);
+      }
+    }
+  }
+}

+ 138 - 0
FatPkg/EnhancedFatDxe/Delete.c

@@ -0,0 +1,138 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  delete.c
+
+Abstract:
+
+  Function that deletes a file
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatDelete (
+  IN EFI_FILE  *FHand
+  )
+/*++
+
+Routine Description:
+
+  Deletes the file & Closes the file handle.
+
+Arguments:
+
+  FHand                    - Handle to the file to delete.
+
+Returns:
+
+  EFI_SUCCESS              - Delete the file successfully.
+  EFI_WARN_DELETE_FAILURE  - Fail to delete the file.
+
+--*/
+{
+  FAT_IFILE   *IFile;
+  FAT_OFILE   *OFile;
+  FAT_DIRENT  *DirEnt;
+  EFI_STATUS  Status;
+  UINTN       Round;
+
+  IFile = IFILE_FROM_FHAND (FHand);
+  OFile = IFile->OFile;
+
+  //
+  // Lock the volume
+  //
+  FatAcquireLock ();
+
+  //
+  // If the file is read-only, then don't delete it
+  //
+  if (IFile->ReadOnly) {
+    Status = EFI_WRITE_PROTECTED;
+    goto Done;
+  }
+  //
+  // If the file is the root dir, then don't delete it
+  //
+  if (OFile->Parent == NULL) {
+    Status = EFI_ACCESS_DENIED;
+    goto Done;
+  }
+  //
+  // If the file has a permanant error, skip the delete
+  //
+  Status = OFile->Error;
+  if (!EFI_ERROR (Status)) {
+    //
+    // If this is a directory, make sure it's empty before
+    // allowing it to be deleted
+    //
+    if (OFile->ODir != NULL) {
+      //
+      // We do not allow to delete nonempty directory
+      //
+      FatResetODirCursor (OFile);
+      for (Round = 0; Round < 3; Round++) {
+        Status = FatGetNextDirEnt (OFile, &DirEnt);
+        if ((EFI_ERROR (Status)) ||
+            ((Round < 2) && (DirEnt == NULL || !FatIsDotDirEnt (DirEnt))) ||
+            ((Round == 2) && (DirEnt != NULL))
+            ) {
+          Status = EFI_ACCESS_DENIED;
+          goto Done;
+        }
+      }
+    }
+    //
+    // Return the file's space by setting its size to 0
+    //
+    FatTruncateOFile (OFile, 0);
+    //
+    // Free the directory entry for this file
+    //
+    Status = FatRemoveDirEnt (OFile->Parent, OFile->DirEnt);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+    //
+    // Set a permanent error for this OFile in case there
+    // are still opened IFiles attached
+    //
+    OFile->Error = EFI_NOT_FOUND;
+  } else if (OFile->Error == EFI_NOT_FOUND) {
+    Status = EFI_SUCCESS;
+  }
+
+Done:
+  //
+  // Always close the handle
+  //
+  FatIFileClose (IFile);
+  //
+  // Done
+  //
+  Status = FatCleanupVolume (OFile->Volume, NULL, Status);
+  FatReleaseLock ();
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_WARN_DELETE_FAILURE;
+  }
+
+  return Status;
+}

+ 238 - 0
FatPkg/EnhancedFatDxe/DirectoryCache.c

@@ -0,0 +1,238 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  DirectoryCache.c
+
+Abstract:
+
+  Functions for directory cache operation
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+STATIC
+VOID
+FatFreeODir (
+  IN FAT_ODIR    *ODir
+  )
+/*++
+
+Routine Description:
+
+  Free the directory structure and release the memory.
+
+Arguments:
+
+  ODir                  - The directory to be freed.
+
+Returns:
+
+  None.
+
+--*/
+{
+  FAT_DIRENT  *DirEnt;
+
+  //
+  // Release Directory Entry Nodes
+  //
+  while (!IsListEmpty (&ODir->ChildList)) {
+    DirEnt = DIRENT_FROM_LINK (ODir->ChildList.ForwardLink);
+    RemoveEntryList (&DirEnt->Link);
+    //
+    // Make sure the OFile has been closed
+    //
+    ASSERT (DirEnt->OFile == NULL);
+    FatFreeDirEnt (DirEnt);
+  }
+
+  FreePool (ODir);
+}
+
+STATIC
+FAT_ODIR *
+FatAllocateODir (
+  IN FAT_OFILE   *OFile
+  )
+/*++
+
+Routine Description:
+
+  Allocate the directory structure.
+
+Arguments:
+
+  OFile                   - The corresponding OFile.
+
+Returns:
+
+  None.
+
+--*/
+{
+  FAT_ODIR  *ODir;
+
+  ODir = AllocateZeroPool (sizeof (FAT_ODIR));
+  if (ODir != NULL) {
+    //
+    // Initialize the directory entry list
+    //
+    ODir->Signature = FAT_ODIR_SIGNATURE;
+    InitializeListHead (&ODir->ChildList);
+    ODir->CurrentCursor = &ODir->ChildList;
+  }
+
+  return ODir;
+}
+
+VOID
+FatDiscardODir (
+  IN FAT_OFILE    *OFile
+  )
+/*++
+
+Routine Description:
+
+  Discard the directory structure when an OFile will be freed.
+  Volume will cache this directory if the OFile does not represent a deleted file.
+
+Arguments:
+
+  OFile                 - The OFile whose directory structure is to be discarded.
+
+Returns:
+
+  None.
+
+--*/
+{
+  FAT_ODIR    *ODir;
+  FAT_VOLUME  *Volume;
+
+  Volume  = OFile->Volume;
+  ODir    = OFile->ODir;
+  if (!OFile->DirEnt->Invalid) {
+    //
+    // If OFile does not represent a deleted file, then we will cache the directory
+    // We use OFile's first cluster as the directory's tag
+    //
+    ODir->DirCacheTag = OFile->FileCluster;
+    InsertHeadList (&Volume->DirCacheList, &ODir->DirCacheLink);
+    if (Volume->DirCacheCount == FAT_MAX_DIR_CACHE_COUNT) {
+      //
+      // Replace the least recent used directory
+      //
+      ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);
+      RemoveEntryList (&ODir->DirCacheLink);
+    } else {
+      //
+      // No need to find a replace
+      //
+      Volume->DirCacheCount++;
+      ODir = NULL;
+    }
+  }
+  //
+  // Release ODir Structure
+  //
+  if (ODir != NULL) {
+    FatFreeODir (ODir);
+  }
+}
+
+VOID
+FatRequestODir (
+  IN FAT_OFILE    *OFile
+  )
+/*++
+
+Routine Description:
+
+  Request the directory structure when an OFile is newly generated.
+  If the directory structure is cached by volume, then just return this directory;
+  Otherwise, allocate a new one for OFile.
+
+Arguments:
+
+  OFile                 - The OFile which requests directory structure.
+
+Returns:
+
+  None.
+
+--*/
+{
+  UINTN           DirCacheTag;
+  FAT_VOLUME      *Volume;
+  FAT_ODIR        *ODir;
+  FAT_ODIR        *CurrentODir;
+  LIST_ENTRY      *CurrentODirLink;
+
+  Volume      = OFile->Volume;
+  ODir        = NULL;
+  DirCacheTag = OFile->FileCluster;
+  for (CurrentODirLink  = Volume->DirCacheList.ForwardLink;
+       CurrentODirLink != &Volume->DirCacheList;
+       CurrentODirLink  = CurrentODirLink->ForwardLink
+      ) {
+    CurrentODir = ODIR_FROM_DIRCACHELINK (CurrentODirLink);
+    if (CurrentODir->DirCacheTag == DirCacheTag) {
+      RemoveEntryList (&CurrentODir->DirCacheLink);
+      Volume->DirCacheCount--;
+      ODir = CurrentODir;
+      break;
+    }
+  }
+
+  if (ODir == NULL) {
+    //
+    // This directory is not cached, then allocate a new one
+    //
+    ODir = FatAllocateODir (OFile);
+  }
+
+  OFile->ODir = ODir;
+}
+
+VOID
+FatCleanupODirCache (
+  IN FAT_VOLUME         *Volume
+  )
+/*++
+
+Routine Description:
+
+  Clean up all the cached directory structures when the volume is going to be abandoned.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+
+Returns:
+
+  None.
+
+--*/
+{
+  FAT_ODIR  *ODir;
+  while (Volume->DirCacheCount > 0) {
+    ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);
+    RemoveEntryList (&ODir->DirCacheLink);
+    FatFreeODir (ODir);
+    Volume->DirCacheCount--;
+  }
+}

+ 1563 - 0
FatPkg/EnhancedFatDxe/DirectoryManage.c

@@ -0,0 +1,1563 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  DirectoryManage.c
+
+Abstract:
+
+  Functions for performing directory entry io
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+STATIC
+EFI_STATUS
+FatAccessEntry (
+  IN     FAT_OFILE            *Parent,
+  IN     IO_MODE              IoMode,
+  IN     UINTN                EntryPos,
+  IN OUT VOID                 *Entry
+  )
+/*++
+
+Routine Description:
+
+  Get a directory entry from disk for the Ofile.
+
+Arguments:
+
+  Parent                - The parent of the OFile which need to update.
+  IoMode                - Indicate whether to read directory entry or write directroy entry.
+  EntryPos              - The position of the directory entry to be accessed.
+  Entry                 - The directory entry read or written.
+
+Returns:
+
+  EFI_SUCCESS           - Access the directory entry sucessfully.
+  other                 - An error occurred when reading the directory entry.
+
+--*/
+{
+  UINTN Position;
+  UINTN BufferSize;
+
+  Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY);
+  if (Position >= Parent->FileSize) {
+    //
+    // End of directory
+    //
+    ASSERT (IoMode == READ_DATA);
+    ((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);
+}
+
+EFI_STATUS
+FatStoreDirEnt (
+  IN FAT_OFILE            *OFile,
+  IN FAT_DIRENT           *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Save the directory entry to disk.
+
+Arguments:
+
+  OFile                 - The parent OFile which needs to update.
+  DirEnt                - The directory entry to be saved.
+
+Returns:
+
+  EFI_SUCCESS           - Store the directory entry successfully.
+  other                 - An error occurred when writing the directory entry.
+
+--*/
+{
+  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, WRITE_DATA, 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);
+    StrCpy (LfnBuffer, DirEnt->FileString);
+    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, WRITE_DATA, EntryPos, &LfnEntry);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+BOOLEAN
+FatIsDotDirEnt (
+  IN FAT_DIRENT  *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Determine whether the directory entry is "." or ".." entry.
+
+Arguments:
+
+  DirEnt               - The corresponding directory entry.
+
+Returns:
+
+  TRUE                 - The directory entry is "." or ".." directory entry
+  FALSE                - The directory entry is not "." or ".." directory entry
+
+--*/
+{
+  CHAR16  *FileString;
+  FileString = DirEnt->FileString;
+  if (StrCmp (FileString, L".") == 0 || StrCmp (FileString, L"..") == 0) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+STATIC
+VOID
+FatSetDirEntCluster (
+  IN FAT_OFILE    *OFile
+  )
+/*++
+
+Routine Description:
+
+  Set the OFile's cluster info in its directory entry.
+
+Arguments:
+
+  OFile                 - The corresponding OFile.
+
+Returns:
+
+  None.
+
+--*/
+{
+  UINTN       Cluster;
+  FAT_DIRENT  *DirEnt;
+
+  DirEnt                        = OFile->DirEnt;
+  Cluster                       = OFile->FileCluster;
+  DirEnt->Entry.FileClusterHigh = (UINT16) (Cluster >> 16);
+  DirEnt->Entry.FileCluster     = (UINT16) Cluster;
+}
+
+VOID
+FatUpdateDirEntClusterSizeInfo (
+  IN FAT_OFILE    *OFile
+  )
+/*++
+
+Routine Description:
+
+  Set the OFile's cluster and size info in its directory entry.
+
+Arguments:
+
+  OFile                 - The corresponding OFile.
+
+Returns:
+
+  None.
+
+--*/
+{
+  ASSERT (OFile->ODir == NULL);
+  OFile->DirEnt->Entry.FileSize = (UINT32) OFile->FileSize;
+  FatSetDirEntCluster (OFile);
+}
+
+VOID
+FatCloneDirEnt (
+  IN  FAT_DIRENT          *DirEnt1,
+  IN  FAT_DIRENT          *DirEnt2
+  )
+/*++
+
+Routine Description:
+
+  Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
+
+Arguments:
+
+  DirEnt1               - The destination directory entry.
+  DirEnt2               - The source directory entry.
+
+Returns:
+
+  None.
+
+--*/
+{
+  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
+    );
+}
+
+STATIC
+VOID
+FatLoadLongNameEntry (
+  IN FAT_OFILE           *Parent,
+  IN FAT_DIRENT          *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Get the LFN for the directory entry.
+
+Arguments:
+
+  Parent                - The parent directory.
+  DirEnt                - The directory entry to get LFN.
+
+Returns:
+
+  None.
+
+--*/
+{
+  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, READ_DATA, 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);
+  }
+
+  DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer);
+}
+
+STATIC
+VOID
+FatAddDirEnt (
+  IN FAT_ODIR             *ODir,
+  IN FAT_DIRENT           *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Add this directory entry node to the list of directory entries and hash table.
+
+Arguments:
+
+  ODir                  - The parent OFile which needs to be updated.
+  DirEnt                - The directory entry to be added.
+
+Returns:
+
+  None.
+
+--*/
+{
+  if (DirEnt->Link.BackLink == NULL) {
+    DirEnt->Link.BackLink = &ODir->ChildList;
+  }
+  InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link);
+  FatInsertToHashTable (ODir, DirEnt);
+}
+
+STATIC
+EFI_STATUS
+FatLoadNextDirEnt (
+  IN  FAT_OFILE           *OFile,
+  OUT FAT_DIRENT          **PtrDirEnt
+  )
+/*++
+
+Routine Description:
+
+  Load from disk the next directory entry at current end of directory position
+
+Arguments:
+
+  OFile                 - The parent OFile.
+  PtrDirEnt             - The directory entry that is loaded.
+
+Returns:
+
+  EFI_SUCCESS           - Load the directory entry successfully.
+  EFI_OUT_OF_RESOURCES  - Out of resource.
+  other                 - An error occurred when reading the directory entries.
+
+--*/
+{
+  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, READ_DATA, 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;
+}
+
+EFI_STATUS
+FatGetDirEntInfo (
+  IN     FAT_VOLUME         *Volume,
+  IN     FAT_DIRENT         *DirEnt,
+  IN OUT UINTN              *BufferSize,
+     OUT VOID               *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the directory entry's info into Buffer.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  DirEnt                - The corresponding directory entry.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing file info.
+
+Returns:
+
+  EFI_SUCCESS           - Get the file info successfully.
+  EFI_BUFFER_TOO_SMALL  - The buffer is too small.
+
+--*/
+{
+  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;
+}
+
+STATIC
+EFI_STATUS
+FatSearchODir (
+  IN  FAT_OFILE      *OFile,
+  IN  CHAR16         *FileNameString,
+  OUT FAT_DIRENT     **PtrDirEnt
+  )
+/*++
+
+Routine Description:
+
+  Search the directory for the directory entry whose filename is FileNameString.
+
+Arguments:
+
+  OFile                 - The parent OFile whose directory is to be searched.
+  FileNameString        - The filename to be searched.
+  PtrDirEnt             - pointer to the directory entry if found.
+
+Returns:
+
+  EFI_SUCCESS           - Find the directory entry or not found.
+  other                 - An error occurred when reading the directory entries.
+
+--*/
+{
+  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;
+}
+
+VOID
+FatResetODirCursor (
+  IN FAT_OFILE    *OFile
+  )
+/*++
+
+Routine Description:
+
+  Set the OFile's current directory cursor to the list head.
+
+Arguments:
+
+  OFile                 - The directory OFile whose directory cursor is reset.
+
+Returns:
+
+  None.
+
+--*/
+{
+  FAT_ODIR  *ODir;
+
+  ODir = OFile->ODir;
+  ASSERT (ODir != NULL);
+  ODir->CurrentCursor = &(ODir->ChildList);
+  ODir->CurrentPos    = 0;
+}
+
+EFI_STATUS
+FatGetNextDirEnt (
+  IN  FAT_OFILE     *OFile,
+  OUT FAT_DIRENT    **PtrDirEnt
+  )
+/*++
+
+Routine Description:
+
+  Set the directory’s cursor to the next and get the next directory entry.
+
+Arguments:
+
+  OFile                 - The parent OFile.
+  PtrDirEnt             - The next directory entry.
+
+Returns:
+
+  EFI_SUCCESS           - We get the next directory entry successfully.
+  other                 - An error occurred when get next directory entry.
+
+--*/
+{
+  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;
+}
+
+STATIC
+VOID
+FatSetEntryCount (
+  IN FAT_OFILE    *OFile,
+  IN FAT_DIRENT   *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Set the directory entry count according to the filename.
+
+Arguments:
+
+  OFile                 - The corresponding OFile.
+  DirEnt                - The directory entry to be set.
+
+Returns:
+
+  None.
+
+--*/
+{
+  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);
+    }
+  }
+}
+
+STATIC
+EFI_STATUS
+FatExpandODir (
+  IN FAT_OFILE  *OFile
+  )
+/*++
+
+Routine Description:
+
+  Append a zero cluster to the current OFile.
+
+Arguments:
+
+  OFile        - The directory OFile which needs to be updated.
+
+Returns:
+
+  EFI_SUCCESS  - Append a zero cluster to the OFile successfully.
+  other        - An error occurred when appending the zero cluster.
+
+--*/
+{
+  return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);
+}
+
+STATIC
+EFI_STATUS
+FatSeekVolumeId (
+  IN  FAT_OFILE            *Root,
+  OUT FAT_DIRENT           *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Search the Root OFile for the possible volume label.
+
+Arguments:
+
+  Root                  - The Root OFile.
+  DirEnt                - The returned directory entry of volume label.
+
+Returns:
+
+  EFI_SUCCESS           - The search process is completed successfully.
+  other                 - An error occurred when searching volume label.
+
+--*/
+{
+  EFI_STATUS          Status;
+  UINTN               EntryPos;
+  FAT_DIRECTORY_ENTRY *Entry;
+
+  EntryPos        = 0;
+  Entry           = &DirEnt->Entry;
+  DirEnt->Invalid = TRUE;
+  do {
+    Status = FatAccessEntry (Root, READ_DATA, 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;
+}
+
+STATIC
+EFI_STATUS
+FatFirstFitInsertDirEnt (
+  IN FAT_OFILE    *OFile,
+  IN FAT_DIRENT   *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  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.
+
+Arguments:
+
+  OFile                 - The corresponding OFile.
+  DirEnt                - The directory entry to be inserted.
+
+Returns:
+
+  EFI_SUCCESS           - The directory entry has been successfully inserted.
+  EFI_VOLUME_FULL       - The directory can not hold more directory entries.
+  Others                - Some error occurred when inserting new directory entries.
+
+--*/
+{
+  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;
+}
+
+STATIC
+EFI_STATUS
+FatNewEntryPos (
+  IN FAT_OFILE    *OFile,
+  IN FAT_DIRENT   *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Find the new directory entry position for the directory entry.
+
+Arguments:
+
+  OFile                 - The corresponding OFile.
+  DirEnt                - The directory entry whose new position is to be set.
+
+Returns:
+
+  EFI_SUCCESS           - The new directory entry position is successfully found.
+  EFI_VOLUME_FULL       - The directory has reach its maximum capacity.
+  other                 - An error occurred when reading the directory entry.
+
+--*/
+{
+  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);
+  FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime);
+  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;
+}
+
+EFI_STATUS
+FatGetVolumeEntry (
+  IN FAT_VOLUME           *Volume,
+  IN CHAR16               *Name
+  )
+/*++
+
+Routine Description:
+
+  Get the directory entry for the volume.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  Name                  - The file name of the volume.
+
+Returns:
+
+  EFI_SUCCESS           - Update the volume with the directory entry sucessfully.
+  others                - An error occurred when getting volume label.
+
+--*/
+{
+  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;
+}
+
+EFI_STATUS
+FatSetVolumeEntry (
+  IN FAT_VOLUME           *Volume,
+  IN CHAR16               *Name
+  )
+/*++
+
+Routine Description:
+
+  Set the relevant directory entry into disk for the volume.
+
+Arguments:
+
+  Volume              - FAT file system volume.
+  Name                - The new file name of the volume.
+
+Returns:
+
+  EFI_SUCCESS         - Update the Volume sucessfully.
+  EFI_UNSUPPORTED     - The input label is not a valid volume label.
+  other               - An error occurred when setting volume label.
+
+--*/
+{
+  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);
+}
+
+EFI_STATUS
+FatCreateDotDirEnts (
+  IN FAT_OFILE          *OFile
+  )
+/*++
+
+Routine Description:
+
+  Create "." and ".." directory entries in the newly-created parent OFile.
+
+Arguments:
+
+  OFile                 - The parent OFile.
+
+Returns:
+
+  EFI_SUCCESS           - The dot directory entries are successfully created.
+  other                 - An error occurred when creating the directory entry.
+
+--*/
+{
+  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;
+}
+
+EFI_STATUS
+FatCreateDirEnt (
+  IN  FAT_OFILE         *OFile,
+  IN  CHAR16            *FileName,
+  IN  UINT8             Attributes,
+  OUT FAT_DIRENT        **PtrDirEnt
+  )
+/*++
+
+Routine Description:
+
+  Create a directory entry in the parent OFile.
+
+Arguments:
+
+  OFile                 - The parent OFile.
+  FileName              - The filename of the newly-created directory entry.
+  Attributes            - The attribute of the newly-created directory entry.
+  PtrDirEnt             - The pointer to the newly-created directory entry.
+
+Returns:
+
+  EFI_SUCCESS           - The directory entry is successfully created.
+  EFI_OUT_OF_RESOURCES  - Not enough memory to create the directory entry.
+  other                 - An error occurred when creating the directory entry.
+
+--*/
+{
+  FAT_DIRENT  *DirEnt;
+  FAT_ODIR    *ODir;
+  EFI_STATUS  Status;
+
+  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 ((EFI_D_INFO, "FSOpen: Created new directory entry '%S'\n", DirEnt->FileString));
+  return FatStoreDirEnt (OFile, DirEnt);
+
+Done:
+  FatFreeDirEnt (DirEnt);
+  return Status;
+}
+
+EFI_STATUS
+FatRemoveDirEnt (
+  IN FAT_OFILE    *OFile,
+  IN FAT_DIRENT   *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Remove this directory entry node from the list of directory entries and hash table.
+
+Arguments:
+
+  OFile                - The parent OFile.
+  DirEnt               - The directory entry to be removed.
+
+Returns:
+
+  EFI_SUCCESS          - The directory entry is successfully removed.
+  other                - An error occurred when removing the directory entry.
+
+--*/
+{
+  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);
+}
+
+EFI_STATUS
+FatOpenDirEnt (
+  IN FAT_OFILE         *Parent,
+  IN FAT_DIRENT        *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Open the directory entry to get the OFile.
+
+Arguments:
+
+  OFile                 - The parent OFile.
+  DirEnt                - The directory entry to be opened.
+
+Returns:
+
+  EFI_SUCCESS           - The directory entry is successfully opened.
+  EFI_OUT_OF_RESOURCES  - not enough memory to allocate a new OFile.
+  other                 - An error occurred when opening the directory entry.
+
+--*/
+{
+  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;
+}
+
+VOID
+FatCloseDirEnt (
+  IN FAT_DIRENT        *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Close the directory entry and free the OFile.
+
+Arguments:
+
+  DirEnt               - The directory entry to be closed.
+
+Returns:
+
+  EFI_SUCCESS          - The directory entry is successfully opened.
+  Other                - An error occurred when opening the directory entry.
+
+--*/
+{
+  FAT_OFILE   *OFile;
+  FAT_VOLUME  *Volume;
+
+  OFile   = DirEnt->OFile;
+  Volume  = OFile->Volume;
+  ASSERT (OFile != NULL);
+
+  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);
+  }
+}
+
+EFI_STATUS
+FatLocateOFile (
+  IN OUT FAT_OFILE        **PtrOFile,
+  IN     CHAR16           *FileName,
+  IN     UINT8            Attributes,
+     OUT CHAR16           *NewFileName
+  )
+/*++
+
+Routine Description:
+
+  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.
+
+Arguments:
+  PtrOFile              - As input, the reference OFile; as output, the located OFile.
+  FileName              - The file name relevant to the OFile.
+  Attributes            - The attribute of the destination OFile.
+  NewFileName           - The remaining file name.
+
+Returns:
+
+  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).
+  EFI_INVALID_PARAMETER - The parameter is not valid.
+  EFI_SUCCESS           - Open the file successfully.
+  other                 - An error occured when locating the OFile.
+
+--*/
+{
+  EFI_STATUS  Status;
+  FAT_VOLUME  *Volume;
+  CHAR16      ComponentName[EFI_PATH_STRING_LENGTH];
+  UINTN       FileNameLen;
+  BOOLEAN     DirIntended;
+  CHAR16      *Next;
+  FAT_OFILE   *OFile;
+  FAT_DIRENT  *DirEnt;
+
+  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;
+}
+

+ 541 - 0
FatPkg/EnhancedFatDxe/DiskCache.c

@@ -0,0 +1,541 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  DiskCache.c
+
+Abstract:
+
+  Cache implementation for EFI FAT File system driver
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+STATIC
+VOID
+FatFlushDataCacheRange (
+  IN  FAT_VOLUME         *Volume,
+  IN  IO_MODE            IoMode,
+  IN  UINTN              StartPageNo,
+  IN  UINTN              EndPageNo,
+  OUT UINT8              *Buffer
+  )
+/*++
+
+Routine Description:
+
+  This function is used by the Data Cache.
+
+  When this function is called by write command, all entries in this range
+  are older than the contents in disk, so they are invalid; just mark them invalid.
+
+  When this function is called by read command, if any entry in this range
+  is dirty, it means that the relative info directly readed from media is older than
+  than the info in the cache; So need to update the relative info in the Buffer.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  IoMode                - This function is called by read command or write command
+  StartPageNo           - First PageNo to be checked in the cache.
+  EndPageNo             - Last PageNo to be checked in the cache.
+  Buffer                - The user buffer need to update. Only when doing the read command
+                          and there is dirty cache in the cache range, this parameter will be used.
+
+Returns:
+
+  None.
+
+--*/
+{
+  UINTN       PageNo;
+  UINTN       GroupNo;
+  UINTN       GroupMask;
+  UINTN       PageSize;
+  UINT8       PageAlignment;
+  DISK_CACHE  *DiskCache;
+  CACHE_TAG   *CacheTag;
+  UINT8       *BaseAddress;
+
+  DiskCache     = &Volume->DiskCache[CACHE_DATA];
+  BaseAddress   = DiskCache->CacheBase;
+  GroupMask     = DiskCache->GroupMask;
+  PageAlignment = DiskCache->PageAlignment;
+  PageSize      = (UINTN)1 << PageAlignment;
+
+  for (PageNo = StartPageNo; PageNo < EndPageNo; PageNo++) {
+    GroupNo   = PageNo & GroupMask;
+    CacheTag  = &DiskCache->CacheTag[GroupNo];
+    if (CacheTag->RealSize > 0 && CacheTag->PageNo == PageNo) {
+      //
+      // When reading data form disk directly, if some dirty data
+      // in cache is in this rang, this data in the Buffer need to
+      // be updated with the cache's dirty data.
+      //
+      if (IoMode == READ_DISK) {
+        if (CacheTag->Dirty) {
+          CopyMem (
+            Buffer + ((PageNo - StartPageNo) << PageAlignment),
+            BaseAddress + (GroupNo << PageAlignment),
+            PageSize
+            );
+        }
+      } else {
+        //
+        // Make all valid entries in this range invalid.
+        //
+        CacheTag->RealSize = 0;
+      }
+    }
+  }
+}
+
+STATIC
+EFI_STATUS
+FatExchangeCachePage (
+  IN FAT_VOLUME         *Volume,
+  IN CACHE_DATA_TYPE    DataType,
+  IN IO_MODE            IoMode,
+  IN CACHE_TAG          *CacheTag
+  )
+/*++
+
+Routine Description:
+
+  Exchange the cache page with the image on the disk
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  DataType              - Indicate the cache type.
+  IoMode                - Indicate whether to load this page from disk or store this page to disk.
+  CacheTag              - The Cache Tag for the current cache page.
+
+Returns:
+
+  EFI_SUCCESS           - Cache page exchanged successfully.
+  Others                - An error occurred when exchanging cache page.
+
+--*/
+{
+  EFI_STATUS  Status;
+  UINTN       GroupNo;
+  UINTN       PageNo;
+  UINTN       WriteCount;
+  UINTN       RealSize;
+  UINT64      EntryPos;
+  UINT64      MaxSize;
+  DISK_CACHE  *DiskCache;
+  VOID        *PageAddress;
+  UINT8       PageAlignment;
+
+  DiskCache     = &Volume->DiskCache[DataType];
+  PageNo        = CacheTag->PageNo;
+  GroupNo       = PageNo & DiskCache->GroupMask;
+  PageAlignment = DiskCache->PageAlignment;
+  PageAddress   = DiskCache->CacheBase + (GroupNo << PageAlignment);
+  EntryPos      = DiskCache->BaseAddress + LShiftU64 (PageNo, PageAlignment);
+  RealSize      = CacheTag->RealSize;
+  if (IoMode == READ_DISK) {
+    RealSize  = (UINTN)1 << PageAlignment;
+    MaxSize   = DiskCache->LimitAddress - EntryPos;
+    if (MaxSize < RealSize) {
+      DEBUG ((EFI_D_INFO, "FatDiskIo: Cache Page OutBound occurred! \n"));
+      RealSize = (UINTN) MaxSize;
+    }
+  }
+
+  WriteCount = 1;
+  if (DataType == CACHE_FAT && IoMode == WRITE_DISK) {
+    WriteCount = Volume->NumFats;
+  }
+
+  do {
+    //
+    // Only fat table writing will execute more than once
+    //
+    Status = FatDiskIo (Volume, IoMode, EntryPos, RealSize, PageAddress);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    EntryPos += Volume->FatSize;
+  } while (--WriteCount > 0);
+
+  CacheTag->Dirty     = FALSE;
+  CacheTag->RealSize  = RealSize;
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FatGetCachePage (
+  IN FAT_VOLUME         *Volume,
+  IN CACHE_DATA_TYPE    CacheDataType,
+  IN UINTN              PageNo,
+  IN CACHE_TAG          *CacheTag
+  )
+/*++
+
+Routine Description:
+
+  Get one cache page by specified PageNo.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  CacheDataType         - The cache type: CACHE_FAT or CACHE_DATA.
+  PageNo                - PageNo to match with the cache.
+  CacheTag              - The Cache Tag for the current cache page.
+
+Returns:
+
+  EFI_SUCCESS           - Get the cache page successfully.
+  other                 - An error occurred when accessing data.
+
+--*/
+{
+  EFI_STATUS  Status;
+  UINTN       OldPageNo;
+
+  OldPageNo = CacheTag->PageNo;
+  if (CacheTag->RealSize > 0 && OldPageNo == PageNo) {
+    //
+    // Cache Hit occurred
+    //
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Write dirty cache page back to disk
+  //
+  if (CacheTag->RealSize > 0 && CacheTag->Dirty) {
+    Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+  //
+  // Load new data from disk;
+  //
+  CacheTag->PageNo  = PageNo;
+  Status            = FatExchangeCachePage (Volume, CacheDataType, READ_DISK, CacheTag);
+
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+FatAccessUnalignedCachePage (
+  IN     FAT_VOLUME        *Volume,
+  IN     CACHE_DATA_TYPE   CacheDataType,
+  IN     IO_MODE           IoMode,
+  IN     UINTN             PageNo,
+  IN     UINTN             Offset,
+  IN     UINTN             Length,
+  IN OUT VOID              *Buffer
+  )
+/*++
+Routine Description:
+
+  Read Length bytes from the position of Offset into Buffer, or
+  write Length bytes from Buffer into the position of Offset.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  CacheDataType         - The type of cache: CACHE_DATA or CACHE_FAT.
+  IoMode                - Indicate the type of disk access.
+  PageNo                - The number of unaligned cache page.
+  Offset                - The starting byte of cache page.
+  Length                - The number of bytes that is read or written
+  Buffer                - Buffer containing cache data.
+
+Returns:
+
+  EFI_SUCCESS           - The data was accessed correctly.
+  Others                - An error occurred when accessing unaligned cache page.
+
+--*/
+{
+  EFI_STATUS  Status;
+  VOID        *Source;
+  VOID        *Destination;
+  DISK_CACHE  *DiskCache;
+  CACHE_TAG   *CacheTag;
+  UINTN       GroupNo;
+
+  DiskCache = &Volume->DiskCache[CacheDataType];
+  GroupNo   = PageNo & DiskCache->GroupMask;
+  CacheTag  = &DiskCache->CacheTag[GroupNo];
+  Status    = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag);
+  if (!EFI_ERROR (Status)) {
+    Source      = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset;
+    Destination = Buffer;
+    if (IoMode != READ_DISK) {
+      CacheTag->Dirty   = TRUE;
+      DiskCache->Dirty  = TRUE;
+      Destination       = Source;
+      Source            = Buffer;
+    }
+
+    CopyMem (Destination, Source, Length);
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+FatAccessCache (
+  IN     FAT_VOLUME         *Volume,
+  IN     CACHE_DATA_TYPE    CacheDataType,
+  IN     IO_MODE            IoMode,
+  IN     UINT64             Offset,
+  IN     UINTN              BufferSize,
+  IN OUT UINT8              *Buffer
+  )
+/*++
+Routine Description:
+
+  Read BufferSize bytes from the position of Offset into Buffer,
+  or write BufferSize bytes from Buffer into the position of Offset.
+
+  Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into
+  the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):
+
+  1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache
+     page hit, just return the cache page; else update the related cache page and return
+     the right cache page.
+  2. Access of Data cache (CACHE_DATA):
+     The access data will be divided into UnderRun data, Aligned data and OverRun data;
+     The UnderRun data and OverRun data will be accessed by the Data cache,
+     but the Aligned data will be accessed with disk directly.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  CacheDataType         - The type of cache: CACHE_DATA or CACHE_FAT.
+  IoMode                - Indicate the type of disk access.
+  Offset                - The starting byte offset to read from.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing cache data.
+
+Returns:
+
+  EFI_SUCCESS           - The data was accessed correctly.
+  EFI_MEDIA_CHANGED     - The MediaId does not match the current device.
+  Others                - An error occurred when accessing cache.
+
+--*/
+{
+  EFI_STATUS  Status;
+  UINTN       PageSize;
+  UINTN       UnderRun;
+  UINTN       OverRun;
+  UINTN       AlignedSize;
+  UINTN       Length;
+  UINTN       PageNo;
+  UINTN       AlignedPageCount;
+  UINTN       OverRunPageNo;
+  DISK_CACHE  *DiskCache;
+  UINT64      EntryPos;
+  UINT8       PageAlignment;
+
+  ASSERT (Volume->CacheBuffer != NULL);
+
+  Status        = EFI_SUCCESS;
+  DiskCache     = &Volume->DiskCache[CacheDataType];
+  EntryPos      = Offset - DiskCache->BaseAddress;
+  PageAlignment = DiskCache->PageAlignment;
+  PageSize      = (UINTN)1 << PageAlignment;
+  PageNo        = (UINTN) RShiftU64 (EntryPos, PageAlignment);
+  UnderRun      = ((UINTN) EntryPos) & (PageSize - 1);
+
+  if (UnderRun > 0) {
+    Length = PageSize - UnderRun;
+    if (Length > BufferSize) {
+      Length = BufferSize;
+    }
+
+    Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Buffer     += Length;
+    BufferSize -= Length;
+    PageNo++;
+  }
+
+  AlignedPageCount  = BufferSize >> PageAlignment;
+  OverRunPageNo     = PageNo + AlignedPageCount;
+  //
+  // The access of the Aligned data
+  //
+  if (AlignedPageCount > 0) {
+    //
+    // Accessing fat table cannot have alignment data
+    //
+    ASSERT (CacheDataType == CACHE_DATA);
+
+    EntryPos    = Volume->RootPos + LShiftU64 (PageNo, PageAlignment);
+    AlignedSize = AlignedPageCount << PageAlignment;
+    Status      = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    //
+    // If these access data over laps the relative cache range, these cache pages need
+    // to be updated.
+    //
+    FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer);
+    Buffer      += AlignedSize;
+    BufferSize  -= AlignedSize;
+  }
+  //
+  // The access of the OverRun data
+  //
+  OverRun = BufferSize;
+  if (OverRun > 0) {
+    //
+    // Last read is not a complete page
+    //
+    Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer);
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+FatVolumeFlushCache (
+  IN FAT_VOLUME         *Volume
+  )
+/*++
+
+Routine Description:
+
+  Flush all the dirty cache back, include the FAT cache and the Data cache.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+
+Returns:
+
+  EFI_SUCCESS           - Flush all the dirty cache back successfully
+  other                 - An error occurred when writing the data into the disk
+
+--*/
+{
+  EFI_STATUS      Status;
+  CACHE_DATA_TYPE CacheDataType;
+  UINTN           GroupIndex;
+  UINTN           GroupMask;
+  DISK_CACHE      *DiskCache;
+  CACHE_TAG       *CacheTag;
+
+  for (CacheDataType = (CACHE_DATA_TYPE) 0; CacheDataType < CACHE_MAX_TYPE; CacheDataType++) {
+    DiskCache = &Volume->DiskCache[CacheDataType];
+    if (DiskCache->Dirty) {
+      //
+      // Data cache or fat cache is dirty, write the dirty data back
+      //
+      GroupMask = DiskCache->GroupMask;
+      for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) {
+        CacheTag = &DiskCache->CacheTag[GroupIndex];
+        if (CacheTag->RealSize > 0 && CacheTag->Dirty) {
+          //
+          // Write back all Dirty Data Cache Page to disk
+          //
+          Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag);
+          if (EFI_ERROR (Status)) {
+            return Status;
+          }
+        }
+      }
+
+      DiskCache->Dirty = FALSE;
+    }
+  }
+  //
+  // Flush the block device.
+  //
+  Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo);
+  return Status;
+}
+
+EFI_STATUS
+FatInitializeDiskCache (
+  IN FAT_VOLUME         *Volume
+  )
+/*++
+
+Routine Description:
+
+  Initialize the disk cache according to Volume's FatType.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+
+Returns:
+
+  EFI_SUCCESS           - The disk cache is successfully initialized.
+  EFI_OUT_OF_RESOURCES  - Not enough memory to allocate disk cache.
+
+--*/
+{
+  DISK_CACHE  *DiskCache;
+  UINTN       FatCacheGroupCount;
+  UINTN       DataCacheSize;
+  UINTN       FatCacheSize;
+  UINT8       *CacheBuffer;
+
+  DiskCache = Volume->DiskCache;
+  //
+  // Configure the parameters of disk cache
+  //
+  if (Volume->FatType == FAT12) {
+    FatCacheGroupCount                  = FAT_FATCACHE_GROUP_MIN_COUNT;
+    DiskCache[CACHE_FAT].PageAlignment  = FAT_FATCACHE_PAGE_MIN_ALIGNMENT;
+    DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT;
+  } else {
+    FatCacheGroupCount                  = FAT_FATCACHE_GROUP_MAX_COUNT;
+    DiskCache[CACHE_FAT].PageAlignment  = FAT_FATCACHE_PAGE_MAX_ALIGNMENT;
+    DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT;
+  }
+
+  DiskCache[CACHE_DATA].GroupMask     = FAT_DATACACHE_GROUP_COUNT - 1;
+  DiskCache[CACHE_DATA].BaseAddress   = Volume->RootPos;
+  DiskCache[CACHE_DATA].LimitAddress  = Volume->VolumeSize;
+  DiskCache[CACHE_FAT].GroupMask      = FatCacheGroupCount - 1;
+  DiskCache[CACHE_FAT].BaseAddress    = Volume->FatPos;
+  DiskCache[CACHE_FAT].LimitAddress   = Volume->FatPos + Volume->FatSize;
+  FatCacheSize                        = FatCacheGroupCount << DiskCache[CACHE_FAT].PageAlignment;
+  DataCacheSize                       = FAT_DATACACHE_GROUP_COUNT << DiskCache[CACHE_DATA].PageAlignment;
+  //
+  // Allocate the Fat Cache buffer
+  //
+  CacheBuffer = AllocatePool (FatCacheSize + DataCacheSize);
+  if (CacheBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Volume->CacheBuffer             = CacheBuffer;
+  DiskCache[CACHE_FAT].CacheBase  = CacheBuffer;
+  DiskCache[CACHE_DATA].CacheBase = CacheBuffer + FatCacheSize;
+  return EFI_SUCCESS;
+}

+ 393 - 0
FatPkg/EnhancedFatDxe/Fat.c

@@ -0,0 +1,393 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  Fat.c
+
+Abstract:
+
+  Fat File System driver routines that support EFI driver model
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatEntryPoint (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  );
+
+EFI_STATUS
+EFIAPI
+FatUnload (
+  IN EFI_HANDLE         ImageHandle
+  );
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  );
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  EFI_HANDLE                   Controller,
+  IN  UINTN                        NumberOfChildren,
+  IN  EFI_HANDLE                   *ChildHandleBuffer
+  );
+
+//
+// DriverBinding protocol instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gFatDriverBinding = {
+  FatDriverBindingSupported,
+  FatDriverBindingStart,
+  FatDriverBindingStop,
+  0xa,
+  NULL,
+  NULL
+};
+
+EFI_STATUS
+EFIAPI
+FatEntryPoint (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+/*++
+
+Routine Description:
+
+  Register Driver Binding protocol for this driver.
+
+Arguments:
+
+  ImageHandle           - Handle for the image of this driver.
+  SystemTable           - Pointer to the EFI System Table.
+
+Returns:
+
+  EFI_SUCCESS           - Driver loaded.
+  other                 - Driver not loaded.
+
+--*/
+{
+  EFI_STATUS                Status;
+
+  //
+  // Initialize the EFI Driver Library
+  //
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gFatDriverBinding,
+             ImageHandle,
+             &gFatComponentName,
+             &gFatComponentName2
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatUnload (
+  IN EFI_HANDLE  ImageHandle
+  )
+/*++
+
+Routine Description:
+
+  Unload function for this image. Uninstall DriverBinding protocol.
+
+Arguments:
+
+  ImageHandle           - Handle for the image of this driver.
+
+Returns:
+
+  EFI_SUCCESS           - Driver unloaded successfully.
+  other                 - Driver can not unloaded.
+
+--*/
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  *DeviceHandleBuffer;
+  UINTN       DeviceHandleCount;
+  UINTN       Index;
+
+  Status = gBS->LocateHandleBuffer (
+                  AllHandles,
+                  NULL,
+                  NULL,
+                  &DeviceHandleCount,
+                  &DeviceHandleBuffer
+                  );
+  if (!EFI_ERROR (Status)) {
+    for (Index = 0; Index < DeviceHandleCount; Index++) {
+      Status = gBS->DisconnectController (
+                      DeviceHandleBuffer[Index],
+                      ImageHandle,
+                      NULL
+                      );
+    }
+
+    if (DeviceHandleBuffer != NULL) {
+      FreePool (DeviceHandleBuffer);
+    }
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+/*++
+
+Routine Description:
+
+  Test to see if this driver can add a file system to ControllerHandle.
+  ControllerHandle must support both Disk IO and Block IO protocols.
+
+Arguments:
+
+  This                  - Protocol instance pointer.
+  ControllerHandle      - Handle of device to test.
+  RemainingDevicePath   - Not used.
+
+Returns:
+
+  EFI_SUCCESS           - This driver supports this device.
+  EFI_ALREADY_STARTED   - This driver is already running on this device.
+  other                 - This driver does not support this device.
+
+--*/
+{
+  EFI_STATUS            Status;
+  EFI_DISK_IO_PROTOCOL  *DiskIo;
+
+  //
+  // Open the IO Abstraction(s) needed to perform the supported test
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDiskIoProtocolGuid,
+                  (VOID **) &DiskIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Close the I/O Abstraction(s) used to perform the supported test
+  //
+  gBS->CloseProtocol (
+         ControllerHandle,
+         &gEfiDiskIoProtocolGuid,
+         This->DriverBindingHandle,
+         ControllerHandle
+         );
+
+  //
+  // Open the IO Abstraction(s) needed to perform the supported test
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  NULL,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                  );
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN EFI_HANDLE                   ControllerHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
+  )
+/*++
+
+Routine Description:
+
+  Start this driver on ControllerHandle by opening a Block IO and Disk IO
+  protocol, reading Device Path. Add a Simple File System protocol to
+  ControllerHandle if the media contains a valid file system.
+
+Arguments:
+
+  This                  - Protocol instance pointer.
+  ControllerHandle      - Handle of device to bind driver to.
+  RemainingDevicePath   - Not used.
+
+Returns:
+
+  EFI_SUCCESS           - This driver is added to DeviceHandle.
+  EFI_ALREADY_STARTED   - This driver is already running on DeviceHandle.
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory.
+  other                 - This driver does not support this device.
+
+--*/
+{
+  EFI_STATUS            Status;
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;
+  EFI_DISK_IO_PROTOCOL  *DiskIo;
+
+  Status = InitializeUnicodeCollationSupport (This->DriverBindingHandle);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Open our required BlockIo and DiskIo
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiDiskIoProtocolGuid,
+                  (VOID **) &DiskIo,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Allocate Volume structure. In FatAllocateVolume(), Resources
+  // are allocated with protocol installed and cached initialized
+  //
+  Status = FatAllocateVolume (ControllerHandle, DiskIo, BlockIo);
+
+  //
+  // When the media changes on a device it will Reinstall the BlockIo interaface.
+  // This will cause a call to our Stop(), and a subsequent reentrant call to our
+  // Start() successfully. We should leave the device open when this happen.
+  //
+  if (EFI_ERROR (Status)) {
+    Status = gBS->OpenProtocol (
+                    ControllerHandle,
+                    &gEfiSimpleFileSystemProtocolGuid,
+                    NULL,
+                    This->DriverBindingHandle,
+                    ControllerHandle,
+                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      gBS->CloseProtocol (
+             ControllerHandle,
+             &gEfiDiskIoProtocolGuid,
+             This->DriverBindingHandle,
+             ControllerHandle
+             );
+    }
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,
+  IN  EFI_HANDLE                    ControllerHandle,
+  IN  UINTN                         NumberOfChildren,
+  IN  EFI_HANDLE                    *ChildHandleBuffer
+  )
+/*++
+
+Routine Description:
+  Stop this driver on ControllerHandle.
+
+Arguments:
+  This                  - Protocol instance pointer.
+  ControllerHandle      - Handle of device to stop driver on.
+  NumberOfChildren      - Not used.
+  ChildHandleBuffer     - Not used.
+
+Returns:
+  EFI_SUCCESS           - This driver is removed DeviceHandle.
+  other                 - This driver was not removed from this device.
+
+--*/
+{
+  EFI_STATUS                      Status;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
+  FAT_VOLUME                      *Volume;
+
+  //
+  // Get our context back
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiSimpleFileSystemProtocolGuid,
+                  (VOID **) &FileSystem,
+                  This->DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (!EFI_ERROR (Status)) {
+    Volume = VOLUME_FROM_VOL_INTERFACE (FileSystem);
+    Status = FatAbandonVolume (Volume);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  Status = gBS->CloseProtocol (
+                  ControllerHandle,
+                  &gEfiDiskIoProtocolGuid,
+                  This->DriverBindingHandle,
+                  ControllerHandle
+                  );
+
+  return Status;
+}

+ 1119 - 0
FatPkg/EnhancedFatDxe/Fat.h

@@ -0,0 +1,1119 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  Fat.h
+
+Abstract:
+
+  Main header file for EFI FAT file system driver
+
+Revision History
+
+--*/
+
+#ifndef _FAT_H_
+#define _FAT_H_
+
+#include <Uefi.h>
+
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/GlobalVariable.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/UnicodeCollation.h>
+
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include "FatFileSystem.h"
+
+//
+// The FAT signature
+//
+#define FAT_VOLUME_SIGNATURE         EFI_SIGNATURE_32 ('f', 'a', 't', 'v')
+#define FAT_IFILE_SIGNATURE          EFI_SIGNATURE_32 ('f', 'a', 't', 'i')
+#define FAT_ODIR_SIGNATURE           EFI_SIGNATURE_32 ('f', 'a', 't', 'd')
+#define FAT_DIRENT_SIGNATURE         EFI_SIGNATURE_32 ('f', 'a', 't', 'e')
+#define FAT_OFILE_SIGNATURE          EFI_SIGNATURE_32 ('f', 'a', 't', 'o')
+
+#define ASSERT_VOLUME_LOCKED(a)      ASSERT_LOCKED (&FatFsLock)
+
+#define IFILE_FROM_FHAND(a)          CR (a, FAT_IFILE, Handle, FAT_IFILE_SIGNATURE)
+
+#define DIRENT_FROM_LINK(a)          CR (a, FAT_DIRENT, Link, FAT_DIRENT_SIGNATURE)
+
+#define VOLUME_FROM_ROOT_DIRENT(a)   CR (a, FAT_VOLUME, RootDirEnt, FAT_VOLUME_SIGNATURE)
+
+#define VOLUME_FROM_VOL_INTERFACE(a) CR (a, FAT_VOLUME, VolumeInterface, FAT_VOLUME_SIGNATURE);
+
+#define ODIR_FROM_DIRCACHELINK(a)    CR (a, FAT_ODIR, DirCacheLink, FAT_ODIR_SIGNATURE)
+
+#define OFILE_FROM_CHECKLINK(a)      CR (a, FAT_OFILE, CheckLink, FAT_OFILE_SIGNATURE)
+
+#define OFILE_FROM_CHILDLINK(a)      CR (a, FAT_OFILE, ChildLink, FAT_OFILE_SIGNATURE)
+
+//
+// Minimum sector size is 512B, Maximum sector size is 4096B
+// Max sectors per cluster is 128
+//
+#define MAX_BLOCK_ALIGNMENT               12
+#define MIN_BLOCK_ALIGNMENT               9
+#define MAX_SECTORS_PER_CLUSTER_ALIGNMENT 7
+
+//
+// Efi Time Definition
+//
+#define IS_LEAP_YEAR(a)                   (((a) % 4 == 0) && (((a) % 100 != 0) || ((a) % 400 == 0)))
+
+//
+// Minimum fat page size is 8K, maximum fat page alignment is 32K
+// Minimum data page size is 8K, maximum fat page alignment is 64K
+//
+#define FAT_FATCACHE_PAGE_MIN_ALIGNMENT   13
+#define FAT_FATCACHE_PAGE_MAX_ALIGNMENT   15
+#define FAT_DATACACHE_PAGE_MIN_ALIGNMENT  13
+#define FAT_DATACACHE_PAGE_MAX_ALIGNMENT  16
+#define FAT_DATACACHE_GROUP_COUNT         64
+#define FAT_FATCACHE_GROUP_MIN_COUNT      1
+#define FAT_FATCACHE_GROUP_MAX_COUNT      16
+
+//
+// Used in 8.3 generation algorithm
+//
+#define MAX_SPEC_RETRY          4
+#define SPEC_BASE_TAG_LEN       6
+#define HASH_BASE_TAG_LEN       2
+#define HASH_VALUE_TAG_LEN      (SPEC_BASE_TAG_LEN - HASH_BASE_TAG_LEN)
+
+//
+// Path name separator is back slash
+//
+#define PATH_NAME_SEPARATOR     L'\\'
+
+
+#define EFI_PATH_STRING_LENGTH  260
+#define EFI_FILE_STRING_LENGTH  255
+#define FAT_MAX_ALLOCATE_SIZE   0xA00000
+#define LC_ISO_639_2_ENTRY_SIZE 3
+#define MAX_LANG_CODE_SIZE      100
+
+#define FAT_MAX_DIR_CACHE_COUNT 8
+#define FAT_MAX_DIRENTRY_COUNT  0xFFFF
+typedef CHAR8                   LC_ISO_639_2;
+
+//
+// The fat types we support
+//
+typedef enum {
+  FAT12,
+  FAT16,
+  FAT32,
+  FatUndefined
+} FAT_VOLUME_TYPE;
+
+typedef enum {
+  CACHE_FAT,
+  CACHE_DATA,
+  CACHE_MAX_TYPE
+} CACHE_DATA_TYPE;
+
+//
+// Used in FatDiskIo
+//
+typedef enum {
+  READ_DISK     = 0,  // raw disk read
+  WRITE_DISK    = 1,  // raw disk write
+  READ_FAT      = 2,  // read fat cache
+  WRITE_FAT     = 3,  // write fat cache
+  READ_DATA     = 6,  // read data cache
+  WRITE_DATA    = 7   // write data cache
+} IO_MODE;
+
+#define CACHE_ENABLED(a)  ((a) >= 2)
+#define RAW_ACCESS(a)     ((IO_MODE)((a) & 0x1))
+#define CACHE_TYPE(a)     ((CACHE_DATA_TYPE)((a) >> 2))
+
+//
+// Disk cache tag
+//
+typedef struct {
+  UINTN   PageNo;
+  UINTN   RealSize;
+  BOOLEAN Dirty;
+} CACHE_TAG;
+
+typedef struct {
+  UINT64    BaseAddress;
+  UINT64    LimitAddress;
+  UINT8     *CacheBase;
+  BOOLEAN   Dirty;
+  UINT8     PageAlignment;
+  UINTN     GroupMask;
+  CACHE_TAG CacheTag[FAT_DATACACHE_GROUP_COUNT];
+} DISK_CACHE;
+
+//
+// Hash table size
+//
+#define HASH_TABLE_SIZE  0x400
+#define HASH_TABLE_MASK  (HASH_TABLE_SIZE - 1)
+
+//
+// The directory entry for opened directory
+//
+typedef struct _FAT_DIRENT {
+  UINTN               Signature;
+  UINT16              EntryPos;               // The position of this directory entry in the parent directory file
+  UINT8               EntryCount;             // The count of the directory entry in the parent directory file
+  BOOLEAN             Invalid;                // Indicate whether this directory entry is valid
+  CHAR16              *FileString;            // The unicode long file name for this directory entry
+  struct _FAT_OFILE   *OFile;                 // The OFile of the corresponding directory entry
+  struct _FAT_DIRENT  *ShortNameForwardLink;  // Hash successor link for short filename
+  struct _FAT_DIRENT  *LongNameForwardLink;   // Hash successor link for long filename
+  LIST_ENTRY          Link;                   // Connection of every directory entry
+  FAT_DIRECTORY_ENTRY Entry;                  // The physical directory entry stored in disk
+} FAT_DIRENT;
+
+typedef struct _FAT_ODIR {
+  UINTN               Signature;
+  UINT32              CurrentEndPos;          // Current end position of the directory
+  UINT32              CurrentPos;             // Current position of the directory
+  LIST_ENTRY          *CurrentCursor;         // Current directory entry pointer
+  LIST_ENTRY          ChildList;              // List of all directory entries
+  BOOLEAN             EndOfDir;               // Indicate whether we have reached the end of the directory
+  LIST_ENTRY          DirCacheLink;           // Linked in Volume->DirCacheList when discarded
+  UINTN               DirCacheTag;            // The identification of the directory when in directory cache
+  FAT_DIRENT          *LongNameHashTable[HASH_TABLE_SIZE];
+  FAT_DIRENT          *ShortNameHashTable[HASH_TABLE_SIZE];
+} FAT_ODIR;
+
+typedef struct {
+  UINTN               Signature;
+  EFI_FILE            Handle;
+  UINT64              Position;
+  BOOLEAN             ReadOnly;
+  struct _FAT_OFILE   *OFile;
+  LIST_ENTRY          Link;
+} FAT_IFILE;
+
+//
+// FAT_OFILE - Each opened file
+//
+typedef struct _FAT_OFILE {
+  UINTN               Signature;
+  struct _FAT_VOLUME  *Volume;
+  //
+  // A permanant error code to return to all accesses to
+  // this opened file
+  //
+  EFI_STATUS          Error;
+  //
+  // A list of the IFILE instances for this OFile
+  //
+  LIST_ENTRY          Opens;
+
+  //
+  // The dynamic infomation
+  //
+  UINTN               FileSize;
+  UINTN               FileCluster;
+  UINTN               FileCurrentCluster;
+  UINTN               FileLastCluster;
+
+  //
+  // Dirty is set if there have been any updates to the
+  // file
+  // Archive is set if the archive attribute in the file’s
+  // directory entry needs to be set when performing flush
+  // PreserveLastMod is set if the last modification of the
+  // file is specified by SetInfo API
+  //
+  BOOLEAN             Dirty;
+  BOOLEAN             IsFixedRootDir;
+  BOOLEAN             PreserveLastModification;
+  BOOLEAN             Archive;
+  //
+  // Set by an OFile SetPosition
+  //
+  UINTN               Position; // within file
+  UINT64              PosDisk;  // on the disk
+  UINTN               PosRem;   // remaining in this disk run
+  //
+  // The opened parent, full path length and currently opened child files
+  //
+  struct _FAT_OFILE   *Parent;
+  UINTN               FullPathLen;
+  LIST_ENTRY          ChildHead;
+  LIST_ENTRY          ChildLink;
+
+  //
+  // The opened directory structure for a directory; if this
+  // OFile represents a file, then ODir = NULL
+  //
+  FAT_ODIR            *ODir;
+  //
+  // The directory entry for the Ofile
+  //
+  FAT_DIRENT          *DirEnt;
+
+  //
+  // Link in Volume's reference list
+  //
+  LIST_ENTRY          CheckLink;
+} FAT_OFILE;
+
+typedef struct _FAT_VOLUME {
+  UINTN                           Signature;
+
+  EFI_HANDLE                      Handle;
+  BOOLEAN                         Valid;
+  BOOLEAN                         DiskError;
+
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL VolumeInterface;
+
+  //
+  // If opened, the parent handle and BlockIo interface
+  //
+  EFI_BLOCK_IO_PROTOCOL           *BlockIo;
+  EFI_DISK_IO_PROTOCOL            *DiskIo;
+  UINT32                          MediaId;
+  BOOLEAN                         ReadOnly;
+
+  //
+  // Computed values from fat bpb info
+  //
+  UINT64                          VolumeSize;
+  UINT64                          FatPos;           // Disk pos of fat tables
+  UINT64                          RootPos;          // Disk pos of root directory
+  UINT64                          FirstClusterPos;  // Disk pos of first cluster
+  UINTN                           FatSize;          // Number of bytes in each fat
+  UINTN                           MaxCluster;       // Max cluster number
+  UINTN                           ClusterSize;      // Cluster size of fat partition
+  UINT8                           ClusterAlignment; // Equal to log_2 (clustersize);
+  FAT_VOLUME_TYPE                 FatType;
+
+  //
+  // Current part of fat table that's present
+  //
+  UINT64                          FatEntryPos;    // Location of buffer
+  UINTN                           FatEntrySize;   // Size of buffer
+  UINT32                          FatEntryBuffer; // The buffer
+  FAT_INFO_SECTOR                 FatInfoSector;  // Free cluster info
+  UINTN                           FreeInfoPos;    // Pos with the free cluster info
+  BOOLEAN                         FreeInfoValid;  // If free cluster info is valid
+  //
+  // Unpacked Fat BPB info
+  //
+  UINTN                           NumFats;
+  UINTN                           RootEntries;    // < FAT32, root dir is fixed size
+  UINTN                           RootCluster;    // >= FAT32, root cluster chain head
+  //
+  // info for marking the volume dirty or not
+  //
+  BOOLEAN                         FatDirty;       // If fat-entries have been updated
+  UINT32                          DirtyValue;
+  UINT32                          NotDirtyValue;
+
+  //
+  // The root directory entry and opened root file
+  //
+  FAT_DIRENT                      RootDirEnt;
+  //
+  // File Name of root OFile, it is empty string
+  //
+  CHAR16                          RootFileString[1];
+  struct _FAT_OFILE               *Root;
+
+  //
+  // New OFiles are added to this list so they
+  // can be cleaned up if they aren't referenced.
+  //
+  LIST_ENTRY                      CheckRef;
+
+  //
+  // Directory cache List
+  //
+  LIST_ENTRY                      DirCacheList;
+  UINTN                           DirCacheCount;
+
+  //
+  // Disk Cache for this volume
+  //
+  VOID                            *CacheBuffer;
+  DISK_CACHE                      DiskCache[CACHE_MAX_TYPE];
+} FAT_VOLUME;
+
+//
+// Function Prototypes
+//
+EFI_STATUS
+EFIAPI
+FatOpen (
+  IN  EFI_FILE          *FHand,
+  OUT EFI_FILE          **NewHandle,
+  IN  CHAR16            *FileName,
+  IN  UINT64            OpenMode,
+  IN  UINT64            Attributes
+  )
+/*++
+Routine Description:
+
+  Implements Open() of Simple File System Protocol.
+
+Arguments:
+
+  FHand                 - File handle of the file serves as a starting reference point.
+  NewHandle             - Handle of the file that is newly opened.
+  FileName              - File name relative to FHand.
+  OpenMode              - Open mode.
+  Attributes            - Attributes to set if the file is created.
+
+Returns:
+
+  EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.
+                          The OpenMode is not supported.
+                          The Attributes is not the valid attributes.
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory for file string.
+  EFI_SUCCESS           - Open the file successfully.
+  Others                - The status of open file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatGetPosition (
+  IN  EFI_FILE          *FHand,
+  OUT UINT64            *Position
+  )
+/*++
+
+Routine Description:
+
+  Get the file's position of the file
+
+Arguments:
+
+  FHand                 - The handle of file.
+  Position              - The file's position of the file.
+
+Returns:
+
+  EFI_SUCCESS           - Get the info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+  EFI_UNSUPPORTED       - The open file is not a file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatGetInfo (
+  IN     EFI_FILE      *FHand,
+  IN     EFI_GUID      *Type,
+  IN OUT UINTN         *BufferSize,
+     OUT VOID          *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the some types info of the file into Buffer
+
+Arguments:
+
+  FHand                 - The handle of file.
+  Type                  - The type of the info.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing volume info.
+
+Returns:
+
+  EFI_SUCCESS           - Get the info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatSetInfo (
+  IN EFI_FILE           *FHand,
+  IN EFI_GUID           *Type,
+  IN UINTN              BufferSize,
+  IN VOID               *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Set the some types info of the file into Buffer
+
+Arguments:
+
+  FHand                 - The handle of file.
+  Type                  - The type of the info.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing volume info.
+
+Returns:
+
+  EFI_SUCCESS           - Set the info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatFlush (
+  IN EFI_FILE           *FHand
+  )
+/*++
+
+Routine Description:
+
+  Flushes all data associated with the file handle
+
+Arguments:
+
+  FHand                 - Handle to file to flush
+
+Returns:
+
+  EFI_SUCCESS           - Flushed the file successfully
+  EFI_WRITE_PROTECTED   - The volume is read only
+  EFI_ACCESS_DENIED     - The volume is not read only
+                          but the file is read only
+  Others                - Flushing of the file is failed
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatClose (
+  IN EFI_FILE  *FHand
+  )
+/*++
+
+Routine Description:
+
+  Flushes & Closes the file handle.
+
+Arguments:
+
+  FHand                 - Handle to the file to delete.
+
+Returns:
+
+  EFI_SUCCESS           - Closed the file successfully.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatDelete (
+  IN EFI_FILE           *FHand
+  )
+/*++
+
+Routine Description:
+
+  Deletes the file & Closes the file handle.
+
+Arguments:
+
+  FHand                    - Handle to the file to delete.
+
+Returns:
+
+  EFI_SUCCESS              - Delete the file successfully.
+  EFI_WARN_DELETE_FAILURE  - Fail to delete the file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatSetPosition (
+  IN EFI_FILE           *FHand,
+  IN UINT64             Position
+  )
+/*++
+
+Routine Description:
+
+  Set the file's position of the file
+
+Arguments:
+
+  FHand                 - The handle of file
+  Position              - The file's position of the file
+
+Returns:
+
+  EFI_SUCCESS           - Set the info successfully
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file
+  EFI_UNSUPPORTED       - Set a directory with a not-zero position
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatRead (
+  IN     EFI_FILE   *FHand,
+  IN OUT UINTN      *BufferSize,
+     OUT VOID       *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the file info.
+
+Arguments:
+
+  FHand                 - The handle of the file.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing read data.
+
+Returns:
+
+  EFI_SUCCESS           - Get the file info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+  EFI_VOLUME_CORRUPTED  - The file type of open file is error.
+  other                 - An error occurred when operation the disk.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatWrite (
+  IN     EFI_FILE      *FHand,
+  IN OUT UINTN         *BufferSize,
+  IN     VOID          *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Set the file info.
+
+Arguments:
+
+  FHand                 - The handle of the file.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing write data.
+
+Returns:
+
+  EFI_SUCCESS           - Set the file info successfully.
+  EFI_WRITE_PROTECTED   - The disk is write protected.
+  EFI_ACCESS_DENIED     - The file is read-only.
+  EFI_DEVICE_ERROR      - The OFile is not valid.
+  EFI_UNSUPPORTED       - The open file is not a file.
+                        - The writing file size is larger than 4GB.
+  other                 - An error occurred when operation the disk.
+
+--*/
+;
+
+//
+// DiskCache.c
+//
+EFI_STATUS
+FatInitializeDiskCache (
+  IN FAT_VOLUME              *Volume
+  );
+
+EFI_STATUS
+FatAccessCache (
+  IN     FAT_VOLUME          *Volume,
+  IN     CACHE_DATA_TYPE     CacheDataType,
+  IN     IO_MODE             IoMode,
+  IN     UINT64              Offset,
+  IN     UINTN               BufferSize,
+  IN OUT UINT8               *Buffer
+  );
+
+EFI_STATUS
+FatVolumeFlushCache (
+  IN FAT_VOLUME              *Volume
+  );
+
+//
+// Flush.c
+//
+EFI_STATUS
+FatOFileFlush (
+  IN FAT_OFILE          *OFile
+  );
+
+BOOLEAN
+FatCheckOFileRef (
+  IN FAT_OFILE          *OFile
+  );
+
+VOID
+FatSetVolumeError (
+  IN FAT_OFILE          *OFile,
+  IN EFI_STATUS         Status
+  );
+
+EFI_STATUS
+FatIFileClose (
+  FAT_IFILE             *IFile
+  );
+
+EFI_STATUS
+FatCleanupVolume (
+  IN FAT_VOLUME         *Volume,
+  IN FAT_OFILE          *OFile,
+  IN EFI_STATUS         EfiStatus
+  );
+
+//
+// FileSpace.c
+//
+EFI_STATUS
+FatShrinkEof (
+  IN FAT_OFILE          *OFile
+  );
+
+EFI_STATUS
+FatGrowEof (
+  IN FAT_OFILE          *OFile,
+  IN UINT64             NewSizeInBytes
+  );
+
+UINTN
+FatPhysicalDirSize (
+  IN FAT_VOLUME         *Volume,
+  IN UINTN              Cluster
+  );
+
+UINT64
+FatPhysicalFileSize (
+  IN FAT_VOLUME         *Volume,
+  IN UINTN              RealSize
+  );
+
+EFI_STATUS
+FatOFilePosition (
+  IN FAT_OFILE            *OFile,
+  IN UINTN                Position,
+  IN UINTN                PosLimit
+  );
+
+VOID
+FatComputeFreeInfo (
+  IN FAT_VOLUME         *Volume
+  );
+
+//
+// Init.c
+//
+EFI_STATUS
+FatAllocateVolume (
+  IN  EFI_HANDLE                     Handle,
+  IN  EFI_DISK_IO_PROTOCOL           *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL          *BlockIo
+  );
+
+EFI_STATUS
+FatOpenDevice (
+  IN OUT FAT_VOLUME     *Volume
+  );
+
+EFI_STATUS
+FatAbandonVolume (
+  IN FAT_VOLUME         *Volume
+  );
+
+//
+// Misc.c
+//
+EFI_STATUS
+FatAccessVolumeDirty (
+  IN FAT_VOLUME         *Volume,
+  IN IO_MODE            IoMode,
+  IN VOID               *DirtyValue
+  );
+
+EFI_STATUS
+FatDiskIo (
+  IN FAT_VOLUME         *Volume,
+  IN IO_MODE            IoMode,
+  IN UINT64             Offset,
+  IN UINTN              BufferSize,
+  IN OUT VOID           *Buffer
+  );
+
+VOID
+FatAcquireLock (
+  VOID
+  );
+
+VOID
+FatReleaseLock (
+  VOID
+  );
+
+BOOLEAN
+FatIsLocked (
+  VOID
+  );
+
+VOID
+FatFreeDirEnt (
+  IN FAT_DIRENT         *DirEnt
+  );
+
+VOID
+FatFreeVolume (
+  IN FAT_VOLUME         *Volume
+  );
+
+VOID
+FatEfiTimeToFatTime (
+  IN EFI_TIME           *ETime,
+  OUT FAT_DATE_TIME     *FTime
+  );
+
+VOID
+FatFatTimeToEfiTime (
+  IN FAT_DATE_TIME      *FTime,
+  OUT EFI_TIME          *ETime
+  );
+
+VOID
+FatGetCurrentFatTime (
+  OUT FAT_DATE_TIME     *FatTime
+  );
+
+BOOLEAN
+FatIsValidTime (
+  IN EFI_TIME           *Time
+  );
+
+//
+// UnicodeCollation.c
+//
+EFI_STATUS
+InitializeUnicodeCollationSupport (
+  IN EFI_HANDLE    AgentHandle
+  );
+
+VOID
+FatFatToStr (
+  IN UINTN              FatSize,
+  IN CHAR8              *Fat,
+  OUT CHAR16            *String
+  );
+
+BOOLEAN
+FatStrToFat (
+  IN  CHAR16            *String,
+  IN  UINTN             FatSize,
+  OUT CHAR8             *Fat
+  );
+
+VOID
+FatStrLwr (
+  IN CHAR16             *Str
+  );
+
+VOID
+FatStrUpr (
+  IN CHAR16             *Str
+  );
+
+INTN
+FatStriCmp (
+  IN CHAR16             *Str1,
+  IN CHAR16             *Str2
+  );
+
+//
+// Open.c
+//
+EFI_STATUS
+FatOFileOpen (
+  IN FAT_OFILE          *OFile,
+  OUT FAT_IFILE         **NewIFile,
+  IN CHAR16             *FileName,
+  IN UINT64             OpenMode,
+  IN UINT8              Attributes
+  );
+
+EFI_STATUS
+FatAllocateIFile (
+  IN FAT_OFILE          *OFile,
+  OUT FAT_IFILE         **PtrIFile
+  );
+
+//
+// OpenVolume.c
+//
+EFI_STATUS
+EFIAPI
+FatOpenVolume (
+  IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+  OUT EFI_FILE                        **File
+  );
+
+//
+// ReadWrite.c
+//
+EFI_STATUS
+FatAccessOFile (
+  IN FAT_OFILE          *OFile,
+  IN IO_MODE            IoMode,
+  IN UINTN              Position,
+  IN UINTN              *DataBufferSize,
+  IN UINT8              *UserBuffer
+  );
+
+EFI_STATUS
+FatExpandOFile (
+  IN FAT_OFILE          *OFile,
+  IN UINT64             ExpandedSize
+  );
+
+EFI_STATUS
+FatWriteZeroPool (
+  IN FAT_OFILE          *OFile,
+  IN UINTN              WritePos
+  );
+
+EFI_STATUS
+FatTruncateOFile (
+  IN FAT_OFILE          *OFile,
+  IN UINTN              TruncatedSize
+  );
+
+//
+// DirectoryManage.c
+//
+VOID
+FatResetODirCursor (
+  IN FAT_OFILE          *OFile
+  );
+
+EFI_STATUS
+FatGetNextDirEnt (
+  IN  FAT_OFILE         *OFILE,
+  OUT FAT_DIRENT        **PtrDirEnt
+  );
+
+EFI_STATUS
+FatRemoveDirEnt (
+  IN FAT_OFILE          *OFile,
+  IN FAT_DIRENT         *DirEnt
+  );
+
+EFI_STATUS
+FatStoreDirEnt (
+  IN FAT_OFILE          *OFile,
+  IN FAT_DIRENT         *DirEnt
+  );
+
+EFI_STATUS
+FatCreateDirEnt (
+  IN  FAT_OFILE         *OFile,
+  IN  CHAR16            *FileName,
+  IN  UINT8             Attributes,
+  OUT FAT_DIRENT        **PtrDirEnt
+  );
+
+BOOLEAN
+FatIsDotDirEnt (
+  IN FAT_DIRENT         *DirEnt
+  );
+
+VOID
+FatUpdateDirEntClusterSizeInfo (
+  IN FAT_OFILE          *OFile
+  );
+
+VOID
+FatCloneDirEnt (
+  IN  FAT_DIRENT        *DirEnt1,
+  IN  FAT_DIRENT        *DirEnt2
+  );
+
+EFI_STATUS
+FatGetDirEntInfo (
+  IN FAT_VOLUME         *Volume,
+  IN FAT_DIRENT         *DirEnt,
+  IN OUT UINTN          *BufferSize,
+  OUT VOID              *Buffer
+  );
+
+EFI_STATUS
+FatOpenDirEnt (
+  IN FAT_OFILE          *OFile,
+  IN FAT_DIRENT         *DirEnt
+  );
+
+EFI_STATUS
+FatCreateDotDirEnts (
+  IN FAT_OFILE          *OFile
+  );
+
+VOID
+FatCloseDirEnt (
+  IN FAT_DIRENT         *DirEnt
+  );
+
+EFI_STATUS
+FatLocateOFile (
+  IN OUT FAT_OFILE      **PtrOFile,
+  IN     CHAR16         *FileName,
+  IN     UINT8          Attributes,
+     OUT CHAR16         *NewFileName
+  );
+
+EFI_STATUS
+FatGetVolumeEntry (
+  IN FAT_VOLUME         *Volume,
+  IN CHAR16             *Name
+  );
+
+EFI_STATUS
+FatSetVolumeEntry (
+  IN FAT_VOLUME         *Volume,
+  IN CHAR16             *Name
+  );
+
+//
+// Hash.c
+//
+FAT_DIRENT **
+FatLongNameHashSearch (
+  IN FAT_ODIR           *ODir,
+  IN CHAR16             *LongNameString
+  );
+
+FAT_DIRENT **
+FatShortNameHashSearch (
+  IN FAT_ODIR           *ODir,
+  IN CHAR8              *ShortNameString
+  );
+
+VOID
+FatInsertToHashTable (
+  IN FAT_ODIR           *ODir,
+  IN FAT_DIRENT         *DirEnt
+  );
+
+VOID
+FatDeleteFromHashTable (
+  IN FAT_ODIR           *ODir,
+  IN FAT_DIRENT         *DirEnt
+  );
+
+//
+// FileName.c
+//
+BOOLEAN
+FatCheckIs8Dot3Name (
+  IN CHAR16             *FileName,
+  OUT CHAR8             *File8Dot3Name
+  );
+
+VOID
+FatCreate8Dot3Name (
+  IN FAT_OFILE          *Parent,
+  IN FAT_DIRENT         *DirEnt
+  );
+
+VOID
+FatNameToStr (
+  IN CHAR8              *FatName,
+  IN UINTN              Len,
+  IN UINTN              LowerCase,
+  IN CHAR16             *Str
+  );
+
+VOID
+FatSetCaseFlag (
+  IN FAT_DIRENT         *DirEnt
+  );
+
+VOID
+FatGetFileNameViaCaseFlag (
+  IN  FAT_DIRENT        *DirEnt,
+  OUT CHAR16            *FileString
+  );
+
+UINT8
+FatCheckSum (
+  IN CHAR8              *ShortNameString
+  );
+
+CHAR16*
+FatGetNextNameComponent (
+  IN  CHAR16            *Path,
+  OUT CHAR16            *Name
+  );
+
+BOOLEAN
+FatFileNameIsValid (
+  IN  CHAR16  *InputFileName,
+  OUT CHAR16  *OutputFileName
+  );
+
+//
+// DirectoryCache.c
+//
+VOID
+FatDiscardODir (
+  IN FAT_OFILE    *OFile
+  );
+
+VOID
+FatRequestODir (
+  IN FAT_OFILE    *OFile
+  );
+
+VOID
+FatCleanupODirCache (
+  IN FAT_VOLUME   *Volume
+  );
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL     gFatDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL     gFatComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL    gFatComponentName2;
+extern EFI_LOCK                        FatFsLock;
+extern EFI_FILE                        FatFileInterface;
+
+#endif

+ 98 - 0
FatPkg/EnhancedFatDxe/Fat.inf

@@ -0,0 +1,98 @@
+#/** @file
+#  Component description file for FAT module.
+#
+#  This UEFI driver detects the FAT file system in the disk.
+#  It also produces the Simple File System protocol for the consumer to
+#  perform file and directory operations on the disk.
+#  Copyright (c) 2007, Intel Corporation
+#
+#  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.
+#
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = Fat
+  FILE_GUID                      = 961578FE-B6B7-44c3-AF35-6BC705CD2B1F
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  EDK_RELEASE_VERSION            = 0x00020000
+  EFI_SPECIFICATION_VERSION      = 0x00020000
+
+  ENTRY_POINT                    = FatEntryPoint
+  UNLOAD_IMAGE                   = FatUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+#  DRIVER_BINDING                =  gFatDriverBinding
+#  COMPONENT_NAME                =  gFatComponentName
+#  COMPONENT_NAME2               =  gFatComponentName2
+#
+
+[Sources.common]
+  DirectoryCache.c
+  DiskCache.c
+  FileName.c
+  Hash.c
+  DirectoryManage.c
+  ComponentName.c
+  FatFileSystem.h
+  Fat.h
+  ReadWrite.c
+  OpenVolume.c
+  Open.c
+  Misc.c
+  Init.c
+  Info.c
+  FileSpace.c
+  Flush.c
+  Fat.c
+  Delete.c
+  Data.c
+  UnicodeCollation.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  FatPkg/FatPkg.dec
+
+[LibraryClasses]
+  UefiRuntimeServicesTableLib
+  UefiBootServicesTableLib
+  MemoryAllocationLib
+  BaseMemoryLib
+  BaseLib
+  UefiLib
+  UefiDriverEntryPoint
+  DebugLib
+  PcdLib
+
+[Guids]
+  gEfiFileInfoGuid
+  gEfiFileSystemInfoGuid
+  gEfiFileSystemVolumeLabelInfoIdGuid
+  gEfiGlobalVariableGuid
+
+[Protocols]
+  gEfiDiskIoProtocolGuid
+  gEfiBlockIoProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
+  gEfiUnicodeCollationProtocolGuid
+  gEfiUnicodeCollation2ProtocolGuid
+
+[FeaturePcd]
+  gEfiFatPkgTokenSpaceGuid.PcdUnicodeCollationSupport
+  gEfiFatPkgTokenSpaceGuid.PcdUnicodeCollation2Support
+
+[Pcd]
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang
+  gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang

+ 221 - 0
FatPkg/EnhancedFatDxe/FatFileSystem.h

@@ -0,0 +1,221 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  FatFileSystem.h
+
+Abstract:
+
+  Definitions for on-disk FAT structures
+
+Revision History
+
+--*/
+
+#ifndef _FATFILESYSTEM_H_
+#define _FATFILESYSTEM_H_
+
+#pragma pack(1)
+//
+// FAT info signature
+//
+#define FAT_INFO_SIGNATURE        0x41615252
+#define FAT_INFO_BEGIN_SIGNATURE  0x61417272
+#define FAT_INFO_END_SIGNATURE    0xAA550000
+//
+// FAT entry values
+//
+#define FAT_CLUSTER_SPECIAL_EXT       (-1 & (~0xF))
+#define FAT_CLUSTER_SPECIAL           ((FAT_CLUSTER_SPECIAL_EXT) | 0x07)
+#define FAT_CLUSTER_FREE              0
+#define FAT_CLUSTER_RESERVED          (FAT_CLUSTER_SPECIAL)
+#define FAT_CLUSTER_BAD               (FAT_CLUSTER_SPECIAL)
+#define FAT_CLUSTER_LAST              (-1)
+#define FAT_END_OF_FAT_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL))
+#define FAT_MIN_CLUSTER               2
+#define FAT_MAX_FAT12_CLUSTER         0xFF5
+#define FAT_MAX_FAT16_CLUSTER         0xFFF5
+#define FAT_CLUSTER_SPECIAL_FAT12     0xFF7
+#define FAT_CLUSTER_SPECIAL_FAT16     0xFFF7
+#define FAT_CLUSTER_SPECIAL_FAT32     0x0FFFFFF7
+#define FAT_CLUSTER_MASK_FAT12        0xFFF
+#define FAT_CLUSTER_UNMASK_FAT12      0xF000
+#define FAT_CLUSTER_MASK_FAT32        0x0FFFFFFF
+#define FAT_CLUSTER_UNMASK_FAT32      0xF0000000
+#define FAT_POS_FAT12(a)              ((a) * 3 / 2)
+#define FAT_POS_FAT16(a)              ((a) * 2)
+#define FAT_POS_FAT32(a)              ((a) * 4)
+#define FAT_ODD_CLUSTER_FAT12(a)      (((a) & 1) != 0)
+
+
+//
+// FAT attribute define
+//
+#define FAT_ATTRIBUTE_READ_ONLY 0x01
+#define FAT_ATTRIBUTE_HIDDEN    0x02
+#define FAT_ATTRIBUTE_SYSTEM    0x04
+#define FAT_ATTRIBUTE_VOLUME_ID 0x08
+#define FAT_ATTRIBUTE_DIRECTORY 0x10
+#define FAT_ATTRIBUTE_ARCHIVE   0x20
+#define FAT_ATTRIBUTE_DEVICE    0x40
+#define FAT_ATTRIBUTE_LFN       0x0F
+//
+// Some Long File Name definitions
+//
+#define FAT_LFN_LAST            0x40  // Ordinal field
+#define MAX_LFN_ENTRIES         20
+#define LFN_CHAR1_LEN           5
+#define LFN_CHAR2_LEN           6
+#define LFN_CHAR3_LEN           2
+#define LFN_CHAR_TOTAL          (LFN_CHAR1_LEN + LFN_CHAR2_LEN + LFN_CHAR3_LEN)
+#define LFN_ENTRY_NUMBER(a)     (((a) + LFN_CHAR_TOTAL - 1) / LFN_CHAR_TOTAL)
+//
+// Some 8.3 File Name definitions
+//
+#define FAT_MAIN_NAME_LEN       8
+#define FAT_EXTEND_NAME_LEN     3
+#define FAT_NAME_LEN            (FAT_MAIN_NAME_LEN + FAT_EXTEND_NAME_LEN)
+//
+// Some directory entry information
+//
+#define FAT_ENTRY_INFO_OFFSET   13
+#define DELETE_ENTRY_MARK       0xE5
+#define EMPTY_ENTRY_MARK        0x00
+
+//
+// Volume dirty Mask
+//
+#define FAT16_DIRTY_MASK        0x7fff
+#define FAT32_DIRTY_MASK        0xf7ffffff
+//
+// internal flag
+//
+#define FAT_CASE_MIXED          0x01
+#define FAT_CASE_NAME_LOWER     0x08
+#define FAT_CASE_EXT_LOWER      0x10
+
+typedef struct {
+  UINT8   Ia32Jump[3];
+  CHAR8   OemId[8];
+  UINT16  SectorSize;
+  UINT8   SectorsPerCluster;
+  UINT16  ReservedSectors;
+  UINT8   NumFats;
+  UINT16  RootEntries;          // < FAT32, root dir is fixed size
+  UINT16  Sectors;
+  UINT8   Media;
+  UINT16  SectorsPerFat;        // < FAT32
+  UINT16  SectorsPerTrack;      // (ignored)
+  UINT16  Heads;                // (ignored)
+  UINT32  HiddenSectors;        // (ignored)
+  UINT32  LargeSectors;         // Used if Sectors==0
+} FAT_BOOT_SECTOR_BASIC;
+
+typedef struct {
+  UINT8 PhysicalDriveNumber;    // (ignored)
+  UINT8 CurrentHead;            // holds boot_sector_dirty bit
+  UINT8 Signature;              // (ignored)
+  CHAR8 Id[4];
+  CHAR8 FatLabel[11];
+  CHAR8 SystemId[8];
+} FAT_BOOT_SECTOR_EXT;
+
+typedef struct {
+  UINT32  LargeSectorsPerFat;   // FAT32
+  UINT16  ExtendedFlags;        // FAT32 (ignored)
+  UINT16  FsVersion;            // FAT32 (ignored)
+  UINT32  RootDirFirstCluster;  // FAT32
+  UINT16  FsInfoSector;         // FAT32
+  UINT16  BackupBootSector;     // FAT32
+  UINT8   Reserved[12];         // FAT32 (ignored)
+  UINT8   PhysicalDriveNumber;  // (ignored)
+  UINT8   CurrentHead;          // holds boot_sector_dirty bit
+  UINT8   Signature;            // (ignored)
+  CHAR8   Id[4];
+  CHAR8   FatLabel[11];
+  CHAR8   SystemId[8];
+} FAT32_BOOT_SECTOR_EXT;
+
+typedef struct {
+  FAT_BOOT_SECTOR_BASIC   FatBsb;
+  union {
+    FAT_BOOT_SECTOR_EXT   FatBse;
+    FAT32_BOOT_SECTOR_EXT Fat32Bse;
+  } FatBse;
+} FAT_BOOT_SECTOR;
+
+//
+// FAT Info Structure
+//
+typedef struct {
+  UINT32  ClusterCount;
+  UINT32  NextCluster;
+} FAT_FREE_INFO;
+
+typedef struct {
+  UINT32        Signature;
+  UINT8         ExtraBootCode[480];
+  UINT32        InfoBeginSignature;
+  FAT_FREE_INFO FreeInfo;
+  UINT8         Reserved[12];
+  UINT32        InfoEndSignature;
+} FAT_INFO_SECTOR;
+
+//
+// Directory Entry
+//
+#define FAT_MAX_YEAR_FROM_1980  0x7f
+typedef struct {
+  UINT16  Day : 5;
+  UINT16  Month : 4;
+  UINT16  Year : 7;                 // From 1980
+} FAT_DATE;
+
+typedef struct {
+  UINT16  DoubleSecond : 5;
+  UINT16  Minute : 6;
+  UINT16  Hour : 5;
+} FAT_TIME;
+
+typedef struct {
+  FAT_TIME  Time;
+  FAT_DATE  Date;
+} FAT_DATE_TIME;
+
+typedef struct {
+  CHAR8         FileName[11];       // 8.3 filename
+  UINT8         Attributes;
+  UINT8         CaseFlag;
+  UINT8         CreateMillisecond;  // (creation milliseconds - ignored)
+  FAT_DATE_TIME FileCreateTime;
+  FAT_DATE      FileLastAccess;
+  UINT16        FileClusterHigh;    // >= FAT32
+  FAT_DATE_TIME FileModificationTime;
+  UINT16        FileCluster;
+  UINT32        FileSize;
+} FAT_DIRECTORY_ENTRY;
+
+typedef struct {
+  UINT8   Ordinal;
+  CHAR8   Name1[10];                // (Really 5 chars, but not WCHAR aligned)
+  UINT8   Attributes;
+  UINT8   Type;
+  UINT8   Checksum;
+  CHAR16  Name2[6];
+  UINT16  MustBeZero;
+  CHAR16  Name3[2];
+} FAT_DIRECTORY_LFN;
+
+#pragma pack()
+
+#endif

+ 583 - 0
FatPkg/EnhancedFatDxe/FileName.c

@@ -0,0 +1,583 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  FileName.c
+
+Abstract:
+
+  Functions for manipulating file names
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+BOOLEAN
+FatCheckIs8Dot3Name (
+  IN  CHAR16    *FileName,
+  OUT CHAR8     *File8Dot3Name
+  )
+/*++
+
+Routine Description:
+
+  This function checks whether the input FileName is a valid 8.3 short name.
+  If the input FileName is a valid 8.3, the output is the 8.3 short name;
+  otherwise, the output is the base tag of 8.3 short name.
+
+Arguments:
+
+  FileName              - The input unicode filename.
+  File8Dot3Name         - The output ascii 8.3 short name or base tag of 8.3 short name.
+
+Returns:
+
+  TRUE                  - The input unicode filename is a valid 8.3 short name.
+  FALSE                 - The input unicode filename is not a valid 8.3 short name.
+
+--*/
+{
+  BOOLEAN PossibleShortName;
+  CHAR16  *TempName;
+  CHAR16  *ExtendName;
+  CHAR16  *SeparateDot;
+  UINTN   MainNameLen;
+  UINTN   ExtendNameLen;
+
+  PossibleShortName = TRUE;
+  SeparateDot       = NULL;
+  SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');
+  for (TempName = FileName; *TempName; TempName++) {
+    if (*TempName == L'.') {
+      SeparateDot = TempName;
+    }
+  }
+
+  if (SeparateDot == NULL) {
+    //
+    // Extended filename is not detected
+    //
+    MainNameLen   = TempName - FileName;
+    ExtendName    = TempName;
+    ExtendNameLen = 0;
+  } else {
+    //
+    // Extended filename is detected
+    //
+    MainNameLen   = SeparateDot - FileName;
+    ExtendName    = SeparateDot + 1;
+    ExtendNameLen = TempName - ExtendName;
+  }
+  //
+  // We scan the filename for the second time
+  // to check if there exists any extra blanks and dots
+  //
+  while (--TempName >= FileName) {
+    if ((*TempName == L'.' || *TempName == L' ') && (TempName != SeparateDot)) {
+      //
+      // There exist extra blanks and dots
+      //
+      PossibleShortName = FALSE;
+    }
+  }
+
+  if (MainNameLen == 0) {
+    PossibleShortName = FALSE;
+  }
+
+  if (MainNameLen > FAT_MAIN_NAME_LEN) {
+    PossibleShortName = FALSE;
+    MainNameLen       = FAT_MAIN_NAME_LEN;
+  }
+
+  if (ExtendNameLen > FAT_EXTEND_NAME_LEN) {
+    PossibleShortName = FALSE;
+    ExtendNameLen     = FAT_EXTEND_NAME_LEN;
+  }
+
+  if (FatStrToFat (FileName, MainNameLen, File8Dot3Name)) {
+    PossibleShortName = FALSE;
+  }
+
+  if (FatStrToFat (ExtendName, ExtendNameLen, File8Dot3Name + FAT_MAIN_NAME_LEN)) {
+    PossibleShortName = FALSE;
+  }
+
+  return PossibleShortName;
+}
+
+STATIC
+UINTN
+FatTrimAsciiTrailingBlanks (
+  IN CHAR8        *Name,
+  IN UINTN        Len
+  )
+/*++
+
+Routine Description:
+
+  Trim the trailing blanks of fat name.
+
+Arguments:
+
+  Name                  - The Char8 string needs to be trimed.
+  Len                   - The length of the fat name.
+
+Returns:
+
+  The real length of the fat name after the trailing blanks are trimmed.
+
+--*/
+{
+  while (Len > 0 && Name[Len - 1] == ' ') {
+    Len--;
+  }
+
+  return Len;
+}
+
+VOID
+FatNameToStr (
+  IN  CHAR8            *FatName,
+  IN  UINTN            Len,
+  IN  UINTN            LowerCase,
+  OUT CHAR16           *Str
+  )
+/*++
+
+Routine Description:
+
+  Convert the ascii fat name to the unicode string and strip trailing spaces,
+  and if necessary, convert the unicode string to lower case.
+
+Arguments:
+
+  FatName               - The Char8 string needs to be converted.
+  Len                   - The length of the fat name.
+  LowerCase             - Indicate whether to convert the string to lower case.
+  Str                   - The result of the convertion.
+
+Returns:
+
+  None.
+
+--*/
+{
+  //
+  // First, trim the trailing blanks
+  //
+  Len = FatTrimAsciiTrailingBlanks (FatName, Len);
+  //
+  // Convert fat string to unicode string
+  //
+  FatFatToStr (Len, FatName, Str);
+
+  //
+  // If the name is to be lower cased, do it now
+  //
+  if (LowerCase != 0) {
+    FatStrLwr (Str);
+  }
+}
+
+VOID
+FatCreate8Dot3Name (
+  IN FAT_OFILE    *Parent,
+  IN FAT_DIRENT   *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  This function generates 8Dot3 name from user specified name for a newly created file.
+
+Arguments:
+
+  Parent                - The parent directory.
+  DirEnt                - The directory entry whose 8Dot3Name needs to be generated.
+
+Returns:
+
+  None.
+
+--*/
+{
+  CHAR8 *ShortName;
+  CHAR8 *ShortNameChar;
+  UINTN BaseTagLen;
+  UINTN Index;
+  UINTN Retry;
+  UINT8 Segment;
+  union {
+    UINT32  Crc;
+    struct HEX_DATA {
+      UINT8 Segment : HASH_VALUE_TAG_LEN;
+    } Hex[HASH_VALUE_TAG_LEN];
+  } HashValue;
+  //
+  // Make sure the whole directory has been loaded
+  //
+  ASSERT (Parent->ODir->EndOfDir);
+  ShortName = DirEnt->Entry.FileName;
+
+  //
+  // Trim trailing blanks of 8.3 name
+  //
+  BaseTagLen = FatTrimAsciiTrailingBlanks (ShortName, FAT_MAIN_NAME_LEN);
+  if (BaseTagLen > SPEC_BASE_TAG_LEN) {
+    BaseTagLen = SPEC_BASE_TAG_LEN;
+  }
+  //
+  // We first use the algorithm described by spec.
+  //
+  ShortNameChar     = ShortName + BaseTagLen;
+  *ShortNameChar++  = '~';
+  *ShortNameChar    = '1';
+  Retry = 0;
+  while (*FatShortNameHashSearch (Parent->ODir, ShortName) != NULL) {
+    *ShortNameChar = (CHAR8)(*ShortNameChar + 1);
+    if (++Retry == MAX_SPEC_RETRY) {
+      //
+      // We use new algorithm to generate 8.3 name
+      //
+      ASSERT (DirEnt->FileString != NULL);
+      gBS->CalculateCrc32 (DirEnt->FileString, StrSize (DirEnt->FileString), &HashValue.Crc);
+
+      if (BaseTagLen > HASH_BASE_TAG_LEN) {
+        BaseTagLen = HASH_BASE_TAG_LEN;
+      }
+
+      ShortNameChar = ShortName + BaseTagLen;
+      for (Index = 0; Index < HASH_VALUE_TAG_LEN; Index++) {
+        Segment = HashValue.Hex[Index].Segment;
+        if (Segment > 9) {
+          *ShortNameChar++ = (CHAR8)(Segment - 10 + 'A');
+        } else {
+          *ShortNameChar++ = (CHAR8)(Segment + '0');
+        }
+      }
+
+      *ShortNameChar++  = '~';
+      *ShortNameChar    = '1';
+    }
+  }
+}
+
+STATIC
+UINT8
+FatCheckNameCase (
+  IN CHAR16           *Str,
+  IN UINT8            InCaseFlag
+  )
+/*++
+
+Routine Description:
+
+  Check the string is lower case or upper case
+  and it is used by fatname to dir entry count
+
+Arguments:
+
+  Str                   - The string which needs to be checked.
+  InCaseFlag            - The input case flag which is returned when the string is lower case.
+
+Returns:
+
+  OutCaseFlag           - The output case flag.
+
+--*/
+{
+  CHAR16  Buffer[FAT_MAIN_NAME_LEN + 1];
+  UINT8   OutCaseFlag;
+
+  ASSERT (StrSize (Str) <= sizeof (Buffer));
+  //
+  // Assume the case of input string is mixed
+  //
+  OutCaseFlag = FAT_CASE_MIXED;
+  //
+  // Lower case a copy of the string, if it matches the
+  // original then the string is lower case
+  //
+  StrCpy (Buffer, Str);
+  FatStrLwr (Buffer);
+  if (StrCmp (Str, Buffer) == 0) {
+    OutCaseFlag = InCaseFlag;
+  }
+  //
+  // Upper case a copy of the string, if it matches the
+  // original then the string is upper case
+  //
+  StrCpy (Buffer, Str);
+  FatStrUpr (Buffer);
+  if (StrCmp (Str, Buffer) == 0) {
+    OutCaseFlag = 0;
+  }
+
+  return OutCaseFlag;
+}
+
+VOID
+FatSetCaseFlag (
+  IN FAT_DIRENT   *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Set the caseflag value for the directory entry.
+
+Arguments:
+
+  DirEnt                - The logical directory entry whose caseflag value is to be set.
+
+Returns:
+
+  None.
+
+--*/
+{
+  CHAR16  LfnBuffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1];
+  CHAR16  *TempCharPtr;
+  CHAR16  *ExtendName;
+  CHAR16  *FileNameCharPtr;
+  UINT8   CaseFlag;
+
+  ExtendName      = NULL;
+  TempCharPtr     = LfnBuffer;
+  FileNameCharPtr = DirEnt->FileString;
+  ASSERT (StrSize (DirEnt->FileString) <= sizeof (LfnBuffer));
+  while ((*TempCharPtr = *FileNameCharPtr) != 0) {
+    if (*TempCharPtr == L'.') {
+      ExtendName = TempCharPtr;
+    }
+
+    TempCharPtr++;
+    FileNameCharPtr++;
+  }
+
+  CaseFlag = 0;
+  if (ExtendName != NULL) {
+    *ExtendName = 0;
+    ExtendName++;
+    CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (ExtendName, FAT_CASE_EXT_LOWER));
+  }
+
+  CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (LfnBuffer, FAT_CASE_NAME_LOWER));
+  if ((CaseFlag & FAT_CASE_MIXED) == 0) {
+    //
+    // We just need one directory entry to store this file name entry
+    //
+    DirEnt->Entry.CaseFlag = CaseFlag;
+  } else {
+    //
+    // We need one extra directory entry to store the mixed case entry
+    //
+    DirEnt->Entry.CaseFlag = 0;
+    DirEnt->EntryCount++;
+  }
+}
+
+VOID
+FatGetFileNameViaCaseFlag (
+  IN  FAT_DIRENT    *DirEnt,
+  OUT CHAR16        *FileString
+  )
+/*++
+
+Routine Description:
+
+  Convert the 8.3 ASCII fat name to cased Unicode string according to case flag.
+
+Arguments:
+
+  DirEnt                - The corresponding directory entry.
+  FileString            - The output Unicode file name.
+
+Returns:
+
+  None.
+
+--*/
+{
+  UINT8   CaseFlag;
+  CHAR8   *File8Dot3Name;
+  CHAR16  TempExt[1 + FAT_EXTEND_NAME_LEN + 1];
+  //
+  // Store file extension like ".txt"
+  //
+  CaseFlag      = DirEnt->Entry.CaseFlag;
+  File8Dot3Name = DirEnt->Entry.FileName;
+
+  FatNameToStr (File8Dot3Name, FAT_MAIN_NAME_LEN, CaseFlag & FAT_CASE_NAME_LOWER, FileString);
+  FatNameToStr (File8Dot3Name + FAT_MAIN_NAME_LEN, FAT_EXTEND_NAME_LEN, CaseFlag & FAT_CASE_EXT_LOWER, &TempExt[1]);
+  if (TempExt[1] != 0) {
+    TempExt[0] = L'.';
+    StrCat (FileString, TempExt);
+  }
+}
+
+UINT8
+FatCheckSum (
+  IN CHAR8  *ShortNameString
+  )
+/*++
+
+Routine Description:
+
+  Get the Check sum for a short name.
+
+Arguments:
+
+  ShortNameString       - The short name for a file.
+
+Returns:
+
+  Sum                   - UINT8 checksum.
+
+--*/
+{
+  UINTN ShortNameLen;
+  UINT8 Sum;
+  Sum = 0;
+  for (ShortNameLen = FAT_NAME_LEN; ShortNameLen != 0; ShortNameLen--) {
+    Sum = (UINT8)(((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *ShortNameString++);
+  }
+
+  return Sum;
+}
+
+CHAR16 *
+FatGetNextNameComponent (
+  IN  CHAR16      *Path,
+  OUT CHAR16      *Name
+  )
+/*++
+
+Routine Description:
+
+  Takes Path as input, returns the next name component
+  in Name, and returns the position after Name (e.g., the
+  start of the next name component)
+
+Arguments:
+
+  Path                  - The path of one file.
+  Name                  - The next name component in Path.
+
+Returns:
+
+  The position after Name in the Path
+
+--*/
+{
+  while (*Path != 0 && *Path != PATH_NAME_SEPARATOR) {
+    *Name++ = *Path++;
+  }
+  *Name = 0;
+  //
+  // Get off of trailing path name separator
+  //
+  while (*Path == PATH_NAME_SEPARATOR) {
+    Path++;
+  }
+
+  return Path;
+}
+
+BOOLEAN
+FatFileNameIsValid (
+  IN  CHAR16  *InputFileName,
+  OUT CHAR16  *OutputFileName
+  )
+/*++
+
+Routine Description:
+
+  Check whether the IFileName is valid long file name. If the IFileName is a valid
+  long file name, then we trim the possible leading blanks and leading/trailing dots.
+  the trimmed filename is stored in OutputFileName
+
+Arguments:
+
+  InputFileName         - The input file name.
+  OutputFileName        - The output file name.
+
+
+Returns:
+
+  TRUE                  - The InputFileName is a valid long file name.
+  FALSE                 - The InputFileName is not a valid long file name.
+
+--*/
+{
+  CHAR16  *TempNamePointer;
+  CHAR16  TempChar;
+  //
+  // Trim Leading blanks
+  //
+  while (*InputFileName == L' ') {
+    InputFileName++;
+  }
+
+  TempNamePointer = OutputFileName;
+  while (*InputFileName != 0) {
+    *TempNamePointer++ = *InputFileName++;
+  }
+  //
+  // Trim Trailing blanks and dots
+  //
+  while (TempNamePointer > OutputFileName) {
+    TempChar = *(TempNamePointer - 1);
+    if (TempChar != L' ' && TempChar != L'.') {
+      break;
+    }
+
+    TempNamePointer--;
+  }
+
+  *TempNamePointer = 0;
+
+  //
+  // Per FAT Spec the file name should meet the following criteria:
+  //   C1. Length (FileLongName) <= 255
+  //   C2. Length (X:FileFullPath<NUL>) <= 260
+  // Here we check C1.
+  //
+  if (TempNamePointer - OutputFileName > EFI_FILE_STRING_LENGTH) {
+    return FALSE;
+  }
+  //
+  // See if there is any illegal characters within the name
+  //
+  do {
+    if (*OutputFileName < 0x20 ||
+        *OutputFileName == '\"' ||
+        *OutputFileName == '*' ||
+        *OutputFileName == '/' ||
+        *OutputFileName == ':' ||
+        *OutputFileName == '<' ||
+        *OutputFileName == '>' ||
+        *OutputFileName == '?' ||
+        *OutputFileName == '\\' ||
+        *OutputFileName == '|'
+        ) {
+      return FALSE;
+    }
+
+    OutputFileName++;
+  } while (*OutputFileName != 0);
+  return TRUE;
+}

+ 816 - 0
FatPkg/EnhancedFatDxe/FileSpace.c

@@ -0,0 +1,816 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  FileSpace.c
+
+Abstract:
+
+  Routines dealing with disk spaces and FAT table entries
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+
+STATIC
+VOID *
+FatLoadFatEntry (
+  IN FAT_VOLUME       *Volume,
+  IN UINTN            Index
+  )
+/*++
+
+Routine Description:
+
+  Get the FAT entry of the volume, which is identified with the Index.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  Index                 - The index of the FAT entry of the volume.
+
+Returns:
+
+  The buffer of the FAT entry
+
+--*/
+{
+  UINTN       Pos;
+  EFI_STATUS  Status;
+
+  if (Index > (Volume->MaxCluster + 1)) {
+    Volume->FatEntryBuffer = (UINT32) -1;
+    return &Volume->FatEntryBuffer;
+  }
+  //
+  // Compute buffer position needed
+  //
+  switch (Volume->FatType) {
+  case FAT12:
+    Pos = FAT_POS_FAT12 (Index);
+    break;
+
+  case FAT16:
+    Pos = FAT_POS_FAT16 (Index);
+    break;
+
+  default:
+    Pos = FAT_POS_FAT32 (Index);
+  }
+  //
+  // Set the position and read the buffer
+  //
+  Volume->FatEntryPos = Volume->FatPos + Pos;
+  Status = FatDiskIo (
+             Volume,
+             READ_FAT,
+             Volume->FatEntryPos,
+             Volume->FatEntrySize,
+             &Volume->FatEntryBuffer
+             );
+  if (EFI_ERROR (Status)) {
+    Volume->FatEntryBuffer = (UINT32) -1;
+  }
+
+  return &Volume->FatEntryBuffer;
+}
+
+STATIC
+UINTN
+FatGetFatEntry (
+  IN FAT_VOLUME       *Volume,
+  IN UINTN            Index
+  )
+/*++
+
+Routine Description:
+
+  Get the FAT entry value of the volume, which is identified with the Index.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  Index                 - The index of the FAT entry of the volume.
+
+Returns:
+
+  The value of the FAT entry.
+
+--*/
+{
+  VOID    *Pos;
+  UINT8   *E12;
+  UINT16  *E16;
+  UINT32  *E32;
+  UINTN   Accum;
+
+  Pos = FatLoadFatEntry (Volume, Index);
+
+  if (Index > (Volume->MaxCluster + 1)) {
+    return (UINTN) -1;
+  }
+
+  switch (Volume->FatType) {
+  case FAT12:
+    E12   = Pos;
+    Accum = E12[0] | (E12[1] << 8);
+    Accum = FAT_ODD_CLUSTER_FAT12 (Index) ? (Accum >> 4) : (Accum & FAT_CLUSTER_MASK_FAT12);
+    Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT12) ? FAT_CLUSTER_SPECIAL_EXT : 0);
+    break;
+
+  case FAT16:
+    E16   = Pos;
+    Accum = *E16;
+    Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT16) ? FAT_CLUSTER_SPECIAL_EXT : 0);
+    break;
+
+  default:
+    E32   = Pos;
+    Accum = *E32 & FAT_CLUSTER_MASK_FAT32;
+    Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT32) ? FAT_CLUSTER_SPECIAL_EXT : 0);
+  }
+
+  return Accum;
+}
+
+STATIC
+EFI_STATUS
+FatSetFatEntry (
+  IN FAT_VOLUME       *Volume,
+  IN UINTN            Index,
+  IN UINTN            Value
+  )
+/*++
+
+Routine Description:
+
+  Set the FAT entry value of the volume, which is identified with the Index.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  Index                 - The index of the FAT entry of the volume.
+  Value                 - The new value of the FAT entry.
+
+Returns:
+
+  EFI_SUCCESS           - Set the new FAT entry value sucessfully.
+  EFI_VOLUME_CORRUPTED  - The FAT type of the volume is error.
+  other                 - An error occurred when operation the FAT entries.
+
+--*/
+{
+  VOID        *Pos;
+  UINT8       *E12;
+  UINT16      *E16;
+  UINT32      *E32;
+  UINTN       Accum;
+  EFI_STATUS  Status;
+  UINTN       OriginalVal;
+
+  if (Index < FAT_MIN_CLUSTER) {
+    return EFI_VOLUME_CORRUPTED;
+  }
+
+  OriginalVal = FatGetFatEntry (Volume, Index);
+  if (Value == FAT_CLUSTER_FREE && OriginalVal != FAT_CLUSTER_FREE) {
+    Volume->FatInfoSector.FreeInfo.ClusterCount += 1;
+    if (Index < Volume->FatInfoSector.FreeInfo.NextCluster) {
+      Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;
+    }
+  } else if (Value != FAT_CLUSTER_FREE && OriginalVal == FAT_CLUSTER_FREE) {
+    if (Volume->FatInfoSector.FreeInfo.ClusterCount != 0) {
+      Volume->FatInfoSector.FreeInfo.ClusterCount -= 1;
+    }
+  }
+  //
+  // Make sure the entry is in memory
+  //
+  Pos = FatLoadFatEntry (Volume, Index);
+
+  //
+  // Update the value
+  //
+  switch (Volume->FatType) {
+  case FAT12:
+    E12   = Pos;
+    Accum = E12[0] | (E12[1] << 8);
+    Value = Value & FAT_CLUSTER_MASK_FAT12;
+
+    if (FAT_ODD_CLUSTER_FAT12 (Index)) {
+      Accum = (Value << 4) | (Accum & 0xF);
+    } else {
+      Accum = Value | (Accum & FAT_CLUSTER_UNMASK_FAT12);
+    }
+
+    E12[0]  = (UINT8) (Accum & 0xFF);
+    E12[1]  = (UINT8) (Accum >> 8);
+    break;
+
+  case FAT16:
+    E16   = Pos;
+    *E16  = (UINT16) Value;
+    break;
+
+  default:
+    E32   = Pos;
+    *E32  = (*E32 & FAT_CLUSTER_UNMASK_FAT32) | (UINT32) (Value & FAT_CLUSTER_MASK_FAT32);
+  }
+  //
+  // If the volume's dirty bit is not set, set it now
+  //
+  if (!Volume->FatDirty && Volume->FatType != FAT12) {
+    Volume->FatDirty = TRUE;
+    FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->DirtyValue);
+  }
+  //
+  // Write the updated fat entry value to the volume
+  // The fat is the first fat, and other fat will be in sync
+  // when the FAT cache flush back.
+  //
+  Status = FatDiskIo (
+             Volume,
+             WRITE_FAT,
+             Volume->FatEntryPos,
+             Volume->FatEntrySize,
+             &Volume->FatEntryBuffer
+             );
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+FatFreeClusters (
+  IN FAT_VOLUME           *Volume,
+  IN UINTN                Cluster
+  )
+/*++
+
+Routine Description:
+
+  Free the cluster clain.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  Cluster               - The first cluster of cluster chain.
+
+Returns:
+
+  EFI_SUCCESS           - The cluster chain is freed successfully.
+  EFI_VOLUME_CORRUPTED  - There are errors in the file's clusters.
+
+--*/
+{
+  UINTN LastCluster;
+
+  while (!FAT_END_OF_FAT_CHAIN (Cluster)) {
+    if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
+
+      DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    LastCluster = Cluster;
+    Cluster     = FatGetFatEntry (Volume, Cluster);
+    FatSetFatEntry (Volume, LastCluster, FAT_CLUSTER_FREE);
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+UINTN
+FatAllocateCluster (
+  IN FAT_VOLUME   *Volume
+  )
+/*++
+
+Routine Description:
+
+  Allocate a free cluster and return the cluster index.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+
+Returns:
+
+  The index of the free cluster
+
+--*/
+{
+  UINTN Cluster;
+
+  //
+  // Start looking at FatFreePos for the next unallocated cluster
+  //
+  if (Volume->DiskError) {
+    return (UINTN) FAT_CLUSTER_LAST;
+  }
+
+  for (;;) {
+    //
+    // If the end of the list, return no available cluster
+    //
+    if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {
+      if (Volume->FreeInfoValid && 0 < (INT32) (Volume->FatInfoSector.FreeInfo.ClusterCount)) {
+        Volume->FreeInfoValid = FALSE;
+      }
+
+      FatComputeFreeInfo (Volume);
+      if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {
+        return (UINTN) FAT_CLUSTER_LAST;
+      }
+    }
+
+    Cluster = FatGetFatEntry (Volume, Volume->FatInfoSector.FreeInfo.NextCluster);
+    if (Cluster == FAT_CLUSTER_FREE) {
+      break;
+    }
+    //
+    // Try the next cluster
+    //
+    Volume->FatInfoSector.FreeInfo.NextCluster += 1;
+  }
+
+  Cluster = Volume->FatInfoSector.FreeInfo.NextCluster;
+  Volume->FatInfoSector.FreeInfo.NextCluster += 1;
+  return Cluster;
+}
+
+STATIC
+UINTN
+FatSizeToClusters (
+  IN FAT_VOLUME       *Volume,
+  IN UINTN            Size
+  )
+/*++
+
+Routine Description:
+
+  Count the number of clusters given a size
+
+Arguments:
+
+  Volume                - The file system volume.
+  Size                  - The size in bytes.
+
+Returns:
+
+  The number of the clusters.
+
+--*/
+{
+  UINTN Clusters;
+
+  Clusters = Size >> Volume->ClusterAlignment;
+  if ((Size & (Volume->ClusterSize - 1)) > 0) {
+    Clusters += 1;
+  }
+
+  return Clusters;
+}
+
+EFI_STATUS
+FatShrinkEof (
+  IN FAT_OFILE            *OFile
+  )
+/*++
+
+Routine Description:
+
+  Shrink the end of the open file base on the file size.
+
+Arguments:
+
+  OFile                 - The open file.
+
+Returns:
+
+  EFI_SUCCESS           - Shrinked sucessfully.
+  EFI_VOLUME_CORRUPTED  - There are errors in the file's clusters.
+
+--*/
+{
+  FAT_VOLUME  *Volume;
+  UINTN       NewSize;
+  UINTN       CurSize;
+  UINTN       Cluster;
+  UINTN       LastCluster;
+
+  Volume  = OFile->Volume;
+  ASSERT_VOLUME_LOCKED (Volume);
+
+  NewSize = FatSizeToClusters (Volume, OFile->FileSize);
+
+  //
+  // Find the address of the last cluster
+  //
+  Cluster     = OFile->FileCluster;
+  LastCluster = FAT_CLUSTER_FREE;
+
+  if (NewSize != 0) {
+
+    for (CurSize = 0; CurSize < NewSize; CurSize++) {
+      if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
+
+        DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));
+        return EFI_VOLUME_CORRUPTED;
+      }
+
+      LastCluster = Cluster;
+      Cluster     = FatGetFatEntry (Volume, Cluster);
+    }
+
+    FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);
+
+  } else {
+    //
+    // Check to see if the file is already completely truncated
+    //
+    if (Cluster == FAT_CLUSTER_FREE) {
+      return EFI_SUCCESS;
+    }
+    //
+    // The file is being completely truncated.
+    //
+    OFile->FileCluster      = FAT_CLUSTER_FREE;
+  }
+  //
+  // Set CurrentCluster == FileCluster
+  // to force a recalculation of Position related stuffs
+  //
+  OFile->FileCurrentCluster = OFile->FileCluster;
+  OFile->FileLastCluster    = LastCluster;
+  OFile->Dirty              = TRUE;
+  //
+  // Free the remaining cluster chain
+  //
+  return FatFreeClusters (Volume, Cluster);
+}
+
+EFI_STATUS
+FatGrowEof (
+  IN FAT_OFILE            *OFile,
+  IN UINT64               NewSizeInBytes
+  )
+/*++
+
+Routine Description:
+
+  Grow the end of the open file base on the NewSizeInBytes.
+
+Arguments:
+
+  OFile                 - The open file.
+  NewSizeInBytes        - The new size in bytes of the open file.
+
+Returns:
+
+  EFI_SUCCESS           - The file is grown sucessfully.
+  EFI_UNSUPPORTED       - The file size is larger than 4GB.
+  EFI_VOLUME_CORRUPTED  - There are errors in the files' clusters.
+  EFI_VOLUME_FULL       - The volume is full and can not grow the file.
+
+--*/
+{
+  FAT_VOLUME  *Volume;
+  EFI_STATUS  Status;
+  UINTN       Cluster;
+  UINTN       CurSize;
+  UINTN       NewSize;
+  UINTN       LastCluster;
+  UINTN       NewCluster;
+  UINTN       ClusterCount;
+
+  //
+  // For FAT file system, the max file is 4GB.
+  //
+  if (NewSizeInBytes > 0x0FFFFFFFFL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Volume = OFile->Volume;
+  ASSERT_VOLUME_LOCKED (Volume);
+  //
+  // If the file is already large enough, do nothing
+  //
+  CurSize = FatSizeToClusters (Volume, OFile->FileSize);
+  NewSize = FatSizeToClusters (Volume, (UINTN) NewSizeInBytes);
+
+  if (CurSize < NewSize) {
+    //
+    // If we haven't found the files last cluster do it now
+    //
+    if ((OFile->FileCluster != 0) && (OFile->FileLastCluster == 0)) {
+      Cluster       = OFile->FileCluster;
+      ClusterCount  = 0;
+
+      while (!FAT_END_OF_FAT_CHAIN (Cluster)) {
+        if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
+
+          DEBUG (
+            (EFI_D_INIT | EFI_D_ERROR,
+            "FatGrowEof: cluster chain corrupt\n")
+            );
+          Status = EFI_VOLUME_CORRUPTED;
+          goto Done;
+        }
+
+        ClusterCount++;
+        OFile->FileLastCluster  = Cluster;
+        Cluster                 = FatGetFatEntry (Volume, Cluster);
+      }
+
+      if (ClusterCount != CurSize) {
+        DEBUG (
+          (EFI_D_INIT | EFI_D_ERROR,
+          "FatGrowEof: cluster chain size does not match file size\n")
+          );
+        Status = EFI_VOLUME_CORRUPTED;
+        goto Done;
+      }
+
+    }
+    //
+    // Loop until we've allocated enough space
+    //
+    LastCluster = OFile->FileLastCluster;
+
+    while (CurSize < NewSize) {
+      NewCluster = FatAllocateCluster (Volume);
+      if (FAT_END_OF_FAT_CHAIN (NewCluster)) {
+        if (LastCluster != FAT_CLUSTER_FREE) {
+          FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);
+          OFile->FileLastCluster = LastCluster;
+        }
+
+        Status = EFI_VOLUME_FULL;
+        goto Done;
+      }
+
+      if (LastCluster != 0) {
+        FatSetFatEntry (Volume, LastCluster, NewCluster);
+      } else {
+        OFile->FileCluster        = NewCluster;
+        OFile->FileCurrentCluster = NewCluster;
+      }
+
+      LastCluster = NewCluster;
+      CurSize += 1;
+    }
+    //
+    // Terminate the cluster list
+    //
+    FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);
+    OFile->FileLastCluster = LastCluster;
+  }
+
+  OFile->FileSize = (UINTN) NewSizeInBytes;
+  OFile->Dirty    = TRUE;
+  return EFI_SUCCESS;
+
+Done:
+  FatShrinkEof (OFile);
+  return Status;
+}
+
+EFI_STATUS
+FatOFilePosition (
+  IN FAT_OFILE            *OFile,
+  IN UINTN                Position,
+  IN UINTN                PosLimit
+  )
+/*++
+
+Routine Description:
+
+  Seek OFile to requested position, and calculate the number of
+  consecutive clusters from the position in the file
+
+Arguments:
+
+  OFile                 - The open file.
+  Position              - The file's position which will be accessed.
+  PosLimit              - The maximum length current reading/writing may access
+
+Returns:
+
+  EFI_SUCCESS           - Set the info successfully.
+  EFI_VOLUME_CORRUPTED  - Cluster chain corrupt.
+
+--*/
+{
+  FAT_VOLUME  *Volume;
+  UINTN       ClusterSize;
+  UINTN       Cluster;
+  UINTN       StartPos;
+  UINTN       Run;
+
+  Volume      = OFile->Volume;
+  ClusterSize = Volume->ClusterSize;
+
+  ASSERT_VOLUME_LOCKED (Volume);
+
+  //
+  // If this is the fixed root dir, then compute it's position
+  // from it's fixed info in the fat bpb
+  //
+  if (OFile->IsFixedRootDir) {
+    OFile->PosDisk  = Volume->RootPos + Position;
+    Run             = OFile->FileSize - Position;
+  } else {
+    //
+    // Run the file's cluster chain to find the current position
+    // If possible, run from the current cluster rather than
+    // start from beginning
+    // Assumption: OFile->Position is always consistent with
+    // OFile->FileCurrentCluster.
+    // OFile->Position is not modified outside this function;
+    // OFile->FileCurrentCluster is modified outside this function
+    // to be the same as OFile->FileCluster
+    // when OFile->FileCluster is updated, so make a check of this
+    // and invalidate the original OFile->Position in this case
+    //
+    Cluster     = OFile->FileCurrentCluster;
+    StartPos    = OFile->Position;
+    if (Position < StartPos || OFile->FileCluster == Cluster) {
+      StartPos  = 0;
+      Cluster   = OFile->FileCluster;
+    }
+
+    while (StartPos + ClusterSize <= Position) {
+      StartPos += ClusterSize;
+      if (Cluster == FAT_CLUSTER_FREE || (Cluster >= FAT_CLUSTER_SPECIAL)) {
+        DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatOFilePosition:"" cluster chain corrupt\n"));
+        return EFI_VOLUME_CORRUPTED;
+      }
+
+      Cluster = FatGetFatEntry (Volume, Cluster);
+    }
+
+    if (Cluster < FAT_MIN_CLUSTER) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    OFile->PosDisk            = Volume->FirstClusterPos +
+                                LShiftU64 (Cluster - FAT_MIN_CLUSTER, Volume->ClusterAlignment) +
+                                Position - StartPos;
+    OFile->FileCurrentCluster = Cluster;
+    OFile->Position           = StartPos;
+
+    //
+    // Compute the number of consecutive clusters in the file
+    //
+    Run = StartPos + ClusterSize - Position;
+    if (!FAT_END_OF_FAT_CHAIN (Cluster)) {
+      while ((FatGetFatEntry (Volume, Cluster) == Cluster + 1) && Run < PosLimit) {
+        Run     += ClusterSize;
+        Cluster += 1;
+      }
+    }
+  }
+
+  OFile->PosRem = Run;
+  return EFI_SUCCESS;
+}
+
+UINTN
+FatPhysicalDirSize (
+  IN FAT_VOLUME            *Volume,
+  IN UINTN                 Cluster
+  )
+/*++
+
+Routine Description:
+
+ Get the size of directory of the open file
+
+Arguments:
+
+  Volume                - The File System Volume.
+  Cluster               - The Starting cluster.
+
+Returns:
+
+  The physical size of the file starting at the input cluster, if there is error in the
+  cluster chain, the return value is 0.
+
+--*/
+{
+  UINTN Size;
+  ASSERT_VOLUME_LOCKED (Volume);
+  //
+  // Run the cluster chain for the OFile
+  //
+  Size = 0;
+  //
+  // N.B. ".." directories on some media do not contain a starting
+  // cluster.  In the case of "." or ".." we don't need the size anyway.
+  //
+  if (Cluster != 0) {
+    while (!FAT_END_OF_FAT_CHAIN (Cluster)) {
+      if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
+        DEBUG (
+          (EFI_D_INIT | EFI_D_ERROR,
+          "FATDirSize: cluster chain corrupt\n")
+          );
+        return 0;
+      }
+
+      Size += Volume->ClusterSize;
+      Cluster = FatGetFatEntry (Volume, Cluster);
+    }
+  }
+
+  return Size;
+}
+
+UINT64
+FatPhysicalFileSize (
+  IN FAT_VOLUME            *Volume,
+  IN UINTN                 RealSize
+  )
+/*++
+
+Routine Description:
+
+ Get the physical size of a file on the disk.
+
+Arguments:
+
+  Volume                - The file system volume.
+  RealSize              - The real size of a file.
+
+Returns:
+
+  The physical size of a file on the disk.
+
+--*/
+{
+  UINTN   ClusterSizeMask;
+  UINT64  PhysicalSize;
+  ClusterSizeMask = Volume->ClusterSize - 1;
+  PhysicalSize    = (RealSize + ClusterSizeMask) & (~((UINT64) ClusterSizeMask));
+  return PhysicalSize;
+}
+
+VOID
+FatComputeFreeInfo (
+  IN FAT_VOLUME *Volume
+  )
+/*++
+
+Routine Description:
+
+  Update the free cluster info of FatInfoSector of the volume.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+
+Returns:
+
+  None.
+
+--*/
+{
+  UINTN Index;
+
+  //
+  // If we don't have valid info, compute it now
+  //
+  if (!Volume->FreeInfoValid) {
+
+    Volume->FreeInfoValid                        = TRUE;
+    Volume->FatInfoSector.FreeInfo.ClusterCount  = 0;
+    for (Index = Volume->MaxCluster + 1; Index >= FAT_MIN_CLUSTER; Index--) {
+      if (Volume->DiskError) {
+        break;
+      }
+
+      if (FatGetFatEntry (Volume, Index) == FAT_CLUSTER_FREE) {
+        Volume->FatInfoSector.FreeInfo.ClusterCount += 1;
+        Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;
+      }
+    }
+
+    Volume->FatInfoSector.Signature          = FAT_INFO_SIGNATURE;
+    Volume->FatInfoSector.InfoBeginSignature = FAT_INFO_BEGIN_SIGNATURE;
+    Volume->FatInfoSector.InfoEndSignature   = FAT_INFO_END_SIGNATURE;
+  }
+}

+ 480 - 0
FatPkg/EnhancedFatDxe/Flush.c

@@ -0,0 +1,480 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  flush.c
+
+Abstract:
+
+  Routines that check references and flush OFiles
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatFlush (
+  IN EFI_FILE  *FHand
+  )
+/*++
+
+Routine Description:
+
+  Flushes all data associated with the file handle.
+
+Arguments:
+
+  FHand                 - Handle to file to flush.
+
+Returns:
+
+  EFI_SUCCESS           - Flushed the file successfully.
+  EFI_WRITE_PROTECTED   - The volume is read only.
+  EFI_ACCESS_DENIED     - The file is read only.
+  Others                - Flushing of the file failed.
+
+--*/
+{
+  FAT_IFILE   *IFile;
+  FAT_OFILE   *OFile;
+  FAT_VOLUME  *Volume;
+  EFI_STATUS  Status;
+
+  IFile   = IFILE_FROM_FHAND (FHand);
+  OFile   = IFile->OFile;
+  Volume  = OFile->Volume;
+
+  //
+  // If the file has a permanent error, return it
+  //
+  if (EFI_ERROR (OFile->Error)) {
+    return OFile->Error;
+  }
+
+  if (Volume->ReadOnly) {
+    return EFI_WRITE_PROTECTED;
+  }
+  //
+  // If read only, return error
+  //
+  if (IFile->ReadOnly) {
+    return EFI_ACCESS_DENIED;
+  }
+  //
+  // Flush the OFile
+  //
+  FatAcquireLock ();
+  Status  = FatOFileFlush (OFile);
+  Status  = FatCleanupVolume (OFile->Volume, OFile, Status);
+  FatReleaseLock ();
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatClose (
+  IN EFI_FILE  *FHand
+  )
+/*++
+
+Routine Description:
+
+  Flushes & Closes the file handle.
+
+Arguments:
+
+  FHand                 - Handle to the file to delete.
+
+Returns:
+
+  EFI_SUCCESS           - Closed the file successfully.
+
+--*/
+{
+  FAT_IFILE   *IFile;
+  FAT_OFILE   *OFile;
+  FAT_VOLUME  *Volume;
+
+  IFile   = IFILE_FROM_FHAND (FHand);
+  OFile   = IFile->OFile;
+  Volume  = OFile->Volume;
+
+  //
+  // Lock the volume
+  //
+  FatAcquireLock ();
+
+  //
+  // Close the file instance handle
+  //
+  FatIFileClose (IFile);
+
+  //
+  // Done. Unlock the volume
+  //
+  FatCleanupVolume (Volume, OFile, EFI_SUCCESS);
+  FatReleaseLock ();
+
+  //
+  // Close always succeed
+  //
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatIFileClose (
+  FAT_IFILE           *IFile
+  )
+/*++
+
+Routine Description:
+
+  Close the open file instance.
+
+Arguments:
+
+  IFile                 - Open file instance.
+
+Returns:
+
+  EFI_SUCCESS           - Closed the file successfully.
+
+--*/
+{
+  FAT_OFILE   *OFile;
+  FAT_VOLUME  *Volume;
+
+  OFile   = IFile->OFile;
+  Volume  = OFile->Volume;
+
+  ASSERT_VOLUME_LOCKED (Volume);
+
+  //
+  // Remove the IFile struct
+  //
+  RemoveEntryList (&IFile->Link);
+
+  //
+  // Add the OFile to the check reference list
+  //
+  if (OFile->CheckLink.ForwardLink == NULL) {
+    InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);
+  }
+  //
+  // Done. Free the open instance structure
+  //
+  FreePool (IFile);
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatOFileFlush (
+  IN FAT_OFILE    *OFile
+  )
+/*++
+
+Routine Description:
+
+  Flush the data associated with an open file.
+  In this implementation, only last Mod/Access time is updated.
+
+Arguments:
+
+  OFile                 - The open file.
+
+Returns:
+
+  EFI_SUCCESS           - The OFile is flushed successfully.
+  Others                - An error occurred when flushing this OFile.
+
+--*/
+{
+  EFI_STATUS    Status;
+  FAT_OFILE     *Parent;
+  FAT_DIRENT    *DirEnt;
+  FAT_DATE_TIME FatNow;
+
+  //
+  // Flush each entry up the tree while dirty
+  //
+  do {
+    //
+    // If the file has a permanant error, then don't write any
+    // of its data to the device (may be from different media)
+    //
+    if (EFI_ERROR (OFile->Error)) {
+      return OFile->Error;
+    }
+
+    Parent  = OFile->Parent;
+    DirEnt  = OFile->DirEnt;
+    if (OFile->Dirty) {
+      //
+      // Update the last modification time
+      //
+      FatGetCurrentFatTime (&FatNow);
+      CopyMem (&DirEnt->Entry.FileLastAccess, &FatNow.Date, sizeof (FAT_DATE));
+      if (!OFile->PreserveLastModification) {
+        FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime);
+      }
+
+      OFile->PreserveLastModification = FALSE;
+      if (OFile->Archive) {
+        DirEnt->Entry.Attributes |= FAT_ATTRIBUTE_ARCHIVE;
+        OFile->Archive = FALSE;
+      }
+      //
+      // Write the directory entry
+      //
+      if (Parent != NULL && !DirEnt->Invalid) {
+        //
+        // Write the OFile's directory entry
+        //
+        Status = FatStoreDirEnt (Parent, DirEnt);
+        if (EFI_ERROR (Status)) {
+          return Status;
+        }
+      }
+
+      OFile->Dirty = FALSE;
+    }
+    //
+    // Check the parent
+    //
+    OFile = Parent;
+  } while (OFile != NULL);
+  return EFI_SUCCESS;
+}
+
+BOOLEAN
+FatCheckOFileRef (
+  IN FAT_OFILE   *OFile
+  )
+/*++
+
+Routine Description:
+
+  Check the references of the OFile.
+  If the OFile (that is checked) is no longer
+  referenced, then it is freed.
+
+Arguments:
+
+  OFile                 - The OFile to be checked.
+
+Returns:
+
+  TRUE                  - The OFile is not referenced and freed.
+  FALSE                 - The OFile is kept.
+
+--*/
+{
+  //
+  // If the OFile is on the check ref list, remove it
+  //
+  if (OFile->CheckLink.ForwardLink != NULL) {
+    RemoveEntryList (&OFile->CheckLink);
+    OFile->CheckLink.ForwardLink = NULL;
+  }
+
+  FatOFileFlush (OFile);
+  //
+  // Are there any references to this OFile?
+  //
+  if (!IsListEmpty (&OFile->Opens) || !IsListEmpty (&OFile->ChildHead)) {
+    //
+    // The OFile cannot be freed
+    //
+    return FALSE;
+  }
+  //
+  // Free the Ofile
+  //
+  FatCloseDirEnt (OFile->DirEnt);
+  return TRUE;
+}
+
+STATIC
+VOID
+FatCheckVolumeRef (
+  IN FAT_VOLUME   *Volume
+  )
+/*++
+
+Routine Description:
+
+  Check the references of all open files on the volume.
+  Any open file (that is checked) that is no longer
+  referenced, is freed - and it's parent open file
+  is then referenced checked.
+
+Arguments:
+
+  Volume                - The volume to check the pending open file list.
+
+Returns:
+
+  None
+
+--*/
+{
+  FAT_OFILE *OFile;
+  FAT_OFILE *Parent;
+
+  //
+  // Check all files on the pending check list
+  //
+  while (!IsListEmpty (&Volume->CheckRef)) {
+    //
+    // Start with the first file listed
+    //
+    Parent = OFILE_FROM_CHECKLINK (Volume->CheckRef.ForwardLink);
+    //
+    // Go up the tree cleaning up any un-referenced OFiles
+    //
+    while (Parent != NULL) {
+      OFile   = Parent;
+      Parent  = OFile->Parent;
+      if (!FatCheckOFileRef (OFile)) {
+        break;
+      }
+    }
+  }
+}
+
+EFI_STATUS
+FatCleanupVolume (
+  IN FAT_VOLUME       *Volume,
+  IN FAT_OFILE        *OFile,
+  IN EFI_STATUS       EfiStatus
+  )
+/*++
+
+Routine Description:
+
+  Set error status for a specific OFile, reference checking the volume.
+  If volume is already marked as invalid, and all resources are freed
+  after reference checking, the file system protocol is uninstalled and
+  the volume structure is freed.
+
+Arguments:
+
+  Volume                - the Volume that is to be reference checked and unlocked.
+  OFile                 - the OFile whose permanent error code is to be set.
+  EfiStatus             - error code to be set.
+
+Returns:
+
+  EFI_SUCCESS           - Clean up the volume successfully.
+  Others                - Cleaning up of the volume is failed.
+
+--*/
+{
+  EFI_STATUS  Status;
+  //
+  // Flag the OFile
+  //
+  if (OFile != NULL) {
+    FatSetVolumeError (OFile, EfiStatus);
+  }
+  //
+  // Clean up any dangling OFiles that don't have IFiles
+  // we don't check return status here because we want the
+  // volume be cleaned up even the volume is invalid.
+  //
+  FatCheckVolumeRef (Volume);
+  if (Volume->Valid) {
+    //
+    // Update the free hint info. Volume->FreeInfoPos != 0
+    // indicates this a FAT32 volume
+    //
+    if (Volume->FreeInfoValid && Volume->FatDirty && Volume->FreeInfoPos) {
+      Status = FatDiskIo (Volume, WRITE_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    }
+    //
+    // Update that the volume is not dirty
+    //
+    if (Volume->FatDirty && Volume->FatType != FAT12) {
+      Volume->FatDirty  = FALSE;
+      Status            = FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->NotDirtyValue);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    }
+    //
+    // Flush all dirty cache entries to disk
+    //
+    Status = FatVolumeFlushCache (Volume);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+  //
+  // If the volume is cleared , remove it.
+  // The only time volume be invalidated is in DriverBindingStop.
+  //
+  if (Volume->Root == NULL && !Volume->Valid) {
+    //
+    // Free the volume structure
+    //
+    FatFreeVolume (Volume);
+  }
+
+  return EfiStatus;
+}
+
+VOID
+FatSetVolumeError (
+  IN FAT_OFILE            *OFile,
+  IN EFI_STATUS           Status
+  )
+/*++
+
+Routine Description:
+
+  Set the OFile and its child OFile with the error Status
+
+Arguments:
+
+  OFile                 - The OFile whose permanent error code is to be set.
+  Status                - Error code to be set.
+
+Returns:
+
+  None
+
+--*/
+{
+  LIST_ENTRY      *Link;
+  FAT_OFILE       *ChildOFile;
+
+  //
+  // If this OFile doesn't already have an error, set one
+  //
+  if (!EFI_ERROR (OFile->Error)) {
+    OFile->Error = Status;
+  }
+  //
+  // Set the error on each child OFile
+  //
+  for (Link = OFile->ChildHead.ForwardLink; Link != &OFile->ChildHead; Link = Link->ForwardLink) {
+    ChildOFile = OFILE_FROM_CHILDLINK (Link);
+    FatSetVolumeError (ChildOFile, Status);
+  }
+}

+ 217 - 0
FatPkg/EnhancedFatDxe/Hash.c

@@ -0,0 +1,217 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  Hash.c
+
+Abstract:
+
+  Hash table operations
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+STATIC
+UINT32
+FatHashLongName (
+  IN CHAR16   *LongNameString
+  )
+/*++
+
+Routine Description:
+
+  Get hash value for long name.
+
+Arguments:
+
+  LongNameString        - The long name string to be hashed.
+
+Returns:
+
+  HashValue.
+
+--*/
+{
+  UINT32  HashValue;
+  CHAR16  UpCasedLongFileName[EFI_PATH_STRING_LENGTH];
+  StrCpy (UpCasedLongFileName, LongNameString);
+  FatStrUpr (UpCasedLongFileName);
+  gBS->CalculateCrc32 (UpCasedLongFileName, StrSize (UpCasedLongFileName), &HashValue);
+  return (HashValue & HASH_TABLE_MASK);
+}
+
+STATIC
+UINT32
+FatHashShortName (
+  IN CHAR8   *ShortNameString
+  )
+/*++
+
+Routine Description:
+
+  Get hash value for short name.
+
+Arguments:
+
+  ShortNameString       - The short name string to be hashed.
+
+Returns:
+
+  HashValue
+
+--*/
+{
+  UINT32  HashValue;
+  gBS->CalculateCrc32 (ShortNameString, FAT_NAME_LEN, &HashValue);
+  return (HashValue & HASH_TABLE_MASK);
+}
+
+FAT_DIRENT **
+FatLongNameHashSearch (
+  IN FAT_ODIR       *ODir,
+  IN CHAR16         *LongNameString
+  )
+/*++
+
+Routine Description:
+
+  Search the long name hash table for the directory entry.
+
+Arguments:
+
+  ODir                  - The directory to be searched.
+  LongNameString        - The long name string to search.
+
+Returns:
+
+  The previous long name hash node of the directory entry.
+
+--*/
+{
+  FAT_DIRENT  **PreviousHashNode;
+  for (PreviousHashNode   = &ODir->LongNameHashTable[FatHashLongName (LongNameString)];
+       *PreviousHashNode != NULL;
+       PreviousHashNode   = &(*PreviousHashNode)->LongNameForwardLink
+      ) {
+    if (FatStriCmp (LongNameString, (*PreviousHashNode)->FileString) == 0) {
+      break;
+    }
+  }
+
+  return PreviousHashNode;
+}
+
+FAT_DIRENT **
+FatShortNameHashSearch (
+  IN FAT_ODIR      *ODir,
+  IN CHAR8         *ShortNameString
+  )
+/*++
+
+Routine Description:
+
+  Search the short name hash table for the directory entry.
+
+Arguments:
+
+  ODir                  - The directory to be searched.
+  ShortNameString       - The short name string to search.
+
+Returns:
+
+  The previous short name hash node of the directory entry.
+
+--*/
+{
+  FAT_DIRENT  **PreviousHashNode;
+  for (PreviousHashNode   = &ODir->ShortNameHashTable[FatHashShortName (ShortNameString)];
+       *PreviousHashNode != NULL;
+       PreviousHashNode   = &(*PreviousHashNode)->ShortNameForwardLink
+      ) {
+    if (CompareMem (ShortNameString, (*PreviousHashNode)->Entry.FileName, FAT_NAME_LEN) == 0) {
+      break;
+    }
+  }
+
+  return PreviousHashNode;
+}
+
+VOID
+FatInsertToHashTable (
+  IN FAT_ODIR     *ODir,
+  IN FAT_DIRENT   *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Insert directory entry to hash table.
+
+Arguments:
+
+  ODir                  - The parent directory.
+  DirEnt                - The directory entry node.
+
+Returns:
+
+  None.
+
+--*/
+{
+  FAT_DIRENT  **HashTable;
+  UINT32      HashTableIndex;
+
+  //
+  // Insert hash table index for short name
+  //
+  HashTableIndex                = FatHashShortName (DirEnt->Entry.FileName);
+  HashTable                     = ODir->ShortNameHashTable;
+  DirEnt->ShortNameForwardLink  = HashTable[HashTableIndex];
+  HashTable[HashTableIndex]     = DirEnt;
+  //
+  // Insert hash table index for long name
+  //
+  HashTableIndex                = FatHashLongName (DirEnt->FileString);
+  HashTable                     = ODir->LongNameHashTable;
+  DirEnt->LongNameForwardLink   = HashTable[HashTableIndex];
+  HashTable[HashTableIndex]     = DirEnt;
+}
+
+VOID
+FatDeleteFromHashTable (
+  IN FAT_ODIR     *ODir,
+  IN FAT_DIRENT   *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Delete directory entry from hash table.
+
+Arguments:
+
+  ODir                  - The parent directory.
+  DirEnt                - The directory entry node.
+
+Returns:
+
+  None.
+
+--*/
+{
+  *FatShortNameHashSearch (ODir, DirEnt->Entry.FileName) = DirEnt->ShortNameForwardLink;
+  *FatLongNameHashSearch (ODir, DirEnt->FileString)      = DirEnt->LongNameForwardLink;
+}

+ 625 - 0
FatPkg/EnhancedFatDxe/Info.c

@@ -0,0 +1,625 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  Info.c
+
+Abstract:
+
+  Routines dealing with setting/getting file/volume info
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+FatGetVolumeInfo (
+  IN FAT_VOLUME       *Volume,
+  IN OUT UINTN        *BufferSize,
+  OUT VOID            *Buffer
+  );
+
+EFI_STATUS
+FatSetVolumeInfo (
+  IN FAT_VOLUME       *Volume,
+  IN OUT UINTN        BufferSize,
+  OUT VOID            *Buffer
+  );
+
+EFI_STATUS
+FatSetOrGetInfo (
+  IN BOOLEAN    IsSet,
+  IN EFI_FILE   *FHand,
+  IN EFI_GUID   *Type,
+  IN OUT UINTN  *BufferSize,
+  IN OUT VOID   *Buffer
+  );
+
+EFI_STATUS
+FatGetFileInfo (
+  IN FAT_OFILE        *OFile,
+  IN OUT UINTN        *BufferSize,
+  OUT VOID            *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the open file's info into Buffer.
+
+Arguments:
+
+  OFile                 - The open file.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing file info.
+
+Returns:
+
+  EFI_SUCCESS           - Get the file info successfully.
+  EFI_BUFFER_TOO_SMALL  - The buffer is too small.
+
+--*/
+{
+  return FatGetDirEntInfo (OFile->Volume, OFile->DirEnt, BufferSize, Buffer);
+}
+
+EFI_STATUS
+FatGetVolumeInfo (
+  IN     FAT_VOLUME     *Volume,
+  IN OUT UINTN          *BufferSize,
+     OUT VOID           *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the volume's info into Buffer.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing volume info.
+
+Returns:
+
+  EFI_SUCCESS           - Get the volume info successfully.
+  EFI_BUFFER_TOO_SMALL  - The buffer is too small.
+
+--*/
+{
+  UINTN                 Size;
+  UINTN                 NameSize;
+  UINTN                 ResultSize;
+  CHAR16                Name[FAT_NAME_LEN + 1];
+  EFI_STATUS            Status;
+  EFI_FILE_SYSTEM_INFO  *Info;
+  UINT8                 ClusterAlignment;
+
+  Size              = SIZE_OF_EFI_FILE_SYSTEM_INFO;
+  Status            = FatGetVolumeEntry (Volume, Name);
+  NameSize          = StrSize (Name);
+  ResultSize        = Size + NameSize;
+  ClusterAlignment  = Volume->ClusterAlignment;
+
+  //
+  // If we don't have valid info, compute it now
+  //
+  FatComputeFreeInfo (Volume);
+
+  Status = EFI_BUFFER_TOO_SMALL;
+  if (*BufferSize >= ResultSize) {
+    Status  = EFI_SUCCESS;
+
+    Info    = Buffer;
+    ZeroMem (Info, SIZE_OF_EFI_FILE_SYSTEM_INFO);
+
+    Info->Size        = ResultSize;
+    Info->ReadOnly    = Volume->ReadOnly;
+    Info->BlockSize   = (UINT32) Volume->ClusterSize;
+    Info->VolumeSize  = LShiftU64 (Volume->MaxCluster, ClusterAlignment);
+    Info->FreeSpace   = LShiftU64 (
+                          Volume->FatInfoSector.FreeInfo.ClusterCount,
+                          ClusterAlignment
+                          );
+    CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);
+  }
+
+  *BufferSize = ResultSize;
+  return Status;
+}
+
+EFI_STATUS
+FatGetVolumeLabelInfo (
+  IN FAT_VOLUME       *Volume,
+  IN OUT UINTN        *BufferSize,
+  OUT VOID            *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the volume's label info into Buffer.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing volume's label info.
+
+Returns:
+
+  EFI_SUCCESS           - Get the volume's label info successfully.
+  EFI_BUFFER_TOO_SMALL  - The buffer is too small.
+
+--*/
+{
+  UINTN                             Size;
+  UINTN                             NameSize;
+  UINTN                             ResultSize;
+  CHAR16                            Name[FAT_NAME_LEN + 1];
+  EFI_STATUS                        Status;
+
+  Size        = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO;
+  Status      = FatGetVolumeEntry (Volume, Name);
+  NameSize    = StrSize (Name);
+  ResultSize  = Size + NameSize;
+
+  Status      = EFI_BUFFER_TOO_SMALL;
+  if (*BufferSize >= ResultSize) {
+    Status  = EFI_SUCCESS;
+    CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);
+  }
+
+  *BufferSize = ResultSize;
+  return Status;
+}
+
+EFI_STATUS
+FatSetVolumeInfo (
+  IN FAT_VOLUME       *Volume,
+  IN UINTN            BufferSize,
+  IN VOID             *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Set the volume's info.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing the new volume info.
+
+Returns:
+
+  EFI_SUCCESS           - Set the volume info successfully.
+  EFI_BAD_BUFFER_SIZE   - The buffer size is error.
+  EFI_WRITE_PROTECTED   - The volume is read only.
+  other                 - An error occurred when operation the disk.
+
+--*/
+{
+  EFI_FILE_SYSTEM_INFO  *Info;
+
+  Info = (EFI_FILE_SYSTEM_INFO *) Buffer;
+
+  if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + 2 || Info->Size > BufferSize) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  return FatSetVolumeEntry (Volume, Info->VolumeLabel);
+}
+
+EFI_STATUS
+FatSetVolumeLabelInfo (
+  IN FAT_VOLUME       *Volume,
+  IN UINTN            BufferSize,
+  IN VOID             *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Set the volume's label info
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing the new volume label info.
+
+Returns:
+
+  EFI_SUCCESS           - Set the volume label info successfully.
+  EFI_WRITE_PROTECTED   - The disk is write protected.
+  EFI_BAD_BUFFER_SIZE   - The buffer size is error.
+  other                 - An error occurred when operation the disk.
+
+--*/
+{
+  EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Info;
+
+  Info = (EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *) Buffer;
+
+  if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 2) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  return FatSetVolumeEntry (Volume, Info->VolumeLabel);
+}
+
+EFI_STATUS
+FatSetFileInfo (
+  IN FAT_VOLUME       *Volume,
+  IN FAT_IFILE        *IFile,
+  IN FAT_OFILE        *OFile,
+  IN UINTN            BufferSize,
+  IN VOID             *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Set the file info.
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  IFile                 - The instance of the open file.
+  OFile                 - The open file.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing the new file info.
+
+Returns:
+
+  EFI_SUCCESS           - Set the file info successfully.
+  EFI_ACCESS_DENIED     - It is the root directory
+                          or the directory attribute bit can not change
+                          or try to change a directory size
+                          or something else.
+  EFI_UNSUPPORTED       - The new file size is larger than 4GB.
+  EFI_WRITE_PROTECTED   - The disk is write protected.
+  EFI_BAD_BUFFER_SIZE   - The buffer size is error.
+  EFI_INVALID_PARAMETER - The time info or attributes info is error.
+  EFI_OUT_OF_RESOURCES  - Can not allocate new memory.
+  EFI_VOLUME_CORRUPTED  - The volume is corrupted.
+  other                 - An error occurred when operation the disk.
+
+--*/
+{
+  EFI_STATUS    Status;
+  EFI_FILE_INFO *NewInfo;
+  FAT_OFILE     *DotOFile;
+  FAT_OFILE     *Parent;
+  CHAR16        NewFileName[EFI_PATH_STRING_LENGTH];
+  EFI_TIME      ZeroTime;
+  FAT_DIRENT    *DirEnt;
+  FAT_DIRENT    *TempDirEnt;
+  UINT8         NewAttribute;
+  BOOLEAN       ReadOnly;
+
+  ZeroMem (&ZeroTime, sizeof (EFI_TIME));
+  Parent  = OFile->Parent;
+  DirEnt  = OFile->DirEnt;
+  //
+  // If this is the root directory, we can't make any updates
+  //
+  if (Parent == NULL) {
+    return EFI_ACCESS_DENIED;
+  }
+  //
+  // Make sure there's a valid input buffer
+  //
+  NewInfo = Buffer;
+  if (BufferSize < SIZE_OF_EFI_FILE_INFO + 2 || NewInfo->Size > BufferSize) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  ReadOnly = (BOOLEAN)(IFile->ReadOnly || (DirEnt->Entry.Attributes & EFI_FILE_READ_ONLY));
+  //
+  // if a zero time is specified, then the original time is preserved
+  //
+  if (CompareMem (&ZeroTime, &NewInfo->CreateTime, sizeof (EFI_TIME)) != 0) {
+    if (!FatIsValidTime (&NewInfo->CreateTime)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (!ReadOnly) {
+      FatEfiTimeToFatTime (&NewInfo->CreateTime, &DirEnt->Entry.FileCreateTime);
+    }
+  }
+
+  if (CompareMem (&ZeroTime, &NewInfo->ModificationTime, sizeof (EFI_TIME)) != 0) {
+    if (!FatIsValidTime (&NewInfo->ModificationTime)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (!ReadOnly) {
+      FatEfiTimeToFatTime (&NewInfo->ModificationTime, &DirEnt->Entry.FileModificationTime);
+    }
+
+    OFile->PreserveLastModification = TRUE;
+  }
+
+  if (NewInfo->Attribute & (~EFI_FILE_VALID_ATTR)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  NewAttribute = (UINT8) NewInfo->Attribute;
+  //
+  // Can not change the directory attribute bit
+  //
+  if ((NewAttribute ^ DirEnt->Entry.Attributes) & EFI_FILE_DIRECTORY) {
+    return EFI_ACCESS_DENIED;
+  }
+  //
+  // Set the current attributes even if the IFile->ReadOnly is TRUE
+  //
+  DirEnt->Entry.Attributes = (UINT8) ((DirEnt->Entry.Attributes &~EFI_FILE_VALID_ATTR) | NewAttribute);
+  //
+  // Open the filename and see if it refers to an existing file
+  //
+  Status = FatLocateOFile (&Parent, NewInfo->FileName, DirEnt->Entry.Attributes, NewFileName);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (*NewFileName != 0) {
+    //
+    // File was not found.  We do not allow rename of the current directory if
+    // there are open files below the current directory
+    //
+    if (!IsListEmpty (&OFile->ChildHead) || Parent == OFile) {
+      return EFI_ACCESS_DENIED;
+    }
+
+    if (ReadOnly) {
+      return EFI_ACCESS_DENIED;
+    }
+
+    Status = FatRemoveDirEnt (OFile->Parent, DirEnt);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    //
+    // Create new dirent
+    //
+    Status = FatCreateDirEnt (Parent, NewFileName, DirEnt->Entry.Attributes, &TempDirEnt);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    FatCloneDirEnt (TempDirEnt, DirEnt);
+    FatFreeDirEnt (DirEnt);
+    DirEnt        = TempDirEnt;
+    DirEnt->OFile = OFile;
+    OFile->DirEnt = DirEnt;
+    OFile->Parent = Parent;
+    RemoveEntryList (&OFile->ChildLink);
+    InsertHeadList (&Parent->ChildHead, &OFile->ChildLink);
+    //
+    // If this is a directory, synchronize its dot directory entry
+    //
+    if (OFile->ODir != NULL) {
+      //
+      // Syncronize its dot entry
+      //
+      FatResetODirCursor (OFile);
+      ASSERT (OFile->Parent != NULL);
+      for (DotOFile = OFile; DotOFile != OFile->Parent->Parent; DotOFile = DotOFile->Parent) {
+        Status = FatGetNextDirEnt (OFile, &DirEnt);
+        if (EFI_ERROR (Status) || DirEnt == NULL || !FatIsDotDirEnt (DirEnt)) {
+          return EFI_VOLUME_CORRUPTED;
+        }
+
+        FatCloneDirEnt (DirEnt, DotOFile->DirEnt);
+        Status = FatStoreDirEnt (OFile, DirEnt);
+        if (EFI_ERROR (Status)) {
+          return Status;
+        }
+      }
+    }
+    //
+    // If the file is renamed, we should append the ARCHIVE attribute
+    //
+    OFile->Archive = TRUE;
+  } else if (Parent != OFile) {
+    //
+    // filename is to a different filename that already exists
+    //
+    return EFI_ACCESS_DENIED;
+  }
+  //
+  // If the file size has changed, apply it
+  //
+  if (NewInfo->FileSize != OFile->FileSize) {
+    if (OFile->ODir != NULL || ReadOnly) {
+      //
+      // If this is a directory or the file is read only, we can't change the file size
+      //
+      return EFI_ACCESS_DENIED;
+    }
+
+    if (NewInfo->FileSize > OFile->FileSize) {
+      Status = FatExpandOFile (OFile, NewInfo->FileSize);
+    } else {
+      Status = FatTruncateOFile (OFile, (UINTN) NewInfo->FileSize);
+    }
+
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    FatUpdateDirEntClusterSizeInfo (OFile);
+  }
+
+  OFile->Dirty = TRUE;
+  return FatOFileFlush (OFile);
+}
+
+EFI_STATUS
+FatSetOrGetInfo (
+  IN     BOOLEAN        IsSet,
+  IN     EFI_FILE       *FHand,
+  IN     EFI_GUID       *Type,
+  IN OUT UINTN          *BufferSize,
+  IN OUT VOID           *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Set or Get the some types info of the file into Buffer
+
+Arguments:
+
+  IsSet      - TRUE:The access is set, else is get
+  FHand      - The handle of file
+  Type       - The type of the info
+  BufferSize - Size of Buffer
+  Buffer     - Buffer containing volume info
+
+Returns:
+
+  EFI_SUCCESS       - Get the info successfully
+  EFI_DEVICE_ERROR  - Can not find the OFile for the file
+
+--*/
+{
+  FAT_IFILE   *IFile;
+  FAT_OFILE   *OFile;
+  FAT_VOLUME  *Volume;
+  EFI_STATUS  Status;
+
+  IFile   = IFILE_FROM_FHAND (FHand);
+  OFile   = IFile->OFile;
+  Volume  = OFile->Volume;
+
+  Status  = OFile->Error;
+  if (Status == EFI_NOT_FOUND) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  FatAcquireLock ();
+
+  //
+  // Verify the file handle isn't in an error state
+  //
+  if (!EFI_ERROR (Status)) {
+    //
+    // Get the proper information based on the request
+    //
+    Status = EFI_UNSUPPORTED;
+    if (IsSet) {
+      if (Volume->ReadOnly) {
+        Status = EFI_WRITE_PROTECTED;
+      } else {
+        if (CompareGuid (Type, &gEfiFileInfoGuid)) {
+          Status = FatSetFileInfo (Volume, IFile, OFile, *BufferSize, Buffer);
+        }
+
+        if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {
+          Status = FatSetVolumeInfo (Volume, *BufferSize, Buffer);
+        }
+
+        if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+          Status = FatSetVolumeLabelInfo (Volume, *BufferSize, Buffer);
+        }
+      }
+    } else {
+      if (CompareGuid (Type, &gEfiFileInfoGuid)) {
+        Status = FatGetFileInfo (OFile, BufferSize, Buffer);
+      }
+
+      if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {
+        Status = FatGetVolumeInfo (Volume, BufferSize, Buffer);
+      }
+
+      if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+        Status = FatGetVolumeLabelInfo (Volume, BufferSize, Buffer);
+      }
+    }
+  }
+
+  Status = FatCleanupVolume (Volume, NULL, Status);
+
+  FatReleaseLock ();
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatGetInfo (
+  IN     EFI_FILE       *FHand,
+  IN     EFI_GUID       *Type,
+  IN OUT UINTN          *BufferSize,
+     OUT VOID           *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the some types info of the file into Buffer.
+
+Arguments:
+
+  FHand                 - The handle of file.
+  Type                  - The type of the info.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing volume info.
+
+Returns:
+
+  EFI_SUCCESS           - Get the info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+
+--*/
+{
+  return FatSetOrGetInfo (FALSE, FHand, Type, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+FatSetInfo (
+  IN EFI_FILE  *FHand,
+  IN EFI_GUID  *Type,
+  IN UINTN     BufferSize,
+  IN VOID      *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Set the some types info of the file into Buffer.
+
+Arguments:
+
+  FHand                 - The handle of file.
+  Type                  - The type of the info.
+  BufferSize            - Size of Buffer
+  Buffer                - Buffer containing volume info.
+
+Returns:
+
+  EFI_SUCCESS           - Set the info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+
+--*/
+{
+  return FatSetOrGetInfo (TRUE, FHand, Type, &BufferSize, Buffer);
+}

+ 431 - 0
FatPkg/EnhancedFatDxe/Init.c

@@ -0,0 +1,431 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  Init.c
+
+Abstract:
+
+  Initialization routines
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+FatAllocateVolume (
+  IN  EFI_HANDLE                Handle,
+  IN  EFI_DISK_IO_PROTOCOL      *DiskIo,
+  IN  EFI_BLOCK_IO_PROTOCOL     *BlockIo
+  )
+/*++
+
+Routine Description:
+
+  Allocates volume structure, detects FAT file system, installs protocol,
+  and initialize cache.
+
+Arguments:
+
+  Handle                - The handle of parent device.
+  DiskIo                - The DiskIo of parent device.
+  BlockIo               - The BlockIo of parent devicel
+
+Returns:
+
+  EFI_SUCCESS           - Allocate a new volume successfully.
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory.
+  Others                - Allocating a new volume failed.
+
+--*/
+{
+  EFI_STATUS  Status;
+  FAT_VOLUME  *Volume;
+  BOOLEAN     LockedByMe;
+  LockedByMe = FALSE;
+  //
+  // Allocate a volume structure
+  //
+  Volume = AllocateZeroPool (sizeof (FAT_VOLUME));
+  if (Volume == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  //
+  // Acquire the lock.
+  // If caller has already acquired the lock, cannot lock it again.
+  //
+  if (!FatIsLocked ()) {
+    FatAcquireLock ();
+    LockedByMe = TRUE;
+  }
+  //
+  // Initialize the structure
+  //
+  Volume->Signature                   = FAT_VOLUME_SIGNATURE;
+  Volume->Handle                      = Handle;
+  Volume->DiskIo                      = DiskIo;
+  Volume->BlockIo                     = BlockIo;
+  Volume->MediaId                     = BlockIo->Media->MediaId;
+  Volume->ReadOnly                    = BlockIo->Media->ReadOnly;
+  Volume->VolumeInterface.Revision    = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
+  Volume->VolumeInterface.OpenVolume  = FatOpenVolume;
+  InitializeListHead (&Volume->CheckRef);
+  InitializeListHead (&Volume->DirCacheList);
+  //
+  // Initialize Root Directory entry
+  //
+  Volume->RootDirEnt.FileString       = Volume->RootFileString;
+  Volume->RootDirEnt.Entry.Attributes = FAT_ATTRIBUTE_DIRECTORY;
+  //
+  // Check to see if there's a file system on the volume
+  //
+  Status = FatOpenDevice (Volume);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+  //
+  // Initialize cache
+  //
+  Status = FatInitializeDiskCache (Volume);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+  //
+  // Install our protocol interfaces on the device's handle
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Volume->Handle,
+                  &gEfiSimpleFileSystemProtocolGuid,
+                  &Volume->VolumeInterface,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+  //
+  // Volume installed
+  //
+  DEBUG ((EFI_D_INIT, "%HInstalled Fat filesystem on %x%N\n", Handle));
+  Volume->Valid = TRUE;
+
+Done:
+  //
+  // Unlock if locked by myself.
+  //
+  if (LockedByMe) {
+    FatReleaseLock ();
+  }
+
+  if (EFI_ERROR (Status)) {
+    FatFreeVolume (Volume);
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+FatAbandonVolume (
+  IN FAT_VOLUME *Volume
+  )
+/*++
+
+Routine Description:
+
+  Called by FatDriverBindingStop(), Abandon the volume.
+
+Arguments:
+
+  Volume                - The volume to be abandoned.
+
+Returns:
+
+  EFI_SUCCESS           - Abandoned the volume successfully.
+  Others                - Can not uninstall the protocol interfaces.
+
+--*/
+{
+  EFI_STATUS  Status;
+  BOOLEAN     LockedByMe;
+
+  //
+  // Uninstall the protocol interface.
+  //
+  if (Volume->Handle != NULL) {
+    Status = gBS->UninstallMultipleProtocolInterfaces (
+                    Volume->Handle,
+                    &gEfiSimpleFileSystemProtocolGuid,
+                    &Volume->VolumeInterface,
+                    NULL
+                    );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  LockedByMe = FALSE;
+
+  //
+  // Acquire the lock.
+  // If the caller has already acquired the lock (which
+  // means we are in the process of some Fat operation),
+  // we can not acquire again.
+  //
+  if (!FatIsLocked ()) {
+    LockedByMe = TRUE;
+    FatAcquireLock ();
+  }
+  //
+  // The volume is still being used. Hence, set error flag for all OFiles still in
+  // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is
+  // EFI_NO_MEDIA.
+  //
+  if (Volume->Root != NULL) {
+    FatSetVolumeError (
+      Volume->Root,
+      Volume->BlockIo->Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA
+      );
+  }
+
+  Volume->Valid = FALSE;
+
+  //
+  // Release the lock.
+  // If locked by me, this means DriverBindingStop is NOT
+  // called within an on-going Fat operation, so we should
+  // take responsibility to cleanup and free the volume.
+  // Otherwise, the DriverBindingStop is called within an on-going
+  // Fat operation, we shouldn't check reference, so just let outer
+  // FatCleanupVolume do the task.
+  //
+  if (LockedByMe) {
+    FatCleanupVolume (Volume, NULL, EFI_SUCCESS);
+    FatReleaseLock ();
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatOpenDevice (
+  IN OUT FAT_VOLUME           *Volume
+  )
+/*++
+
+Routine Description:
+
+  Detects FAT file system on Disk and set relevant fields of Volume
+
+Arguments:
+
+  Volume                - The volume structure.
+
+Returns:
+
+  EFI_SUCCESS           - The Fat File System is detected successfully
+  EFI_UNSUPPORTED       - The volume is not FAT file system.
+  EFI_VOLUME_CORRUPTED  - The volume is corrupted.
+
+--*/
+{
+  EFI_STATUS            Status;
+  UINT32                BlockSize;
+  UINT32                DirtyMask;
+  EFI_DISK_IO_PROTOCOL  *DiskIo;
+  FAT_BOOT_SECTOR       FatBs;
+  FAT_VOLUME_TYPE       FatType;
+  UINTN                 RootDirSectors;
+  UINTN                 FatLba;
+  UINTN                 RootLba;
+  UINTN                 FirstClusterLba;
+  UINTN                 Sectors;
+  UINTN                 SectorsPerFat;
+  UINT8                 SectorsPerClusterAlignment;
+  UINT8                 BlockAlignment;
+
+  //
+  // Read the FAT_BOOT_SECTOR BPB info
+  // This is the only part of FAT code that uses parent DiskIo,
+  // Others use FatDiskIo which utilizes a Cache.
+  //
+  DiskIo  = Volume->DiskIo;
+  Status  = DiskIo->ReadDisk (DiskIo, Volume->MediaId, 0, sizeof (FatBs), &FatBs);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INIT, "FatOpenDevice: read of part_lba failed %r\n", Status));
+    return Status;
+  }
+
+  FatType = FatUndefined;
+
+  //
+  // Use LargeSectors if Sectors is 0
+  //
+  Sectors = FatBs.FatBsb.Sectors;
+  if (Sectors == 0) {
+    Sectors = FatBs.FatBsb.LargeSectors;
+  }
+
+  SectorsPerFat = FatBs.FatBsb.SectorsPerFat;
+  if (SectorsPerFat == 0) {
+    SectorsPerFat = FatBs.FatBse.Fat32Bse.LargeSectorsPerFat;
+    FatType       = FAT32;
+  }
+  //
+  // Is boot sector a fat sector?
+  // (Note that so far we only know if the sector is FAT32 or not, we don't
+  // know if the sector is Fat16 or Fat12 until later when we can compute
+  // the volume size)
+  //
+  if (FatBs.FatBsb.ReservedSectors == 0 || FatBs.FatBsb.NumFats == 0 || Sectors == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if ((FatBs.FatBsb.SectorSize & (FatBs.FatBsb.SectorSize - 1)) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  BlockAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorSize);
+  if (BlockAlignment > MAX_BLOCK_ALIGNMENT || BlockAlignment < MIN_BLOCK_ALIGNMENT) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if ((FatBs.FatBsb.SectorsPerCluster & (FatBs.FatBsb.SectorsPerCluster - 1)) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  SectorsPerClusterAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorsPerCluster);
+  if (SectorsPerClusterAlignment > MAX_SECTORS_PER_CLUSTER_ALIGNMENT) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (FatBs.FatBsb.Media <= 0xf7 &&
+      FatBs.FatBsb.Media != 0xf0 &&
+      FatBs.FatBsb.Media != 0x00 &&
+      FatBs.FatBsb.Media != 0x01
+      ) {
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Initialize fields the volume information for this FatType
+  //
+  if (FatType != FAT32) {
+    if (FatBs.FatBsb.RootEntries == 0) {
+      return EFI_UNSUPPORTED;
+    }
+    //
+    // Unpack fat12, fat16 info
+    //
+    Volume->RootEntries = FatBs.FatBsb.RootEntries;
+  } else {
+    //
+    // If this is fat32, refuse to mount mirror-disabled volumes
+    //
+    if ((SectorsPerFat == 0 || FatBs.FatBse.Fat32Bse.FsVersion != 0) || (FatBs.FatBse.Fat32Bse.ExtendedFlags & 0x80)) {
+      return EFI_UNSUPPORTED;
+    }
+    //
+    // Unpack fat32 info
+    //
+    Volume->RootCluster = FatBs.FatBse.Fat32Bse.RootDirFirstCluster;
+  }
+
+  Volume->NumFats           = FatBs.FatBsb.NumFats;
+  //
+  // Compute some fat locations
+  //
+  BlockSize                 = FatBs.FatBsb.SectorSize;
+  RootDirSectors            = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (BlockSize - 1)) / BlockSize;
+
+  FatLba                    = FatBs.FatBsb.ReservedSectors;
+  RootLba                   = FatBs.FatBsb.NumFats * SectorsPerFat + FatLba;
+  FirstClusterLba           = RootLba + RootDirSectors;
+
+  Volume->FatPos            = FatLba * BlockSize;
+  Volume->FatSize           = SectorsPerFat * BlockSize;
+
+  Volume->VolumeSize        = LShiftU64 (Sectors, BlockAlignment);
+  Volume->RootPos           = LShiftU64 (RootLba, BlockAlignment);
+  Volume->FirstClusterPos   = LShiftU64 (FirstClusterLba, BlockAlignment);
+  Volume->MaxCluster        = (Sectors - FirstClusterLba) >> SectorsPerClusterAlignment;
+  Volume->ClusterAlignment  = (UINT8)(BlockAlignment + SectorsPerClusterAlignment);
+  Volume->ClusterSize       = (UINTN)1 << (Volume->ClusterAlignment);
+
+  //
+  // If this is not a fat32, determine if it's a fat16 or fat12
+  //
+  if (FatType != FAT32) {
+    if (Volume->MaxCluster >= FAT_MAX_FAT16_CLUSTER) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+
+    FatType = Volume->MaxCluster < FAT_MAX_FAT12_CLUSTER ? FAT12 : FAT16;
+    //
+    // fat12 & fat16 fat-entries are 2 bytes
+    //
+    Volume->FatEntrySize = sizeof (UINT16);
+    DirtyMask            = FAT16_DIRTY_MASK;
+  } else {
+    if (Volume->MaxCluster < FAT_MAX_FAT16_CLUSTER) {
+      return EFI_VOLUME_CORRUPTED;
+    }
+    //
+    // fat32 fat-entries are 4 bytes
+    //
+    Volume->FatEntrySize = sizeof (UINT32);
+    DirtyMask            = FAT32_DIRTY_MASK;
+  }
+  //
+  // Get the DirtyValue and NotDirtyValue
+  // We should keep the initial value as the NotDirtyValue
+  // in case the volume is dirty already
+  //
+  if (FatType != FAT12) {
+    Status = FatAccessVolumeDirty (Volume, READ_DISK, &Volume->NotDirtyValue);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Volume->DirtyValue = Volume->NotDirtyValue & DirtyMask;
+  }
+  //
+  // If present, read the fat hint info
+  //
+  if (FatType == FAT32) {
+    Volume->FreeInfoPos = FatBs.FatBse.Fat32Bse.FsInfoSector * BlockSize;
+    if (FatBs.FatBse.Fat32Bse.FsInfoSector != 0) {
+      FatDiskIo (Volume, READ_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector);
+      if (Volume->FatInfoSector.Signature == FAT_INFO_SIGNATURE &&
+          Volume->FatInfoSector.InfoBeginSignature == FAT_INFO_BEGIN_SIGNATURE &&
+          Volume->FatInfoSector.InfoEndSignature == FAT_INFO_END_SIGNATURE &&
+          Volume->FatInfoSector.FreeInfo.ClusterCount <= Volume->MaxCluster
+          ) {
+        Volume->FreeInfoValid = TRUE;
+      }
+    }
+  }
+  //
+  // Just make up a FreeInfo.NextCluster for use by allocate cluster
+  //
+  if (FAT_MIN_CLUSTER > Volume->FatInfoSector.FreeInfo.NextCluster ||
+     Volume->FatInfoSector.FreeInfo.NextCluster > Volume->MaxCluster + 1
+     ) {
+    Volume->FatInfoSector.FreeInfo.NextCluster = FAT_MIN_CLUSTER;
+  }
+  //
+  // We are now defining FAT Type
+  //
+  Volume->FatType = FatType;
+  ASSERT (FatType != FatUndefined);
+
+  return EFI_SUCCESS;
+}

+ 409 - 0
FatPkg/EnhancedFatDxe/Misc.c

@@ -0,0 +1,409 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  Misc.c
+
+Abstract:
+
+  Miscellaneous functions
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+FatAccessVolumeDirty (
+  IN FAT_VOLUME       *Volume,
+  IN IO_MODE          IoMode,
+  IN VOID             *DirtyValue
+  )
+/*++
+
+Routine Description:
+
+  Set the volume as dirty or not
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  IoMode                - The access mode.
+  DirtyValue            - Set the volume as dirty or not.
+
+Returns:
+
+  EFI_SUCCESS           - Set the new FAT entry value sucessfully.
+  other                 - An error occurred when operation the FAT entries.
+
+--*/
+{
+  UINTN WriteCount;
+
+  WriteCount = Volume->FatEntrySize;
+  return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue);
+}
+
+EFI_STATUS
+FatDiskIo (
+  IN     FAT_VOLUME       *Volume,
+  IN     IO_MODE          IoMode,
+  IN     UINT64           Offset,
+  IN     UINTN            BufferSize,
+  IN OUT VOID             *Buffer
+  )
+/*++
+
+Routine Description:
+
+  General disk access function
+
+Arguments:
+
+  Volume                - FAT file system volume.
+  IoMode                - The access mode (disk read/write or cache access).
+  Offset                - The starting byte offset to read from.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing read data.
+
+Returns:
+
+  EFI_SUCCESS           - The operation is performed successfully.
+  EFI_VOLUME_CORRUPTED  - The accesss is
+  Others                - The status of read/write the disk
+
+--*/
+{
+  EFI_STATUS            Status;
+  EFI_DISK_IO_PROTOCOL  *DiskIo;
+  EFI_DISK_READ         IoFunction;
+
+  //
+  // Verify the IO is in devices range
+  //
+  Status = EFI_VOLUME_CORRUPTED;
+  if (Offset + BufferSize <= Volume->VolumeSize) {
+    if (CACHE_ENABLED (IoMode)) {
+      //
+      // Access cache
+      //
+      Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer);
+    } else {
+      //
+      // Access disk directly
+      //
+      DiskIo      = Volume->DiskIo;
+      IoFunction  = (IoMode == READ_DISK) ? DiskIo->ReadDisk : DiskIo->WriteDisk;
+      Status      = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    Volume->DiskError = TRUE;
+    DEBUG ((EFI_D_INFO, "FatDiskIo: error %r\n", Status));
+  }
+
+  return Status;
+}
+
+VOID
+FatAcquireLock (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Lock the volume.
+
+Arguments:
+
+  None.
+
+Returns:
+
+  None.
+
+--*/
+{
+  EfiAcquireLock (&FatFsLock);
+}
+
+BOOLEAN
+FatIsLocked (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Get the locking status of the volume.
+
+Arguments:
+
+  None.
+
+Returns:
+
+  TRUE                  - The volume is locked.
+  FALSE                 - The volume is not locked.
+
+--*/
+{
+  return (BOOLEAN) (FatFsLock.Lock);
+}
+
+VOID
+FatReleaseLock (
+  VOID
+  )
+/*++
+
+Routine Description:
+
+  Unlock the volume.
+
+Arguments:
+
+  Null.
+
+Returns:
+
+  None.
+
+--*/
+{
+  EfiReleaseLock (&FatFsLock);
+}
+
+VOID
+FatFreeDirEnt (
+  IN FAT_DIRENT       *DirEnt
+  )
+/*++
+
+Routine Description:
+
+  Free directory entry.
+
+Arguments:
+
+  DirEnt                - The directory entry to be freed.
+
+Returns:
+
+  None.
+
+--*/
+{
+  if (DirEnt->FileString != NULL) {
+    FreePool (DirEnt->FileString);
+  }
+
+  FreePool (DirEnt);
+}
+
+VOID
+FatFreeVolume (
+  IN FAT_VOLUME       *Volume
+  )
+/*++
+
+Routine Description:
+
+  Free volume structure (including the contents of directory cache and disk cache).
+
+Arguments:
+
+  Volume                - The volume structure to be freed.
+
+Returns:
+
+  None.
+
+--*/
+{
+  //
+  // Free disk cache
+  //
+  if (Volume->CacheBuffer != NULL) {
+    FreePool (Volume->CacheBuffer);
+  }
+  //
+  // Free directory cache
+  //
+  FatCleanupODirCache (Volume);
+  FreePool (Volume);
+}
+
+VOID
+FatEfiTimeToFatTime (
+  IN  EFI_TIME        *ETime,
+  OUT FAT_DATE_TIME   *FTime
+  )
+/*++
+
+Routine Description:
+
+  Translate EFI time to FAT time.
+
+Arguments:
+
+  ETime                 - The time of EFI_TIME.
+  FTime                 - The time of FAT_DATE_TIME.
+
+Returns:
+
+  None.
+
+--*/
+{
+  //
+  // ignores timezone info in source ETime
+  //
+  if (ETime->Year > 1980) {
+    FTime->Date.Year = (UINT16) (ETime->Year - 1980);
+  }
+
+  if (ETime->Year >= 1980 + FAT_MAX_YEAR_FROM_1980) {
+    FTime->Date.Year = FAT_MAX_YEAR_FROM_1980;
+  }
+
+  FTime->Date.Month         = ETime->Month;
+  FTime->Date.Day           = ETime->Day;
+  FTime->Time.Hour          = ETime->Hour;
+  FTime->Time.Minute        = ETime->Minute;
+  FTime->Time.DoubleSecond  = (UINT16) (ETime->Second / 2);
+}
+
+VOID
+FatFatTimeToEfiTime (
+  IN  FAT_DATE_TIME     *FTime,
+  OUT EFI_TIME          *ETime
+  )
+/*++
+
+Routine Description:
+
+  Translate Fat time to EFI time.
+
+Arguments:
+
+  FTime                 - The time of FAT_DATE_TIME.
+  ETime                 - The time of EFI_TIME.
+
+Returns:
+
+  None.
+
+--*/
+{
+  ETime->Year       = (UINT16) (FTime->Date.Year + 1980);
+  ETime->Month      = (UINT8) FTime->Date.Month;
+  ETime->Day        = (UINT8) FTime->Date.Day;
+  ETime->Hour       = (UINT8) FTime->Time.Hour;
+  ETime->Minute     = (UINT8) FTime->Time.Minute;
+  ETime->Second     = (UINT8) (FTime->Time.DoubleSecond * 2);
+  ETime->Nanosecond = 0;
+  ETime->TimeZone   = EFI_UNSPECIFIED_TIMEZONE;
+  ETime->Daylight   = 0;
+}
+
+VOID
+FatGetCurrentFatTime (
+  OUT FAT_DATE_TIME   *FatNow
+  )
+/*++
+
+Routine Description:
+
+  Get Current FAT time.
+
+Arguments:
+
+  FatNow                - Current FAT time.
+
+Returns:
+
+  None.
+
+--*/
+{
+  EFI_TIME  Now;
+  gRT->GetTime (&Now, NULL);
+  FatEfiTimeToFatTime (&Now, FatNow);
+}
+
+BOOLEAN
+FatIsValidTime (
+  IN EFI_TIME         *Time
+  )
+/*++
+
+Routine Description:
+
+  Check whether a time is valid.
+
+Arguments:
+
+  Time                  - The time of EFI_TIME.
+
+Returns:
+
+  TRUE                  - The time is valid.
+  FALSE                 - The time is not valid.
+
+--*/
+{
+  static UINT8  MonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+  UINTN         Day;
+  BOOLEAN       ValidTime;
+
+  ValidTime = TRUE;
+
+  //
+  // Check the fields for range problems
+  // Fat can only support from 1980
+  //
+  if (Time->Year < 1980 ||
+      Time->Month < 1 ||
+      Time->Month > 12 ||
+      Time->Day < 1 ||
+      Time->Day > 31 ||
+      Time->Hour > 23 ||
+      Time->Minute > 59 ||
+      Time->Second > 59 ||
+      Time->Nanosecond > 999999999
+      ) {
+
+    ValidTime = FALSE;
+
+  } else {
+    //
+    // Perform a more specific check of the day of the month
+    //
+    Day = MonthDays[Time->Month - 1];
+    if (Time->Month == 2 && IS_LEAP_YEAR (Time->Year)) {
+      Day += 1;
+      //
+      // 1 extra day this month
+      //
+    }
+    if (Time->Day > Day) {
+      ValidTime = FALSE;
+    }
+  }
+
+  return ValidTime;
+}

+ 285 - 0
FatPkg/EnhancedFatDxe/Open.c

@@ -0,0 +1,285 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  open.c
+
+Abstract:
+
+  Routines dealing with file open
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+FatAllocateIFile (
+  IN FAT_OFILE    *OFile,
+  OUT FAT_IFILE   **PtrIFile
+  )
+/*++
+
+Routine Description:
+
+  Create an Open instance for the existing OFile.
+  The IFile of the newly opened file is passed out.
+
+Arguments:
+
+  OFile                 - The file that serves as a starting reference point.
+  PtrIFile              - The newly generated IFile instance.
+
+Returns:
+
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory for the IFile
+  EFI_SUCCESS           - Create the new IFile for the OFile successfully
+
+--*/
+{
+  FAT_IFILE *IFile;
+
+  ASSERT_VOLUME_LOCKED (OFile->Volume);
+
+  //
+  // Allocate a new open instance
+  //
+  IFile = AllocateZeroPool (sizeof (FAT_IFILE));
+  if (IFile == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  IFile->Signature = FAT_IFILE_SIGNATURE;
+
+  CopyMem (&(IFile->Handle), &FatFileInterface, sizeof (EFI_FILE));
+
+  IFile->OFile = OFile;
+  InsertTailList (&OFile->Opens, &IFile->Link);
+
+  *PtrIFile = IFile;
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatOFileOpen (
+  IN  FAT_OFILE            *OFile,
+  OUT FAT_IFILE            **NewIFile,
+  IN  CHAR16               *FileName,
+  IN  UINT64               OpenMode,
+  IN  UINT8                Attributes
+  )
+/*++
+
+Routine Description:
+
+  Open a file for a file name relative to an existing OFile.
+  The IFile of the newly opened file is passed out.
+
+Arguments:
+
+  OFile                 - The file that serves as a starting reference point.
+  NewIFile              - The newly generated IFile instance.
+  FileName              - The file name relative to the OFile.
+  OpenMode              - Open mode.
+  Attributes            - Attributes to set if the file is created.
+
+Returns:
+
+  EFI_SUCCESS           - Open the file successfully.
+  EFI_INVALID_PARAMETER - The open mode is conflict with the attributes
+                          or the file name is not valid.
+  EFI_NOT_FOUND         - Conficts between dir intention and attribute.
+  EFI_WRITE_PROTECTED   - Can't open for write if the volume is read only.
+  EFI_ACCESS_DENIED     - If the file's attribute is read only, and the
+                          open is for read-write fail it.
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory.
+
+--*/
+{
+  FAT_VOLUME  *Volume;
+  EFI_STATUS  Status;
+  CHAR16      NewFileName[EFI_PATH_STRING_LENGTH];
+  FAT_DIRENT  *DirEnt;
+  UINT8       FileAttributes;
+  BOOLEAN     WriteMode;
+
+  Volume = OFile->Volume;
+  ASSERT_VOLUME_LOCKED (Volume);
+  WriteMode = (BOOLEAN) (OpenMode & EFI_FILE_MODE_WRITE);
+  if (Volume->ReadOnly && WriteMode) {
+    return EFI_WRITE_PROTECTED;
+  }
+  //
+  // Verify the source file handle isn't in an error state
+  //
+  Status = OFile->Error;
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Get new OFile for the file
+  //
+  Status = FatLocateOFile (&OFile, FileName, Attributes, NewFileName);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (*NewFileName != 0) {
+    //
+    // If there's a remaining part of the name, then we had
+    // better be creating the file in the directory
+    //
+    if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) {
+      return EFI_NOT_FOUND;
+    }
+
+    Status = FatCreateDirEnt (OFile, NewFileName, Attributes, &DirEnt);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Status = FatOpenDirEnt (OFile, DirEnt);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    OFile = DirEnt->OFile;
+    if (OFile->ODir != NULL) {
+      //
+      // If we just created a directory, we need to create "." and ".."
+      //
+      Status = FatCreateDotDirEnts (OFile);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    }
+  }
+  //
+  // If the file's attribute is read only, and the open is for
+  // read-write, then the access is denied.
+  //
+  FileAttributes = OFile->DirEnt->Entry.Attributes;
+  if ((FileAttributes & EFI_FILE_READ_ONLY) != 0 && (FileAttributes & FAT_ATTRIBUTE_DIRECTORY) == 0 && WriteMode) {
+    return EFI_ACCESS_DENIED;
+  }
+  //
+  // Create an open instance of the OFile
+  //
+  Status = FatAllocateIFile (OFile, NewIFile);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  (*NewIFile)->ReadOnly = (BOOLEAN)!WriteMode;
+
+  DEBUG ((EFI_D_INFO, "FSOpen: Open '%S' %r\n", FileName, Status));
+  return FatOFileFlush (OFile);
+}
+
+EFI_STATUS
+EFIAPI
+FatOpen (
+  IN  EFI_FILE   *FHand,
+  OUT EFI_FILE   **NewHandle,
+  IN  CHAR16     *FileName,
+  IN  UINT64     OpenMode,
+  IN  UINT64     Attributes
+  )
+/*++
+Routine Description:
+
+  Implements Open() of Simple File System Protocol.
+
+Arguments:
+
+  FHand                 - File handle of the file serves as a starting reference point.
+  NewHandle             - Handle of the file that is newly opened.
+  FileName              - File name relative to FHand.
+  OpenMode              - Open mode.
+  Attributes            - Attributes to set if the file is created.
+
+Returns:
+
+  EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.
+                          The OpenMode is not supported.
+                          The Attributes is not the valid attributes.
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory for file string.
+  EFI_SUCCESS           - Open the file successfully.
+  Others                - The status of open file.
+
+--*/
+{
+  FAT_IFILE   *IFile;
+  FAT_IFILE   *NewIFile;
+  FAT_OFILE   *OFile;
+  EFI_STATUS  Status;
+
+  //
+  // Perform some parameter checking
+  //
+  if (FileName == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Check for a valid mode
+  //
+  switch (OpenMode) {
+  case EFI_FILE_MODE_READ:
+  case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
+  case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
+    break;
+
+  default:
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Check for valid attributes
+  //
+  if (Attributes & (~EFI_FILE_VALID_ATTR)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Can't open for create and apply the read only attribute
+  //
+  if ((OpenMode & EFI_FILE_MODE_CREATE) && (Attributes & EFI_FILE_READ_ONLY)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  IFile = IFILE_FROM_FHAND (FHand);
+  OFile = IFile->OFile;
+
+  //
+  // Lock
+  //
+  FatAcquireLock ();
+
+  //
+  // Open the file
+  //
+  Status = FatOFileOpen (OFile, &NewIFile, FileName, OpenMode, (UINT8) Attributes);
+
+  //
+  // If the file was opened, return the handle to the caller
+  //
+  if (!EFI_ERROR (Status)) {
+    *NewHandle = &NewIFile->Handle;
+  }
+  //
+  // Unlock
+  //
+  Status = FatCleanupVolume (OFile->Volume, NULL, Status);
+  FatReleaseLock ();
+
+  return Status;
+}

+ 80 - 0
FatPkg/EnhancedFatDxe/OpenVolume.c

@@ -0,0 +1,80 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  OpenVolume.c
+
+Abstract:
+
+  OpenVolume() function of Simple File System Protocol
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatOpenVolume (
+  IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,
+  OUT EFI_FILE                         **File
+  )
+/*++
+
+Routine Description:
+
+  Implements Simple File System Protocol interface function OpenVolume().
+
+Arguments:
+
+  This                  - Calling context.
+  File                  - the Root Directory of the volume.
+
+Returns:
+
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory.
+  EFI_VOLUME_CORRUPTED  - The FAT type is error.
+  EFI_SUCCESS           - Open the volume successfully.
+
+--*/
+{
+  EFI_STATUS  Status;
+  FAT_VOLUME  *Volume;
+  FAT_IFILE   *IFile;
+
+  Volume = VOLUME_FROM_VOL_INTERFACE (This);
+  FatAcquireLock ();
+
+  //
+  // Open Root file
+  //
+  Status = FatOpenDirEnt (NULL, &Volume->RootDirEnt);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+  //
+  // Open a new instance to the root
+  //
+  Status = FatAllocateIFile (Volume->Root, &IFile);
+  if (!EFI_ERROR (Status)) {
+    *File = &IFile->Handle;
+  }
+
+Done:
+
+  Status = FatCleanupVolume (Volume, Volume->Root, Status);
+  FatReleaseLock ();
+
+  return Status;
+}

+ 612 - 0
FatPkg/EnhancedFatDxe/ReadWrite.c

@@ -0,0 +1,612 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. 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.
+
+
+Module Name:
+
+  ReadWrite.c
+
+Abstract:
+
+  Functions that perform file read/write
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatGetPosition (
+  IN  EFI_FILE          *FHand,
+  OUT UINT64            *Position
+  )
+/*++
+
+Routine Description:
+
+  Get the file's position of the file.
+
+Arguments:
+
+  FHand                 - The handle of file.
+  Position              - The file's position of the file.
+
+Returns:
+
+  EFI_SUCCESS           - Get the info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+  EFI_UNSUPPORTED       - The open file is not a file.
+
+--*/
+{
+  FAT_IFILE *IFile;
+  FAT_OFILE *OFile;
+
+  IFile = IFILE_FROM_FHAND (FHand);
+  OFile = IFile->OFile;
+
+  if (OFile->Error == EFI_NOT_FOUND) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (OFile->ODir != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  *Position = IFile->Position;
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FatSetPosition (
+  IN EFI_FILE  *FHand,
+  IN UINT64    Position
+  )
+/*++
+
+Routine Description:
+
+  Set the file's position of the file.
+
+Arguments:
+
+  FHand                 - The handle of file.
+  Position              - The file's position of the file.
+
+Returns:
+
+  EFI_SUCCESS           - Set the info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+  EFI_UNSUPPORTED       - Set a directory with a not-zero position.
+
+--*/
+{
+  FAT_IFILE *IFile;
+  FAT_OFILE *OFile;
+
+  IFile = IFILE_FROM_FHAND (FHand);
+  OFile = IFile->OFile;
+
+  if (OFile->Error == EFI_NOT_FOUND) {
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // If this is a directory, we can only set back to position 0
+  //
+  if (OFile->ODir != NULL) {
+    if (Position != 0) {
+      //
+      // Reset current directory cursor;
+      //
+      return EFI_UNSUPPORTED;
+    }
+
+    FatResetODirCursor (OFile);
+  }
+  //
+  // Set the position
+  //
+  if (Position == -1) {
+    Position = OFile->FileSize;
+  }
+  //
+  // Set the position
+  //
+  IFile->Position = Position;
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatIFileReadDir (
+  IN     FAT_IFILE              *IFile,
+  IN OUT UINTN                  *BufferSize,
+     OUT VOID                   *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the file info from the open file of the IFile into Buffer.
+
+Arguments:
+
+  IFile                 - The instance of the open file.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing read data.
+
+Returns:
+
+  EFI_SUCCESS           - Get the file info successfully.
+  other                 - An error occurred when operation the disk.
+
+--*/
+{
+  EFI_STATUS  Status;
+  FAT_OFILE   *OFile;
+  FAT_ODIR    *ODir;
+  FAT_DIRENT  *DirEnt;
+  UINT32      CurrentPos;
+
+  OFile       = IFile->OFile;
+  ODir        = OFile->ODir;
+  CurrentPos  = ((UINT32) IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY);
+
+  //
+  // We need to relocate the directory
+  //
+  if (CurrentPos < ODir->CurrentPos) {
+    //
+    // The directory cursor has been modified by another IFile, we reset the cursor
+    //
+    FatResetODirCursor (OFile);
+  }
+  //
+  // We seek the next directory entry's position
+  //
+  do {
+    Status = FatGetNextDirEnt (OFile, &DirEnt);
+    if (EFI_ERROR (Status) || DirEnt == NULL) {
+      //
+      // Something error occurred or reach the end of directory,
+      // return 0 buffersize
+      //
+      *BufferSize = 0;
+      goto Done;
+    }
+  } while (ODir->CurrentPos <= CurrentPos);
+  Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer);
+
+Done:
+  //
+  // Update IFile's Position
+  //
+  if (!EFI_ERROR (Status)) {
+    //
+    // Update IFile->Position, if everything is all right
+    //
+    CurrentPos      = ODir->CurrentPos;
+    IFile->Position = (UINT64) (CurrentPos * sizeof (FAT_DIRECTORY_ENTRY));
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+FatIFileAccess (
+  IN     EFI_FILE              *FHand,
+  IN     IO_MODE               IoMode,
+  IN OUT UINTN                 *BufferSize,
+  IN OUT VOID                  *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the file info from the open file of the IFile into Buffer.
+
+Arguments:
+
+  FHand                 - The file handle to access.
+  IoMode                - Indicate whether the access mode is reading or writing.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing read data.
+
+Returns:
+
+  EFI_SUCCESS           - Get the file info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+  EFI_VOLUME_CORRUPTED  - The file type of open file is error.
+  EFI_WRITE_PROTECTED   - The disk is write protect.
+  EFI_ACCESS_DENIED     - The file is read-only.
+  other                 - An error occurred when operating on the disk.
+
+--*/
+{
+  EFI_STATUS  Status;
+  FAT_IFILE   *IFile;
+  FAT_OFILE   *OFile;
+  FAT_VOLUME  *Volume;
+  UINT64      EndPosition;
+
+  IFile  = IFILE_FROM_FHAND (FHand);
+  OFile  = IFile->OFile;
+  Volume = OFile->Volume;
+
+  if (OFile->Error == EFI_NOT_FOUND) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (IoMode == READ_DATA) {
+    //
+    // If position is at EOF, then return device error
+    //
+    if (IFile->Position > OFile->FileSize) {
+      return EFI_DEVICE_ERROR;
+    }
+  } else {
+    //
+    // Check if the we can write data
+    //
+    if (Volume->ReadOnly) {
+      return EFI_WRITE_PROTECTED;
+    }
+
+    if (IFile->ReadOnly) {
+      return EFI_ACCESS_DENIED;
+    }
+  }
+
+  FatAcquireLock ();
+
+  Status = OFile->Error;
+  if (!EFI_ERROR (Status)) {
+    if (OFile->ODir != NULL) {
+      //
+      // Access a directory
+      //
+      Status = EFI_UNSUPPORTED;
+      if (IoMode == READ_DATA) {
+        //
+        // Read a directory is supported
+        //
+        Status = FatIFileReadDir (IFile, BufferSize, Buffer);
+      }
+
+      OFile = NULL;
+    } else {
+      //
+      // Access a file
+      //
+      EndPosition = IFile->Position + *BufferSize;
+      if (EndPosition > OFile->FileSize) {
+        //
+        // The position goes beyond the end of file
+        //
+        if (IoMode == READ_DATA) {
+          //
+          // Adjust the actual size read
+          //
+          *BufferSize -= (UINTN) EndPosition - OFile->FileSize;
+        } else {
+          //
+          // We expand the file size of OFile
+          //
+          Status = FatGrowEof (OFile, EndPosition);
+          if (EFI_ERROR (Status)) {
+            //
+            // Must update the file's info into the file's Directory Entry
+            // and then flush the dirty cache info into disk.
+            //
+            *BufferSize = 0;
+            FatOFileFlush (OFile);
+            OFile = NULL;
+            goto Done;
+          }
+
+          FatUpdateDirEntClusterSizeInfo (OFile);
+        }
+      }
+
+      Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer);
+      IFile->Position += *BufferSize;
+    }
+  }
+
+Done:
+  if (EFI_ERROR (Status)) {
+    Status = FatCleanupVolume (Volume, OFile, Status);
+  }
+  //
+  // On EFI_SUCCESS case, not calling FatCleanupVolume():
+  // 1) The Cache flush operation is avoided to enhance
+  // performance. Caller is responsible to call Flush() when necessary.
+  // 2) The volume dirty bit is probably set already, and is expected to be
+  // cleaned in subsequent Flush() or other operations.
+  // 3) Write operation doesn't affect OFile/IFile structure, so
+  // Reference checking is not necessary.
+  //
+  FatReleaseLock ();
+  return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatRead (
+  IN     EFI_FILE       *FHand,
+  IN OUT UINTN          *BufferSize,
+     OUT VOID           *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Get the file info.
+
+Arguments:
+
+  FHand                 - The handle of the file.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing read data.
+
+Returns:
+
+  EFI_SUCCESS           - Get the file info successfully.
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.
+  EFI_VOLUME_CORRUPTED  - The file type of open file is error.
+  other                 - An error occurred when operation the disk.
+
+--*/
+{
+  return FatIFileAccess (FHand, READ_DATA, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+FatWrite (
+  IN     EFI_FILE       *FHand,
+  IN OUT UINTN          *BufferSize,
+  IN     VOID           *Buffer
+  )
+/*++
+
+Routine Description:
+
+  Write the content of buffer into files.
+
+Arguments:
+
+  FHand                 - The handle of the file.
+  BufferSize            - Size of Buffer.
+  Buffer                - Buffer containing write data.
+
+Returns:
+
+  EFI_SUCCESS           - Set the file info successfully.
+  EFI_WRITE_PROTECTED   - The disk is write protect.
+  EFI_ACCESS_DENIED     - The file is read-only.
+  EFI_DEVICE_ERROR      - The OFile is not valid.
+  EFI_UNSUPPORTED       - The open file is not a file.
+                        - The writing file size is larger than 4GB.
+  other                 - An error occurred when operation the disk.
+
+--*/
+{
+  return FatIFileAccess (FHand, WRITE_DATA, BufferSize, Buffer);
+}
+
+EFI_STATUS
+FatAccessOFile (
+  IN     FAT_OFILE      *OFile,
+  IN     IO_MODE        IoMode,
+  IN     UINTN          Position,
+  IN OUT UINTN          *DataBufferSize,
+  IN OUT UINT8          *UserBuffer
+  )
+/*++
+
+Routine Description:
+
+  This function reads data from a file or writes data to a file.
+  It uses OFile->PosRem to determine how much data can be accessed in one time.
+
+Arguments:
+
+  OFile                 - The open file.
+  IoMode                - Indicate whether the access mode is reading or writing.
+  Position              - The position where data will be accessed.
+  DataBufferSize        - Size of Buffer.
+  UserBuffer            - Buffer containing data.
+
+Returns:
+
+  EFI_SUCCESS           - Access the data successfully.
+  other                 - An error occurred when operating on the disk.
+
+--*/
+{
+  FAT_VOLUME  *Volume;
+  UINTN       Len;
+  EFI_STATUS  Status;
+  UINTN       BufferSize;
+
+  BufferSize  = *DataBufferSize;
+  Volume      = OFile->Volume;
+  ASSERT_VOLUME_LOCKED (Volume);
+
+  Status = EFI_SUCCESS;
+  while (BufferSize > 0) {
+    //
+    // Seek the OFile to the file position
+    //
+    Status = FatOFilePosition (OFile, Position, BufferSize);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+    //
+    // Clip length to block run
+    //
+    Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize;
+
+    //
+    // Write the data
+    //
+    Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+    //
+    // Data was successfully accessed
+    //
+    Position   += Len;
+    UserBuffer += Len;
+    BufferSize -= Len;
+    if (IoMode == WRITE_DATA) {
+      OFile->Dirty    = TRUE;
+      OFile->Archive  = TRUE;
+    }
+    //
+    // Make sure no outbound occurred
+    //
+    ASSERT (Position <= OFile->FileSize);
+  }
+  //
+  // Update the number of bytes accessed
+  //
+  *DataBufferSize -= BufferSize;
+  return Status;
+}
+
+EFI_STATUS
+FatExpandOFile (
+  IN FAT_OFILE          *OFile,
+  IN UINT64             ExpandedSize
+  )
+/*++
+
+Routine Description:
+
+  Expand OFile by appending zero bytes at the end of OFile.
+
+Arguments:
+
+  OFile                 - The open file.
+  ExpandedSize          - The number of zero bytes appended at the end of the file.
+
+Returns:
+
+  EFI_SUCCESS           - The file is expanded successfully.
+  other                 - An error occurred when expanding file.
+
+--*/
+{
+  EFI_STATUS  Status;
+  UINTN       WritePos;
+
+  WritePos  = OFile->FileSize;
+  Status    = FatGrowEof (OFile, ExpandedSize);
+  if (!EFI_ERROR (Status)) {
+    Status = FatWriteZeroPool (OFile, WritePos);
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+FatWriteZeroPool (
+  IN FAT_OFILE  *OFile,
+  IN UINTN      WritePos
+  )
+/*++
+
+Routine Description:
+
+  Write zero pool from the WritePos to the end of OFile.
+
+Arguments:
+
+  OFile                 - The open file to write zero pool.
+  WritePos              - The number of zero bytes written.
+
+Returns:
+
+  EFI_SUCCESS           - Write the zero pool successfully.
+  EFI_OUT_OF_RESOURCES  - Not enough memory to perform the operation.
+  other                 - An error occurred when writing disk.
+
+--*/
+{
+  EFI_STATUS  Status;
+  VOID        *ZeroBuffer;
+  UINTN       AppendedSize;
+  UINTN       BufferSize;
+  UINTN       WriteSize;
+
+  AppendedSize  = OFile->FileSize - WritePos;
+  BufferSize    = AppendedSize;
+  if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) {
+    //
+    // If the appended size is larger, maybe we can not allocate the whole
+    // memory once. So if the growed size is larger than 10M, we just
+    // allocate 10M memory (one healthy system should have 10M available
+    // memory), and then write the zerobuffer to the file several times.
+    //
+    BufferSize = FAT_MAX_ALLOCATE_SIZE;
+  }
+
+  ZeroBuffer = AllocateZeroPool (BufferSize);
+  if (ZeroBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  do {
+    WriteSize     = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize;
+    AppendedSize -= WriteSize;
+    Status = FatAccessOFile (OFile, WRITE_DATA, WritePos, &WriteSize, ZeroBuffer);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    WritePos += WriteSize;
+  } while (AppendedSize > 0);
+
+  FreePool (ZeroBuffer);
+  return Status;
+}
+
+EFI_STATUS
+FatTruncateOFile (
+  IN FAT_OFILE          *OFile,
+  IN UINTN              TruncatedSize
+  )
+/*++
+
+Routine Description:
+
+  Truncate the OFile to smaller file size.
+
+Arguments:
+
+  OFile                 - The open file.
+  TruncatedSize         - The new file size.
+
+Returns:
+
+  EFI_SUCCESS           - The file is truncated successfully.
+  other                 - An error occurred when truncating file.
+
+--*/
+{
+  OFile->FileSize = TruncatedSize;
+  return FatShrinkEof (OFile);
+}

+ 324 - 0
FatPkg/EnhancedFatDxe/UnicodeCollation.c

@@ -0,0 +1,324 @@
+/** @file
+  Unicode Collation Library that hides the trival difference of Unicode Collation
+  and Unicode collation 2 Protocol.
+
+  Copyright (c) 2007, Intel Corporation<BR>
+  All rights reserved. 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 <Uefi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Protocol/UnicodeCollation.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+STATIC EFI_UNICODE_COLLATION_PROTOCOL  *mUnicodeCollationInterface = NULL;
+
+typedef
+BOOLEAN
+(* SEARCH_LANG_CODE) (
+  IN CONST CHAR8    *Languages,
+  IN CONST CHAR8    *MatchLangCode
+  );
+
+struct _UNICODE_INTERFACE {
+  CHAR16            *VariableName;
+  CHAR8             *DefaultLangCode;
+  SEARCH_LANG_CODE  SearchLangCode;
+  EFI_GUID          *UnicodeProtocolGuid;
+};
+
+typedef struct _UNICODE_INTERFACE UNICODE_INTERFACE;
+
+STATIC
+BOOLEAN
+SearchIso639LangCode (
+  IN CONST CHAR8    *Languages,
+  IN CONST CHAR8    *MatchLangCode
+  )
+{
+  CONST CHAR8       *LangCode;
+
+  for (LangCode = Languages; *LangCode != '\0'; LangCode += 3) {
+    if (CompareMem (LangCode, MatchLangCode, 3) == 0) {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+STATIC
+BOOLEAN
+SearchRfc3066LangCode (
+  IN CONST CHAR8    *Languages,
+  IN CONST CHAR8    *MatchLangCode
+  )
+{
+  CHAR8       *SubStr;
+  CHAR8       Terminal;
+
+  SubStr = AsciiStrStr (Languages, MatchLangCode);
+  if (SubStr == NULL) {
+    return FALSE;
+  }
+
+  if (SubStr != Languages && *(SubStr - 1) != ';') {
+    return FALSE;
+  }
+
+  Terminal = *(SubStr + AsciiStrLen (MatchLangCode));
+  if (Terminal != '\0' && Terminal != ';') {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED UNICODE_INTERFACE mIso639Lang = {
+  L"Lang",
+  (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultLang),
+  SearchIso639LangCode,
+  &gEfiUnicodeCollationProtocolGuid,
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UNICODE_INTERFACE mRfc3066Lang = {
+  L"PlatformLang",
+  (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang),
+  SearchRfc3066LangCode,
+  &gEfiUnicodeCollation2ProtocolGuid,
+};
+
+STATIC
+EFI_STATUS
+InitializeUnicodeCollationSupportWithConfig (
+  IN EFI_HANDLE         AgentHandle,
+  IN UNICODE_INTERFACE  *UnicodeInterface
+  )
+{
+  EFI_STATUS                      Status;
+  CHAR8                           Buffer[100];
+  UINTN                           BufferSize;
+  UINTN                           Index;
+  CHAR8                           *LangCode;
+  UINTN                           NoHandles;
+  EFI_HANDLE                      *Handles;
+  EFI_UNICODE_COLLATION_PROTOCOL  *Uci;
+
+  LangCode   = Buffer;
+  BufferSize = sizeof (Buffer);
+  Status = gRT->GetVariable (
+                  UnicodeInterface->VariableName,
+                  &gEfiGlobalVariableGuid,
+                  NULL,
+                  &BufferSize,
+                  Buffer
+                  );
+  if (EFI_ERROR (Status)) {
+    LangCode = UnicodeInterface->DefaultLangCode;
+  }
+
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  UnicodeInterface->UnicodeProtocolGuid,
+                  NULL,
+                  &NoHandles,
+                  &Handles
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  for (Index = 0; Index < NoHandles; Index++) {
+    //
+    // Open Unicode Collation Protocol
+    //
+    Status = gBS->OpenProtocol (
+                    Handles[Index],
+                    UnicodeInterface->UnicodeProtocolGuid,
+                    (VOID **) &Uci,
+                    AgentHandle,
+                    NULL,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+
+    if (UnicodeInterface->SearchLangCode (Uci->SupportedLanguages, LangCode)) {
+      mUnicodeCollationInterface = Uci;
+      break;
+    }
+  }
+
+  FreePool (Handles);
+
+  return (mUnicodeCollationInterface != NULL)? EFI_SUCCESS : EFI_NOT_FOUND;
+}
+
+/**
+  Initialize Unicode Collation support.
+
+  @param  AgentHandle          The handle used to open Unicode Collation (2) protocol.
+
+  @retval EFI_SUCCESS          The Unicode Collation (2) protocol has been successfully located.
+  @retval Others               The Unicode Collation (2) protocol has not been located.
+
+**/
+EFI_STATUS
+InitializeUnicodeCollationSupport (
+  IN EFI_HANDLE    AgentHandle
+  )
+{
+
+  EFI_STATUS       Status;
+
+  Status = EFI_UNSUPPORTED;
+  if (FeaturePcdGet (PcdUnicodeCollation2Support)) {
+    Status = InitializeUnicodeCollationSupportWithConfig (AgentHandle, &mRfc3066Lang);
+  }
+
+  if (FeaturePcdGet (PcdUnicodeCollationSupport) && EFI_ERROR (Status)) {
+    Status = InitializeUnicodeCollationSupportWithConfig (AgentHandle, &mIso639Lang);
+  }
+
+  return Status;
+}
+
+/**
+  Performs a case-insensitive comparison of two Null-terminated Unicode strings.
+
+  @param  S1                   A pointer to a Null-terminated Unicode string.
+  @param  S2                   A pointer to a Null-terminated Unicode string.
+
+  @retval 0                    S1 is equivalent to S2.
+  @retval >0                   S1 is lexically greater than S2.
+  @retval <0                   S1 is lexically less than S2.
+**/
+INTN
+FatStriCmp (
+  IN CHAR16       *S1,
+  IN CHAR16       *S2
+  )
+{
+  ASSERT (StrSize (S1) != 0);
+  ASSERT (StrSize (S2) != 0);
+  ASSERT (mUnicodeCollationInterface != NULL);
+
+  return mUnicodeCollationInterface->StriColl (
+                                       mUnicodeCollationInterface,
+                                       S1,
+                                       S2
+                                       );
+}
+
+
+/**
+  Uppercase a string.
+
+  @param  Str                   The string which will be upper-cased.
+
+  @return None.
+
+**/
+VOID
+FatStrUpr (
+  IN OUT CHAR16   *String
+  )
+{
+  ASSERT (StrSize (String) != 0);
+  ASSERT (mUnicodeCollationInterface != NULL);
+
+  mUnicodeCollationInterface->StrUpr (mUnicodeCollationInterface, String);
+}
+
+
+/**
+  Lowercase a string
+
+  @param  Str                   The string which will be lower-cased.
+
+  @return None
+
+**/
+VOID
+FatStrLwr (
+  IN OUT CHAR16   *String
+  )
+{
+  ASSERT (StrSize (String) != 0);
+  ASSERT (mUnicodeCollationInterface != NULL);
+
+  mUnicodeCollationInterface->StrLwr (mUnicodeCollationInterface, String);
+}
+
+
+/**
+  Convert FAT string to unicode string.
+
+  @param  FatSize               The size of FAT string.
+  @param  Fat                   The FAT string.
+  @param  String                The unicode string.
+
+  @return None.
+
+**/
+VOID
+FatFatToStr (
+  IN  UINTN                            FatSize,
+  IN  CHAR8                            *Fat,
+  OUT CHAR16                           *String
+  )
+{
+  ASSERT (Fat != NULL);
+  ASSERT (String != NULL);
+  ASSERT (((UINTN) String & 0x01) != 0);
+  ASSERT (mUnicodeCollationInterface != NULL);
+
+  mUnicodeCollationInterface->FatToStr (mUnicodeCollationInterface, FatSize, Fat, String);
+}
+
+
+/**
+  Convert unicode string to Fat string.
+
+  @param  String                The unicode string.
+  @param  FatSize               The size of the FAT string.
+  @param  Fat                   The FAT string.
+
+  @retval TRUE                  Convert successfully.
+  @retval FALSE                 Convert error.
+
+**/
+BOOLEAN
+FatStrToFat (
+  IN  CHAR16                          *String,
+  IN  UINTN                           FatSize,
+  OUT CHAR8                           *Fat
+  )
+{
+  ASSERT (Fat != NULL);
+  ASSERT (StrSize (String) != 0);
+  ASSERT (mUnicodeCollationInterface != NULL);
+
+  return mUnicodeCollationInterface->StrToFat (
+                                       mUnicodeCollationInterface,
+                                       String,
+                                       FatSize,
+                                       Fat
+                                       );
+}

+ 29 - 0
FatPkg/FatPkg.dec

@@ -0,0 +1,29 @@
+#/** @file
+#
+#  FAT Package
+#
+# FAT 32 Driver
+#  Copyright (c) 2007,  Intel Corporation.
+#
+#  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.
+#
+#**/
+
+[Defines]
+  DEC_VERSION                    = 0x00010005
+  PACKAGE_NAME                   = FatPkg
+  PACKAGE_GUID                   = 8EA68A2C-99CB-4332-85C6-DD5864EAA674
+
+[PcdsFeatureFlag.common]
+  gEfiFatPkgTokenSpaceGuid.PcdUnicodeCollationSupport|TRUE|BOOLEAN|0x00010001
+  gEfiFatPkgTokenSpaceGuid.PcdUnicodeCollation2Support|TRUE|BOOLEAN|0x00010002
+
+[Guids.common]
+  gEfiFatPkgTokenSpaceGuid = {0xc8e92dba, 0x1d92, 0x411f, {0xae, 0xa, 0x1d, 0xbe, 0xd8, 0xf1, 0x32, 0x99}};
+

+ 49 - 0
FatPkg/FatPkg.dsc

@@ -0,0 +1,49 @@
+#/** @file
+#
+#  Build Binary Enhanced Fat Driver Modules
+#
+#  This Platform file is used to generate the Binary Fat Drivers
+#  for EDK II Prime release.
+#  Copyright (c) 2007, Intel Corporation
+#
+#  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.
+#
+#**/
+
+[Defines]
+  PLATFORM_NAME                  = Fat
+  PLATFORM_GUID                  = 25b55dbc-9d0b-4a32-80da-46e1273d622c
+  PLATFORM_VERSION               = 0.1
+  DSC_SPECIFICATION              = 0x00010005
+  SUPPORTED_ARCHITECTURES        = IA32|X64|IPF|EBC
+  OUTPUT_DIRECTORY               = Build/Fat
+  BUILD_TARGETS                  = DEBUG|RELEASE
+  SKUID_IDENTIFIER               = DEFAULT
+
+[LibraryClasses.common]
+  #
+  # Entry Point Libraries
+  #
+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+  #
+  # Common Libraries
+  #
+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+  PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+  TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+  MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf
+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+
+[Components.common]
+  FatPkg\EnhancedFatDxe\Fat.inf

+ 11 - 0
FatPkg/License.txt

@@ -0,0 +1,11 @@
+Copyright (c) 2006, Intel Corporation
+All rights reserved.
+
+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.
+

+ 7 - 0
FatPkg/ReadMe.txt

@@ -0,0 +1,7 @@
+EDK II Prime FAT Package
+
+Build Validation:
+MYTOOLS(VS2005) IA32 X64 IPF EBC
+ICC             IA32 X64 IPF
+CYGWINGCC       IA32 X64
+