Initial population coming from edk2.
authorbbahnsen <bbahnsen@65ba2f78-6c18-0410-a7b4-885970cf29fa>
Thu, 13 Jul 2006 03:15:10 +0000 (03:15 +0000)
committerbbahnsen <bbahnsen@65ba2f78-6c18-0410-a7b4-885970cf29fa>
Thu, 13 Jul 2006 03:15:10 +0000 (03:15 +0000)
git-svn-id: https://fat-driver2.tianocore.org/svn/fat-driver2/trunk@4 65ba2f78-6c18-0410-a7b4-885970cf29fa

22 files changed:
EnhancedFat/Dxe/ComponentName.c [new file with mode: 0644]
EnhancedFat/Dxe/Data.c [new file with mode: 0644]
EnhancedFat/Dxe/Debug.c [new file with mode: 0644]
EnhancedFat/Dxe/Delete.c [new file with mode: 0644]
EnhancedFat/Dxe/DirectoryCache.c [new file with mode: 0644]
EnhancedFat/Dxe/DirectoryManage.c [new file with mode: 0644]
EnhancedFat/Dxe/DiskCache.c [new file with mode: 0644]
EnhancedFat/Dxe/Fat.c [new file with mode: 0644]
EnhancedFat/Dxe/Fat.h [new file with mode: 0644]
EnhancedFat/Dxe/Fat.msa [new file with mode: 0644]
EnhancedFat/Dxe/FatFileSystem.h [new file with mode: 0644]
EnhancedFat/Dxe/FileName.c [new file with mode: 0644]
EnhancedFat/Dxe/FileSpace.c [new file with mode: 0644]
EnhancedFat/Dxe/Flush.c [new file with mode: 0644]
EnhancedFat/Dxe/Hash.c [new file with mode: 0644]
EnhancedFat/Dxe/Info.c [new file with mode: 0644]
EnhancedFat/Dxe/Init.c [new file with mode: 0644]
EnhancedFat/Dxe/Misc.c [new file with mode: 0644]
EnhancedFat/Dxe/Open.c [new file with mode: 0644]
EnhancedFat/Dxe/OpenVolume.c [new file with mode: 0644]
EnhancedFat/Dxe/ReadWrite.c [new file with mode: 0644]
EnhancedFat/License.txt [new file with mode: 0644]

diff --git a/EnhancedFat/Dxe/ComponentName.c b/EnhancedFat/Dxe/ComponentName.c
new file mode 100644 (file)
index 0000000..4dc480f
--- /dev/null
@@ -0,0 +1,187 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  ComponentName.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+FatComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                 *This,\r
+  IN  EFI_HANDLE                                  ControllerHandle,\r
+  IN  EFI_HANDLE                                  ChildHandle  OPTIONAL,\r
+  IN  CHAR8                                       *Language,\r
+  OUT CHAR16                                      **ControllerName\r
+  );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+EFI_COMPONENT_NAME_PROTOCOL     gFatComponentName = {\r
+  FatComponentNameGetDriverName,\r
+  FatComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mFatDriverNameTable[] = {\r
+  {\r
+    "eng",\r
+    L"FAT File System Driver"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+static EFI_UNICODE_STRING_TABLE mFatControllerNameTable[] = {\r
+  {\r
+    "eng",\r
+    L"FAT File System"\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  }\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Retrieves a Unicode string that is the user readable name of the EFI Driver.\r
+\r
+Arguments:\r
+\r
+  This                  - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  Language              - A pointer to a three character ISO 639-2 language identifier.\r
+                          This is the language of the driver name that that the caller \r
+                          is requesting, and it must match one of the languages specified\r
+                          in SupportedLanguages.  The number of languages supported by a \r
+                          driver is up to the driver writer.\r
+  DriverName            - A pointer to the Unicode string to return.  This Unicode string\r
+                          is the name of the driver specified by This in the language \r
+                          specified by Language.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Unicode string for the Driver specified by This\r
+                          and the language specified by Language was returned \r
+                          in DriverName.\r
+  EFI_INVALID_PARAMETER - Language is NULL.\r
+  EFI_INVALID_PARAMETER - DriverName is NULL.\r
+  EFI_UNSUPPORTED       - The driver specified by This does not support the \r
+                          language specified by Language.\r
+\r
+--*/\r
+{\r
+  return EfiLibLookupUnicodeString (\r
+           Language,\r
+           gFatComponentName.SupportedLanguages,\r
+           mFatDriverNameTable,\r
+           DriverName\r
+           );\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL    *This,\r
+  IN  EFI_HANDLE                     ControllerHandle,\r
+  IN  EFI_HANDLE                     ChildHandle OPTIONAL,\r
+  IN  CHAR8                          *Language,\r
+  OUT CHAR16                         **ControllerName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by an EFI Driver.\r
+\r
+Arguments:\r
+  \r
+  This                  - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.\r
+  ControllerHandle      - The handle of a controller that the driver specified by \r
+                          This is managing.  This handle specifies the controller \r
+                          whose name is to be returned.\r
+  ChildHandle           - The handle of the child controller to retrieve the name \r
+                          of.  This is an optional parameter that may be NULL.  It \r
+                          will be NULL for device drivers.  It will also be NULL \r
+                          for a bus drivers that wish to retrieve the name of the \r
+                          bus controller.  It will not be NULL for a bus driver \r
+                          that wishes to retrieve the name of a child controller.\r
+  Language              - A pointer to a three character ISO 639-2 language \r
+                          identifier.  This is the language of the controller name \r
+                          that that the caller is requesting, and it must match one\r
+                          of the languages specified in SupportedLanguages.  The \r
+                          number of languages supported by a driver is up to the \r
+                          driver writer.\r
+  ControllerName        - A pointer to the Unicode string to return.  This Unicode\r
+                          string is the name of the controller specified by \r
+                          ControllerHandle and ChildHandle in the language specified\r
+                          by Language from the point of view of the driver specified\r
+                          by This. \r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Unicode string for the user readable name in the \r
+                          language specified by Language for the driver \r
+                          specified by This was returned in DriverName.\r
+  EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.\r
+  EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid \r
+                          EFI_HANDLE.\r
+  EFI_INVALID_PARAMETER - Language is NULL.\r
+  EFI_INVALID_PARAMETER - ControllerName is NULL.\r
+  EFI_UNSUPPORTED       - The driver specified by This is not currently managing \r
+                          the controller specified by ControllerHandle and \r
+                          ChildHandle.\r
+  EFI_UNSUPPORTED       - The driver specified by This does not support the \r
+                          language specified by Language.\r
+\r
+--*/\r
+{\r
+  //\r
+  // This is a device driver, so ChildHandle must be NULL.\r
+  //\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EfiLibLookupUnicodeString (\r
+           Language,\r
+           gFatComponentName.SupportedLanguages,\r
+           mFatControllerNameTable,\r
+           ControllerName\r
+           );\r
+}\r
diff --git a/EnhancedFat/Dxe/Data.c b/EnhancedFat/Dxe/Data.c
new file mode 100644 (file)
index 0000000..09aae7d
--- /dev/null
@@ -0,0 +1,51 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  Data.c\r
+\r
+Abstract:\r
+\r
+  Global data in the FAT Filesystem driver\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+//\r
+// Globals\r
+//\r
+//\r
+// Unicode collation interface pointer\r
+//\r
+EFI_UNICODE_COLLATION_PROTOCOL  *gUnicodeCollationInterface;\r
+\r
+//\r
+// FatFsLock - Global lock for synchronizing all requests.\r
+//\r
+EFI_LOCK FatFsLock = EFI_INITIALIZE_LOCK_VARIABLE(EFI_TPL_CALLBACK);\r
+\r
+//\r
+// Filesystem interface functions\r
+//\r
+EFI_FILE                        FatFileInterface = {\r
+  EFI_FILE_HANDLE_REVISION,\r
+  FatOpen,\r
+  FatClose,\r
+  FatDelete,\r
+  FatRead,\r
+  FatWrite,\r
+  FatGetPosition,\r
+  FatSetPosition,\r
+  FatGetInfo,\r
+  FatSetInfo,\r
+  FatFlush\r
+};\r
diff --git a/EnhancedFat/Dxe/Debug.c b/EnhancedFat/Dxe/Debug.c
new file mode 100644 (file)
index 0000000..80eb5b1
--- /dev/null
@@ -0,0 +1,76 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  debug.c\r
+  \r
+Abstract:\r
+\r
+  Debug functions for fat driver\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+VOID\r
+FatDumpFatTable (\r
+  IN FAT_VOLUME   *Volume\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Dump all the FAT Entry of the FAT table in the volume\r
+\r
+Arguments:\r
+\r
+  Volume - The volume whose FAT info will be dumped\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  UINTN   EntryValue;\r
+  UINTN   MaxIndex;\r
+  UINTN   Index;\r
+  CHAR16  *Pointer;\r
+\r
+  MaxIndex = Volume->MaxCluster + 2;\r
+\r
+  Print (L"Dump of Fat Table, MaxCluster %x\n", MaxIndex);\r
+  for (Index = 0; Index < MaxIndex; Index++) {\r
+    EntryValue = FatGetFatEntry (Volume, Index);\r
+    if (EntryValue != FAT_CLUSTER_FREE) {\r
+      Pointer = NULL;\r
+      switch (EntryValue) {\r
+      case FAT_CLUSTER_RESERVED:\r
+        Pointer = L"RESREVED";\r
+        break;\r
+\r
+      case FAT_CLUSTER_BAD:\r
+        Pointer = L"BAD";\r
+        break;\r
+      }\r
+\r
+      if (FAT_END_OF_FAT_CHAIN (EntryValue)) {\r
+        Pointer = L"LAST";\r
+      }\r
+\r
+      if (Pointer != NULL) {\r
+        Print (L"Entry %x = %s\n", Index, Pointer);\r
+      } else {\r
+        Print (L"Entry %x = %x\n", Index, EntryValue);\r
+      }\r
+    }\r
+  }\r
+}\r
diff --git a/EnhancedFat/Dxe/Delete.c b/EnhancedFat/Dxe/Delete.c
new file mode 100644 (file)
index 0000000..8dd173f
--- /dev/null
@@ -0,0 +1,134 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  delete.c\r
+  \r
+Abstract:\r
+\r
+  Function that deletes a file\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDelete (\r
+  IN EFI_FILE  *FHand\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Deletes the file & Closes the file handle.\r
+  \r
+Arguments:\r
+\r
+  FHand                    - Handle to the file to delete.\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS              - Delete the file successfully.\r
+  EFI_WARN_DELETE_FAILURE  - Fail to delete the file.\r
+\r
+--*/\r
+{\r
+  FAT_IFILE   *IFile;\r
+  FAT_OFILE   *OFile;\r
+  FAT_DIRENT  *DirEnt;\r
+  EFI_STATUS  Status;\r
+  UINTN       Round;\r
+\r
+  IFile = IFILE_FROM_FHAND (FHand);\r
+  OFile = IFile->OFile;\r
+\r
+  //\r
+  // Lock the volume\r
+  //\r
+  FatAcquireLock ();\r
+\r
+  //\r
+  // If the file is read-only, then don't delete it\r
+  //\r
+  if (IFile->ReadOnly) {\r
+    Status = EFI_WRITE_PROTECTED;\r
+    goto Done;\r
+  }\r
+  //\r
+  // If the file is the root dir, then don't delete it\r
+  //\r
+  if (OFile->Parent == NULL) {\r
+    Status = EFI_ACCESS_DENIED;\r
+    goto Done;\r
+  }\r
+  //\r
+  // If the file has a permanant error, skip the delete\r
+  //\r
+  Status = OFile->Error;\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // If this is a directory, make sure it's empty before\r
+    // allowing it to be deleted\r
+    //\r
+    if (OFile->ODir != NULL) {\r
+      //\r
+      // We do not allow to delete nonempty directory\r
+      //\r
+      FatResetODirCursor (OFile);\r
+      for (Round = 0; Round < 3; Round++) {\r
+        Status = FatGetNextDirEnt (OFile, &DirEnt);\r
+        if ((EFI_ERROR (Status)) ||\r
+            ((Round < 2) && (DirEnt == NULL || !FatIsDotDirEnt (DirEnt))) ||\r
+            ((Round == 2) && (DirEnt != NULL))\r
+            ) {\r
+          Status = EFI_ACCESS_DENIED;\r
+          goto Done;\r
+        }\r
+      }\r
+    }\r
+    //\r
+    // Return the file's space by setting its size to 0\r
+    //\r
+    FatTruncateOFile (OFile, 0);\r
+    //\r
+    // Free the directory entry for this file\r
+    //\r
+    Status = FatRemoveDirEnt (OFile->Parent, OFile->DirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    //\r
+    // Set a permanent error for this OFile in case there\r
+    // are still opened IFiles attached\r
+    //\r
+    OFile->Error = EFI_NOT_FOUND;\r
+  } else if (OFile->Error == EFI_NOT_FOUND) {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+Done:\r
+  //\r
+  // Always close the handle\r
+  //\r
+  FatIFileClose (IFile);\r
+  //\r
+  // Done\r
+  //\r
+  Status = FatCleanupVolume (OFile->Volume, NULL, Status);\r
+  FatReleaseLock ();\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_WARN_DELETE_FAILURE;\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/EnhancedFat/Dxe/DirectoryCache.c b/EnhancedFat/Dxe/DirectoryCache.c
new file mode 100644 (file)
index 0000000..c9e7771
--- /dev/null
@@ -0,0 +1,234 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  DirectoryCache.c\r
+\r
+Abstract:\r
+\r
+  Functions for directory cache operation\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+STATIC\r
+VOID\r
+FatFreeODir (\r
+  IN FAT_ODIR    *ODir\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Free the directory structure and release the memory.\r
+  \r
+Arguments:\r
+\r
+  ODir                  - The directory to be freed.\r
+  \r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  FAT_DIRENT  *DirEnt;\r
+\r
+  //\r
+  // Release Directory Entry Nodes\r
+  //\r
+  while (!IsListEmpty (&ODir->ChildList)) {\r
+    DirEnt = DIRENT_FROM_LINK (ODir->ChildList.ForwardLink);\r
+    RemoveEntryList (&DirEnt->Link);\r
+    //\r
+    // Make sure the OFile has been closed\r
+    //\r
+    ASSERT (DirEnt->OFile == NULL);\r
+    FatFreeDirEnt (DirEnt);\r
+  }\r
+\r
+  gBS->FreePool (ODir);\r
+}\r
+\r
+STATIC\r
+FAT_ODIR *\r
+FatAllocateODir (\r
+  IN FAT_OFILE   *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Allocate the directory structure.\r
+  \r
+Arguments:\r
+\r
+  OFile                   - The corresponding OFile.\r
+  \r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  FAT_ODIR  *ODir;\r
+\r
+  ODir = EfiLibAllocateZeroPool (sizeof (FAT_ODIR));\r
+  if (ODir != NULL) {\r
+    //\r
+    // Initialize the directory entry list\r
+    //\r
+    ODir->Signature = FAT_ODIR_SIGNATURE;\r
+    InitializeListHead (&ODir->ChildList);\r
+    ODir->CurrentCursor = &ODir->ChildList;\r
+  }\r
+\r
+  return ODir;\r
+}\r
+\r
+VOID\r
+FatDiscardODir (\r
+  IN FAT_OFILE    *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Discard the directory structure when an OFile will be freed.\r
+  Volume will cache this directory if the OFile does not represent a deleted file.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The OFile whose directory structure is to be discarded.\r
+  \r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  FAT_ODIR    *ODir;\r
+  FAT_VOLUME  *Volume;\r
+\r
+  Volume  = OFile->Volume;\r
+  ODir    = OFile->ODir;\r
+  if (!OFile->DirEnt->Invalid) {\r
+    //\r
+    // If OFile does not represent a deleted file, then we will cache the directory\r
+    // We use OFile's first cluster as the directory's tag\r
+    //\r
+    ODir->DirCacheTag = OFile->FileCluster;\r
+    InsertHeadList (&Volume->DirCacheList, &ODir->DirCacheLink);\r
+    if (Volume->DirCacheCount == FAT_MAX_DIR_CACHE_COUNT) {\r
+      //\r
+      // Replace the least recent used directory\r
+      //\r
+      ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);\r
+      RemoveEntryList (&ODir->DirCacheLink);\r
+    } else {\r
+      //\r
+      // No need to find a replace\r
+      //\r
+      Volume->DirCacheCount++;\r
+      ODir = NULL;\r
+    }\r
+  }\r
+  //\r
+  // Release ODir Structure\r
+  //\r
+  if (ODir != NULL) {\r
+    FatFreeODir (ODir);\r
+  }\r
+}\r
+\r
+VOID\r
+FatRequestODir (\r
+  IN FAT_OFILE    *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Request the directory structure when an OFile is newly generated.\r
+  If the directory structure is cached by volume, then just return this directory;\r
+  Otherwise, allocate a new one for OFile.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The OFile which requests directory structure.\r
+  \r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  UINTN           DirCacheTag;\r
+  FAT_VOLUME      *Volume;\r
+  FAT_ODIR        *ODir;\r
+  FAT_ODIR        *CurrentODir;\r
+  EFI_LIST_ENTRY  *CurrentODirLink;\r
+\r
+  Volume      = OFile->Volume;\r
+  ODir        = NULL;\r
+  DirCacheTag = OFile->FileCluster;\r
+  for (CurrentODirLink  = Volume->DirCacheList.ForwardLink;\r
+       CurrentODirLink != &Volume->DirCacheList;\r
+       CurrentODirLink  = CurrentODirLink->ForwardLink\r
+      ) {\r
+    CurrentODir = ODIR_FROM_DIRCACHELINK (CurrentODirLink);\r
+    if (CurrentODir->DirCacheTag == DirCacheTag) {\r
+      RemoveEntryList (&CurrentODir->DirCacheLink);\r
+      Volume->DirCacheCount--;\r
+      ODir = CurrentODir;\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (ODir == NULL) {\r
+    //\r
+    // This directory is not cached, then allocate a new one\r
+    //\r
+    ODir = FatAllocateODir (OFile);\r
+  }\r
+\r
+  OFile->ODir = ODir;\r
+}\r
+\r
+VOID\r
+FatCleanupODirCache (\r
+  IN FAT_VOLUME         *Volume\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Clean up all the cached directory structures when the volume is going to be abandoned.\r
+  \r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  \r
+Returns:\r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  FAT_ODIR  *ODir;\r
+  while (Volume->DirCacheCount > 0) {\r
+    ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);\r
+    RemoveEntryList (&ODir->DirCacheLink);\r
+    FatFreeODir (ODir);\r
+    Volume->DirCacheCount--;\r
+  }\r
+}\r
diff --git a/EnhancedFat/Dxe/DirectoryManage.c b/EnhancedFat/Dxe/DirectoryManage.c
new file mode 100644 (file)
index 0000000..c42ecf6
--- /dev/null
@@ -0,0 +1,1547 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  DirectoryManage.c\r
+\r
+Abstract:\r
+\r
+  Functions for performing directory entry io\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatAccessEntry (\r
+  IN     FAT_OFILE            *Parent,\r
+  IN     IO_MODE              IoMode,\r
+  IN     UINT32               EntryPos,\r
+  IN OUT VOID                 *Entry\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get a directory entry from disk for the Ofile.\r
+  \r
+Arguments:\r
+\r
+  Parent                - The parent of the OFile which need to update.\r
+  IoMode                - Indicate whether to read directory entry or write directroy entry.\r
+  EntryPos              - The position of the directory entry to be accessed.\r
+  Entry                 - The directory entry read or written.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - Access the directory entry sucessfully.\r
+  other                 - An error occurred when reading the directory entry.\r
+  \r
+--*/\r
+{\r
+  UINTN Position;\r
+  UINTN BufferSize;\r
+  Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY);\r
+  if (Position >= Parent->FileSize) {\r
+    //\r
+    // End of directory\r
+    //\r
+    ASSERT (IoMode == READ_DATA);\r
+    ((FAT_DIRECTORY_ENTRY *) Entry)->FileName[0] = EMPTY_ENTRY_MARK;\r
+    ((FAT_DIRECTORY_ENTRY *) Entry)->Attributes  = 0;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BufferSize = sizeof (FAT_DIRECTORY_ENTRY);\r
+  return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry);\r
+}\r
+\r
+EFI_STATUS\r
+FatStoreDirEnt (\r
+  IN FAT_OFILE            *OFile,\r
+  IN FAT_DIRENT           *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Save the directory entry to disk.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The parent OFile which needs to update.\r
+  DirEnt                - The directory entry to be saved.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - Store the directory entry successfully.\r
+  other                 - An error occurred when writing the directory entry.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS        Status;\r
+  FAT_DIRECTORY_LFN LfnEntry;\r
+  UINT16            EntryPos;\r
+  CHAR16            *LfnBufferPointer;\r
+  CHAR16            LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];\r
+  UINT8             EntryCount;\r
+  UINT8             LfnOrdinal;\r
+\r
+  EntryPos   = DirEnt->EntryPos;\r
+  EntryCount = DirEnt->EntryCount;\r
+  //\r
+  // Write directory entry\r
+  //\r
+  Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &DirEnt->Entry);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (--EntryCount > 0) {\r
+    //\r
+    // Write LFN directory entry\r
+    //\r
+    EfiSetMem (LfnBuffer, sizeof (CHAR16) * LFN_CHAR_TOTAL * EntryCount, 0xff);\r
+    EfiStrCpy (LfnBuffer, DirEnt->FileString);\r
+    LfnBufferPointer    = LfnBuffer;\r
+    LfnEntry.Attributes = FAT_ATTRIBUTE_LFN;\r
+    LfnEntry.Type       = 0;\r
+    LfnEntry.MustBeZero = 0;\r
+    LfnEntry.Checksum   = FatCheckSum (DirEnt->Entry.FileName);\r
+    for (LfnOrdinal = 1; LfnOrdinal <= EntryCount; LfnOrdinal++) {\r
+      LfnEntry.Ordinal = LfnOrdinal;\r
+      if (LfnOrdinal == EntryCount) {\r
+        LfnEntry.Ordinal |= FAT_LFN_LAST;\r
+      }\r
+\r
+      EfiCopyMem (LfnEntry.Name1, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR1_LEN);\r
+      LfnBufferPointer += LFN_CHAR1_LEN;\r
+      EfiCopyMem (LfnEntry.Name2, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR2_LEN);\r
+      LfnBufferPointer += LFN_CHAR2_LEN;\r
+      EfiCopyMem (LfnEntry.Name3, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR3_LEN);\r
+      LfnBufferPointer += LFN_CHAR3_LEN;\r
+      EntryPos--;\r
+      if (DirEnt->Invalid) {\r
+        LfnEntry.Ordinal = DELETE_ENTRY_MARK;\r
+      }\r
+\r
+      Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &LfnEntry);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+FatIsDotDirEnt (\r
+  IN FAT_DIRENT  *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Determine whether the directory entry is "." or ".." entry.\r
+  \r
+Arguments:\r
+\r
+  DirEnt               - The corresponding directory entry. \r
+\r
+Returns: \r
+\r
+  TRUE                 - The directory entry is "." or ".." directory entry\r
+  FALSE                - The directory entry is not "." or ".." directory entry\r
+  \r
+--*/\r
+{\r
+  CHAR16  *FileString;\r
+  FileString = DirEnt->FileString;\r
+  if (EfiStrCmp (FileString, L".") == 0 || EfiStrCmp (FileString, L"..") == 0) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatSetDirEntCluster (\r
+  IN FAT_OFILE    *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set the OFile's cluster info in its directory entry.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The corresponding OFile.\r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  UINTN       Cluster;\r
+  FAT_DIRENT  *DirEnt;\r
+\r
+  DirEnt                        = OFile->DirEnt;\r
+  Cluster                       = OFile->FileCluster;\r
+  DirEnt->Entry.FileClusterHigh = (UINT16) (Cluster >> 16);\r
+  DirEnt->Entry.FileCluster     = (UINT16) Cluster;\r
+}\r
+\r
+VOID\r
+FatUpdateDirEntClusterSizeInfo (\r
+  IN FAT_OFILE    *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set the OFile's cluster and size info in its directory entry.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The corresponding OFile.\r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  ASSERT (OFile->ODir == NULL);\r
+  OFile->DirEnt->Entry.FileSize = (UINT32) OFile->FileSize;\r
+  FatSetDirEntCluster (OFile);\r
+}\r
+\r
+VOID\r
+FatCloneDirEnt (\r
+  IN  FAT_DIRENT          *DirEnt1,\r
+  IN  FAT_DIRENT          *DirEnt2\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.\r
+\r
+Arguments:\r
+\r
+  DirEnt1               - The destination directory entry.\r
+  DirEnt2               - The source directory entry.\r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  UINT8 *Entry1;\r
+  UINT8 *Entry2;\r
+  Entry1  = (UINT8 *) &DirEnt1->Entry;\r
+  Entry2  = (UINT8 *) &DirEnt2->Entry;\r
+  EfiCopyMem (\r
+    Entry1 + FAT_ENTRY_INFO_OFFSET, \r
+    Entry2 + FAT_ENTRY_INFO_OFFSET, \r
+    sizeof (FAT_DIRECTORY_ENTRY) - FAT_ENTRY_INFO_OFFSET\r
+    );\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatLoadLongNameEntry (\r
+  IN FAT_OFILE           *Parent,\r
+  IN FAT_DIRENT          *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the LFN for the directory entry.\r
+  \r
+Arguments:\r
+\r
+  Parent                - The parent directory.\r
+  DirEnt                - The directory entry to get LFN.\r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  CHAR16            LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];\r
+  CHAR16            *LfnBufferPointer;\r
+  CHAR8             *File8Dot3Name;\r
+  UINT16            EntryPos;\r
+  UINT8             LfnOrdinal;\r
+  UINT8             LfnChecksum;\r
+  FAT_DIRECTORY_LFN LfnEntry;\r
+  EFI_STATUS        Status;\r
+\r
+  EntryPos          = DirEnt->EntryPos;\r
+  File8Dot3Name     = DirEnt->Entry.FileName;\r
+  LfnBufferPointer  = LfnBuffer;\r
+  //\r
+  // Computes checksum for LFN\r
+  //\r
+  LfnChecksum = FatCheckSum (File8Dot3Name);\r
+  LfnOrdinal  = 1;\r
+  do {\r
+    if (EntryPos == 0) {\r
+      LfnBufferPointer = LfnBuffer;\r
+      break;\r
+    }\r
+\r
+    EntryPos--;\r
+    Status = FatAccessEntry (Parent, READ_DATA, EntryPos, &LfnEntry);\r
+    if (EFI_ERROR (Status) ||\r
+        LfnEntry.Attributes != FAT_ATTRIBUTE_LFN ||\r
+        LfnEntry.MustBeZero != 0 ||\r
+        LfnEntry.Checksum != LfnChecksum ||\r
+        (LfnEntry.Ordinal & (~FAT_LFN_LAST)) != LfnOrdinal ||\r
+        LfnOrdinal > MAX_LFN_ENTRIES\r
+        ) {\r
+      //\r
+      // The directory entry does not have a long file name or\r
+      // some error occurs when loading long file name for a directory entry,\r
+      // and then we load the long name from short name\r
+      //\r
+      LfnBufferPointer = LfnBuffer;\r
+      break;\r
+    }\r
+\r
+    EfiCopyMem (LfnBufferPointer, LfnEntry.Name1, sizeof (CHAR16) * LFN_CHAR1_LEN);\r
+    LfnBufferPointer += LFN_CHAR1_LEN;\r
+    EfiCopyMem (LfnBufferPointer, LfnEntry.Name2, sizeof (CHAR16) * LFN_CHAR2_LEN);\r
+    LfnBufferPointer += LFN_CHAR2_LEN;\r
+    EfiCopyMem (LfnBufferPointer, LfnEntry.Name3, sizeof (CHAR16) * LFN_CHAR3_LEN);\r
+    LfnBufferPointer += LFN_CHAR3_LEN;\r
+    LfnOrdinal++;\r
+  } while ((LfnEntry.Ordinal & FAT_LFN_LAST) == 0);\r
+  DirEnt->EntryCount = LfnOrdinal;\r
+  //\r
+  // Terminate current Lfnbuffer\r
+  //\r
+  *LfnBufferPointer = 0;\r
+  if (LfnBufferPointer == LfnBuffer) {\r
+    //\r
+    // Fail to get the long file name from long file name entry,\r
+    // get the file name from short name\r
+    //\r
+    FatGetFileNameViaCaseFlag (DirEnt, LfnBuffer);\r
+  }\r
+\r
+  DirEnt->FileString = EfiLibAllocateCopyPool (EfiStrSize (LfnBuffer), LfnBuffer);\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatAddDirEnt (\r
+  IN FAT_ODIR             *ODir,\r
+  IN FAT_DIRENT           *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Add this directory entry node to the list of directory entries and hash table.\r
+  \r
+Arguments:\r
+\r
+  ODir                  - The parent OFile which needs to be updated.\r
+  DirEnt                - The directory entry to be added. \r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  if (DirEnt->Link.BackLink == NULL) {\r
+    DirEnt->Link.BackLink = &ODir->ChildList;\r
+  }\r
+  InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link);\r
+  FatInsertToHashTable (ODir, DirEnt);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatLoadNextDirEnt (\r
+  IN  FAT_OFILE           *OFile,\r
+  OUT FAT_DIRENT          **PtrDirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Load from disk the next directory entry at current end of directory position \r
+  \r
+Arguments:\r
+\r
+  OFile                 - The parent OFile.\r
+  PtrDirEnt             - The directory entry that is loaded. \r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - Load the directory entry successfully.\r
+  EFI_OUT_OF_RESOURCES  - Out of resource.\r
+  other                 - An error occurred when reading the directory entries.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS          Status;\r
+  FAT_DIRENT          *DirEnt;\r
+  FAT_ODIR            *ODir;\r
+  FAT_DIRECTORY_ENTRY Entry;\r
+\r
+  ODir = OFile->ODir;\r
+  //\r
+  // Make sure the parent's directory has been opened\r
+  //\r
+  ASSERT (ODir != NULL);\r
+  //\r
+  // Assert we have not reached the end of directory\r
+  //\r
+  ASSERT (!ODir->EndOfDir);\r
+  DirEnt = NULL;\r
+\r
+  for (;;) {\r
+    //\r
+    // Read the next directory entry until we find a valid directory entry (excluding lfn entry)\r
+    //\r
+    Status = FatAccessEntry (OFile, READ_DATA, ODir->CurrentEndPos, &Entry);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (((UINT8)Entry.FileName[0] != DELETE_ENTRY_MARK) && \r
+        (Entry.Attributes & FAT_ATTRIBUTE_VOLUME_ID) == 0) {\r
+      //\r
+      // We get a valid directory entry, then handle it\r
+      //\r
+      break;\r
+    }\r
+\r
+    ODir->CurrentEndPos++;\r
+  }\r
+\r
+  if (Entry.FileName[0] != EMPTY_ENTRY_MARK) {\r
+    //\r
+    // This is a valid directory entry\r
+    //\r
+    DirEnt = EfiLibAllocateZeroPool (sizeof (FAT_DIRENT));\r
+    if (DirEnt == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    DirEnt->Signature = FAT_DIRENT_SIGNATURE;\r
+    //\r
+    // Remember the directory's entry position on disk\r
+    //\r
+    DirEnt->EntryPos = (UINT16) ODir->CurrentEndPos;\r
+    EfiCopyMem (&DirEnt->Entry, &Entry, sizeof (FAT_DIRECTORY_ENTRY));\r
+    FatLoadLongNameEntry (OFile, DirEnt);\r
+    if (DirEnt->FileString == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+    //\r
+    // Add this directory entry to directory\r
+    //\r
+    FatAddDirEnt (ODir, DirEnt);\r
+    //\r
+    // Point to next directory entry\r
+    //\r
+    ODir->CurrentEndPos++;\r
+  } else {\r
+    ODir->EndOfDir = TRUE;\r
+  }\r
+\r
+  *PtrDirEnt = DirEnt;\r
+  return EFI_SUCCESS;\r
+\r
+Done:\r
+  FatFreeDirEnt (DirEnt);\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatGetDirEntInfo (\r
+  IN     FAT_VOLUME         *Volume,\r
+  IN     FAT_DIRENT         *DirEnt,\r
+  IN OUT UINTN              *BufferSize,\r
+     OUT VOID               *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Get the directory entry's info into Buffer.\r
+\r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  DirEnt                - The corresponding directory entry.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing file info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get the file info successfully.\r
+  EFI_BUFFER_TOO_SMALL  - The buffer is too small.\r
+\r
+--*/\r
+{\r
+  UINTN               Size;\r
+  UINTN               NameSize;\r
+  UINTN               ResultSize;\r
+  UINTN               ClusterSize;\r
+  UINTN               Cluster;\r
+  EFI_STATUS          Status;\r
+  EFI_FILE_INFO       *Info;\r
+  FAT_DIRECTORY_ENTRY *Entry;\r
+  FAT_DATE_TIME       FatLastAccess;\r
+\r
+  ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+  Size        = SIZE_OF_EFI_FILE_INFO;\r
+  NameSize    = EfiStrSize (DirEnt->FileString);\r
+  ResultSize  = Size + NameSize;\r
+\r
+  Status      = EFI_BUFFER_TOO_SMALL;\r
+  if (*BufferSize >= ResultSize) {\r
+    Status      = EFI_SUCCESS;\r
+    Entry       = &DirEnt->Entry;\r
+    ClusterSize = Volume->ClusterSize;\r
+    Info        = Buffer;\r
+    Info->Size  = ResultSize;\r
+    if ((Entry->Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {\r
+      Cluster             = (Entry->FileClusterHigh << 16) | Entry->FileCluster;\r
+      Info->PhysicalSize  = FatPhysicalDirSize (Volume, Cluster);\r
+      Info->FileSize      = Info->PhysicalSize;\r
+    } else {\r
+      Info->FileSize      = Entry->FileSize;\r
+      Info->PhysicalSize  = FatPhysicalFileSize (Volume, Entry->FileSize);\r
+    }\r
+\r
+    EfiZeroMem (&FatLastAccess.Time, sizeof (FatLastAccess.Time));\r
+    EfiCopyMem (&FatLastAccess.Date, &Entry->FileLastAccess, sizeof (FatLastAccess.Date));\r
+    FatFatTimeToEfiTime (&FatLastAccess, &Info->LastAccessTime);\r
+    FatFatTimeToEfiTime (&Entry->FileCreateTime, &Info->CreateTime);\r
+    FatFatTimeToEfiTime (&Entry->FileModificationTime, &Info->ModificationTime);\r
+    Info->Attribute = Entry->Attributes & EFI_FILE_VALID_ATTR;\r
+    EfiCopyMem ((CHAR8 *) Buffer + Size, DirEnt->FileString, NameSize);\r
+  }\r
+\r
+  *BufferSize = ResultSize;\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatSearchODir (\r
+  IN  FAT_OFILE      *OFile,\r
+  IN  CHAR16         *FileNameString,\r
+  OUT FAT_DIRENT     **PtrDirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Search the directory for the directory entry whose filename is FileNameString.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The parent OFile whose directory is to be searched.\r
+  FileNameString        - The filename to be searched.\r
+  PtrDirEnt             - pointer to the directory entry if found.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - Find the directory entry or not found.\r
+  other                 - An error occurred when reading the directory entries.\r
+  \r
+--*/\r
+{\r
+  BOOLEAN     PossibleShortName;\r
+  CHAR8       File8Dot3Name[FAT_NAME_LEN];\r
+  FAT_ODIR    *ODir;\r
+  FAT_DIRENT  *DirEnt;\r
+  EFI_STATUS  Status;\r
+\r
+  ODir = OFile->ODir;\r
+  ASSERT (ODir != NULL);\r
+  //\r
+  // Check if the file name is a valid short name\r
+  //\r
+  PossibleShortName = FatCheckIs8Dot3Name (FileNameString, File8Dot3Name);\r
+  //\r
+  // Search the hash table first\r
+  //\r
+  DirEnt = *FatLongNameHashSearch (ODir, FileNameString);\r
+  if (DirEnt == NULL && PossibleShortName) {\r
+      DirEnt = *FatShortNameHashSearch (ODir, File8Dot3Name);\r
+  }\r
+  if (DirEnt == NULL) {\r
+    //\r
+    // We fail to get the directory entry from hash table; we then\r
+    // search the rest directory\r
+    //\r
+    while (!ODir->EndOfDir) {\r
+      Status = FatLoadNextDirEnt (OFile, &DirEnt);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      if (DirEnt != NULL) {\r
+        if (FatStriCmp (FileNameString, DirEnt->FileString) == 0) {\r
+          break;\r
+        }\r
+\r
+        if (PossibleShortName && EfiCompareMem (File8Dot3Name, DirEnt->Entry.FileName, FAT_NAME_LEN) == 0) {\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  *PtrDirEnt = DirEnt;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+FatResetODirCursor (\r
+  IN FAT_OFILE    *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set the OFile's current directory cursor to the list head.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The directory OFile whose directory cursor is reset.\r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  FAT_ODIR  *ODir;\r
+\r
+  ODir = OFile->ODir;\r
+  ASSERT (ODir != NULL);\r
+  ODir->CurrentCursor = &(ODir->ChildList);\r
+  ODir->CurrentPos    = 0;\r
+}\r
+\r
+EFI_STATUS\r
+FatGetNextDirEnt (\r
+  IN  FAT_OFILE     *OFile,\r
+  OUT FAT_DIRENT    **PtrDirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set the directory\92s cursor to the next and get the next directory entry.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The parent OFile.\r
+  PtrDirEnt                      - The next directory entry.\r
+  \r
+Returns: \r
+\r
+  EFI_SUCCESS            - We get the next directory entry successfully.\r
+  other                 - An error occurred when get next directory entry.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  FAT_DIRENT  *DirEnt;\r
+  FAT_ODIR    *ODir;\r
+\r
+  ODir = OFile->ODir;\r
+  ASSERT (ODir != NULL);\r
+  if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {\r
+    //\r
+    // End of directory, we will try one more time\r
+    //\r
+    if (!ODir->EndOfDir) {\r
+      //\r
+      // Read directory from disk\r
+      //\r
+      Status = FatLoadNextDirEnt (OFile, &DirEnt);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {\r
+    //\r
+    // End of directory, return NULL\r
+    //\r
+    DirEnt              = NULL;\r
+    ODir->CurrentPos    = ODir->CurrentEndPos;\r
+  } else {\r
+    ODir->CurrentCursor = ODir->CurrentCursor->ForwardLink;\r
+    DirEnt              = DIRENT_FROM_LINK (ODir->CurrentCursor);\r
+    ODir->CurrentPos    = DirEnt->EntryPos + 1;\r
+  }\r
+\r
+  *PtrDirEnt = DirEnt;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatSetEntryCount (\r
+  IN FAT_OFILE    *OFile,\r
+  IN FAT_DIRENT   *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set the directory entry count according to the filename.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The corresponding OFile.\r
+  DirEnt                - The directory entry to be set.\r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  CHAR16  *FileString;\r
+  CHAR8   *File8Dot3Name;\r
+\r
+  //\r
+  // Get new entry count and set the 8.3 name\r
+  //\r
+  DirEnt->EntryCount  = 1;\r
+  FileString          = DirEnt->FileString;\r
+  File8Dot3Name       = DirEnt->Entry.FileName;\r
+  EfiSetMem (File8Dot3Name, FAT_NAME_LEN, ' ');\r
+  if (EfiStrCmp (FileString, L".") == 0) {\r
+    //\r
+    // "." entry\r
+    //\r
+    File8Dot3Name[0] = '.';\r
+    FatCloneDirEnt (DirEnt, OFile->DirEnt);\r
+  } else if (EfiStrCmp (FileString, L"..") == 0) {\r
+    //\r
+    // ".." entry\r
+    //\r
+    File8Dot3Name[0]  = '.';\r
+    File8Dot3Name[1]  = '.';\r
+    FatCloneDirEnt (DirEnt, OFile->Parent->DirEnt);\r
+  } else {\r
+    //\r
+    // Normal name\r
+    //\r
+    if (FatCheckIs8Dot3Name (FileString, File8Dot3Name)) {\r
+      //\r
+      // This file name is a valid 8.3 file name, we need to further check its case flag\r
+      //\r
+      FatSetCaseFlag (DirEnt);\r
+    } else {\r
+      //\r
+      // The file name is not a valid 8.3 name we need to generate an 8.3 name for it\r
+      //\r
+      FatCreate8Dot3Name (OFile, DirEnt);\r
+      DirEnt->EntryCount += LFN_ENTRY_NUMBER ((UINT8) EfiStrLen (FileString));\r
+    }\r
+  }\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatExpandODir (\r
+  IN FAT_OFILE  *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Append a zero cluster to the current OFile.\r
+  \r
+Arguments:\r
+\r
+  OFile        - The directory OFile which needs to be updated.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS  - Append a zero cluster to the OFile successfully.\r
+  other        - An error occurred when appending the zero cluster.\r
+  \r
+--*/\r
+{\r
+  return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatSeekVolumeId (\r
+  IN  FAT_OFILE            *Root,\r
+  OUT FAT_DIRENT           *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Search the Root OFile for the possible volume label.\r
+  \r
+Arguments:\r
+\r
+  Root                  - The Root OFile.\r
+  DirEnt                - The returned directory entry of volume label.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - The search process is completed successfully.\r
+  other                 - An error occurred when searching volume label.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT16              EntryPos;\r
+  FAT_DIRECTORY_ENTRY *Entry;\r
+  EntryPos        = 0;\r
+  Entry           = &DirEnt->Entry;\r
+  DirEnt->Invalid = TRUE;\r
+  do {\r
+    Status = FatAccessEntry (Root, READ_DATA, EntryPos, Entry);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (((Entry->Attributes) & (~FAT_ATTRIBUTE_ARCHIVE)) == FAT_ATTRIBUTE_VOLUME_ID) {\r
+      DirEnt->EntryPos   = EntryPos;\r
+      DirEnt->EntryCount = 1;\r
+      DirEnt->Invalid    = FALSE;\r
+      break;\r
+    }\r
+\r
+    EntryPos++;\r
+  } while (Entry->FileName[0] != EMPTY_ENTRY_MARK);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatFirstFitInsertDirEnt (\r
+  IN FAT_OFILE    *OFile,\r
+  IN FAT_DIRENT   *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Use First Fit Algorithm to insert directory entry. \r
+  Only this function will erase "E5" entries in a directory. \r
+  In view of safest recovery, this function will only be triggered \r
+  when maximum directory entry number has reached.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The corresponding OFile.\r
+  DirEnt                - The directory entry to be inserted.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - The directory entry has been successfully inserted.\r
+  EFI_VOLUME_FULL       - The directory can not hold more directory entries.\r
+  Others                - Some error occurred when inserting new directory entries.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS      Status;\r
+  FAT_ODIR        *ODir;\r
+  EFI_LIST_ENTRY  *CurrentEntry;\r
+  FAT_DIRENT      *CurrentDirEnt;\r
+  UINT32          CurrentPos;\r
+  UINT32          LabelPos;\r
+  UINT32          NewEntryPos;\r
+  UINT16          EntryCount;\r
+  FAT_DIRENT      LabelDirEnt;\r
+\r
+  LabelPos = 0;\r
+  if (OFile->Parent == NULL) {\r
+    Status = FatSeekVolumeId (OFile, &LabelDirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (!LabelDirEnt.Invalid) {\r
+      LabelPos = LabelDirEnt.EntryPos;\r
+    }\r
+  }\r
+\r
+  EntryCount  = DirEnt->EntryCount;\r
+  NewEntryPos = EntryCount;\r
+  CurrentPos  = 0;\r
+  ODir        = OFile->ODir;\r
+  for (CurrentEntry = ODir->ChildList.ForwardLink;\r
+       CurrentEntry != &ODir->ChildList;\r
+       CurrentEntry = CurrentEntry->ForwardLink\r
+      ) {\r
+    CurrentDirEnt = DIRENT_FROM_LINK (CurrentEntry);\r
+    if (NewEntryPos + CurrentDirEnt->EntryCount <= CurrentDirEnt->EntryPos) {\r
+      if (LabelPos > NewEntryPos || LabelPos <= CurrentPos) {\r
+        //\r
+        // first fit succeeded\r
+        //\r
+        goto Done;\r
+      }\r
+    }\r
+\r
+    CurrentPos  = CurrentDirEnt->EntryPos;\r
+    NewEntryPos = CurrentPos + EntryCount;\r
+  }\r
+\r
+  if (NewEntryPos >= ODir->CurrentEndPos) {\r
+    return EFI_VOLUME_FULL;\r
+  }\r
+\r
+Done:\r
+  DirEnt->EntryPos   = (UINT16) NewEntryPos;\r
+  DirEnt->Link.BackLink = CurrentEntry;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatNewEntryPos (\r
+  IN FAT_OFILE    *OFile,\r
+  IN FAT_DIRENT   *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Find the new directory entry position for the directory entry.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The corresponding OFile.\r
+  DirEnt                - The directory entry whose new position is to be set.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - The new directory entry position is successfully found.\r
+  EFI_VOLUME_FULL       - The directory has reach its maximum capacity.\r
+  other                 - An error occurred when reading the directory entry.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  FAT_ODIR    *ODir;\r
+  FAT_DIRENT  *TempDirEnt;\r
+  UINT32      NewEndPos;\r
+\r
+  ODir = OFile->ODir;\r
+  ASSERT (ODir != NULL);\r
+  //\r
+  // Make sure the whole directory has been loaded\r
+  //\r
+  while (!ODir->EndOfDir) {\r
+    Status = FatLoadNextDirEnt (OFile, &TempDirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // We will append this entry to the end of directory\r
+  //\r
+  FatGetCurrentFatTime (&DirEnt->Entry.FileCreateTime);\r
+  FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime);\r
+  NewEndPos = ODir->CurrentEndPos + DirEnt->EntryCount;\r
+  if (NewEndPos * sizeof (FAT_DIRECTORY_ENTRY) > OFile->FileSize) {\r
+    if (NewEndPos >= (OFile->IsFixedRootDir ? OFile->Volume->RootEntries : FAT_MAX_DIRENTRY_COUNT)) {\r
+      //\r
+      // We try to use fist fit algorithm to insert this directory entry\r
+      //\r
+      return FatFirstFitInsertDirEnt (OFile, DirEnt);\r
+    }\r
+    //\r
+    // We should allocate a new cluster for this directory\r
+    //\r
+    Status = FatExpandODir (OFile);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // We append our directory entry at the end of directory file\r
+  //\r
+  ODir->CurrentEndPos = NewEndPos;\r
+  DirEnt->EntryPos = (UINT16) (ODir->CurrentEndPos - 1);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatGetVolumeEntry (\r
+  IN FAT_VOLUME           *Volume,\r
+  IN CHAR16               *Name\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the directory entry for the volume.\r
+  \r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  Name                  - The file name of the volume.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - Update the volume with the directory entry sucessfully.\r
+  others                - An error occurred when getting volume label.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  FAT_DIRENT  LabelDirEnt;\r
+\r
+  *Name   = 0;\r
+  Status  = FatSeekVolumeId (Volume->Root, &LabelDirEnt);\r
+  if (!EFI_ERROR (Status)) {\r
+    if (!LabelDirEnt.Invalid) {\r
+      FatNameToStr (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, FALSE, Name);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatSetVolumeEntry (\r
+  IN FAT_VOLUME           *Volume,\r
+  IN CHAR16               *Name\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set the relevant directory entry into disk for the volume.\r
+  \r
+Arguments:\r
+\r
+  Volume              - FAT file system volume.\r
+  Name                - The new file name of the volume.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS         - Update the Volume sucessfully.\r
+  EFI_UNSUPPORTED     - The input label is not a valid volume label.\r
+  other               - An error occurred when setting volume label.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  FAT_DIRENT  LabelDirEnt;\r
+  FAT_OFILE   *Root;\r
+\r
+  Root    = Volume->Root;\r
+  Status  = FatSeekVolumeId (Volume->Root, &LabelDirEnt);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (LabelDirEnt.Invalid) {\r
+    //\r
+    // If there is not the relevant directory entry, create a new one\r
+    //\r
+    EfiZeroMem (&LabelDirEnt, sizeof (FAT_DIRENT));\r
+    LabelDirEnt.EntryCount = 1;\r
+    Status                 = FatNewEntryPos (Root, &LabelDirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    LabelDirEnt.Entry.Attributes = FAT_ATTRIBUTE_VOLUME_ID;\r
+  }\r
+\r
+  EfiSetMem (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, ' ');\r
+  if (FatStrToFat (Name, FAT_NAME_LEN, LabelDirEnt.Entry.FileName)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  FatGetCurrentFatTime (&LabelDirEnt.Entry.FileModificationTime);\r
+  return FatStoreDirEnt (Root, &LabelDirEnt);\r
+}\r
+\r
+EFI_STATUS\r
+FatCreateDotDirEnts (\r
+  IN FAT_OFILE          *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create "." and ".." directory entries in the newly-created parent OFile.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The parent OFile.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - The dot directory entries are successfully created.\r
+  other                 - An error occurred when creating the directory entry.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  FAT_DIRENT  *DirEnt;\r
+\r
+  Status = FatExpandODir (OFile);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FatSetDirEntCluster (OFile);\r
+  //\r
+  // Create "."\r
+  //\r
+  Status = FatCreateDirEnt (OFile, L".", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Create ".."\r
+  //\r
+  Status = FatCreateDirEnt (OFile, L"..", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatCreateDirEnt (\r
+  IN  FAT_OFILE         *OFile,\r
+  IN  CHAR16            *FileName,\r
+  IN  UINT8             Attributes,\r
+  OUT FAT_DIRENT        **PtrDirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create a directory entry in the parent OFile.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The parent OFile.\r
+  FileName              - The filename of the newly-created directory entry.\r
+  Attributes            - The attribute of the newly-created directory entry.\r
+  PtrDirEnt             - The pointer to the newly-created directory entry.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - The directory entry is successfully created.\r
+  EFI_OUT_OF_RESOURCES  - Not enough memory to create the directory entry.\r
+  other                 - An error occurred when creating the directory entry.\r
+  \r
+--*/\r
+{\r
+  FAT_DIRENT  *DirEnt;\r
+  FAT_ODIR    *ODir;\r
+  EFI_STATUS  Status;\r
+\r
+  ODir = OFile->ODir;\r
+  ASSERT (ODir != NULL);\r
+  DirEnt = EfiLibAllocateZeroPool (sizeof (FAT_DIRENT));\r
+  if (DirEnt == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  DirEnt->Signature   = FAT_DIRENT_SIGNATURE;\r
+  DirEnt->FileString  = EfiLibAllocateCopyPool (EfiStrSize (FileName), FileName);\r
+  if (DirEnt->FileString == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+  //\r
+  // Determine how many directory entries we need\r
+  //\r
+  FatSetEntryCount (OFile, DirEnt);\r
+  //\r
+  // Determine the file's directory entry position\r
+  //\r
+  Status = FatNewEntryPos (OFile, DirEnt);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  FatAddDirEnt (ODir, DirEnt);\r
+  DirEnt->Entry.Attributes = Attributes;\r
+  *PtrDirEnt               = DirEnt;\r
+  DEBUG ((EFI_D_INFO, "FSOpen: Created new directory entry '%S'\n", DirEnt->FileString));\r
+  return FatStoreDirEnt (OFile, DirEnt);\r
+\r
+Done:\r
+  FatFreeDirEnt (DirEnt);\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatRemoveDirEnt (\r
+  IN FAT_OFILE    *OFile,\r
+  IN FAT_DIRENT   *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Remove this directory entry node from the list of directory entries and hash table. \r
+  \r
+Arguments:\r
+\r
+  OFile                - The parent OFile.\r
+  DirEnt               - The directory entry to be removed.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS          - The directory entry is successfully removed.\r
+  other                - An error occurred when removing the directory entry.\r
+  \r
+--*/\r
+{\r
+  FAT_ODIR  *ODir;\r
+\r
+  ODir = OFile->ODir;\r
+  if (ODir->CurrentCursor == &DirEnt->Link) {\r
+    //\r
+    // Move the directory cursor to its previous directory entry\r
+    //\r
+    ODir->CurrentCursor = ODir->CurrentCursor->BackLink;\r
+  }\r
+  //\r
+  // Remove from directory entry list\r
+  //\r
+  RemoveEntryList (&DirEnt->Link);\r
+  //\r
+  // Remove from hash table\r
+  //\r
+  FatDeleteFromHashTable (ODir, DirEnt);\r
+  DirEnt->Entry.FileName[0] = DELETE_ENTRY_MARK;\r
+  DirEnt->Invalid           = TRUE;\r
+  return FatStoreDirEnt (OFile, DirEnt);\r
+}\r
+\r
+EFI_STATUS\r
+FatOpenDirEnt (\r
+  IN FAT_OFILE         *Parent,\r
+  IN FAT_DIRENT        *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Open the directory entry to get the OFile.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The parent OFile.\r
+  DirEnt                - The directory entry to be opened.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - The directory entry is successfully opened.\r
+  EFI_OUT_OF_RESOURCES  - not enough memory to allocate a new OFile.\r
+  other                 - An error occurred when opening the directory entry.\r
+  \r
+--*/\r
+{\r
+  FAT_OFILE   *OFile;\r
+  FAT_VOLUME  *Volume;\r
+\r
+  if (DirEnt->OFile == NULL) {\r
+    //\r
+    // Open the directory entry\r
+    //\r
+    OFile = EfiLibAllocateZeroPool (sizeof (FAT_OFILE));\r
+    if (OFile == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    OFile->Signature = FAT_OFILE_SIGNATURE;\r
+    InitializeListHead (&OFile->Opens);\r
+    InitializeListHead (&OFile->ChildHead);\r
+    OFile->Parent = Parent;\r
+    OFile->DirEnt = DirEnt;\r
+    if (Parent != NULL) {\r
+      //\r
+      // The newly created OFile is not root\r
+      //\r
+      Volume             = Parent->Volume;\r
+      OFile->FullPathLen = Parent->FullPathLen + 1 + EfiStrLen (DirEnt->FileString);\r
+      OFile->FileCluster = ((DirEnt->Entry.FileClusterHigh) << 16) | (DirEnt->Entry.FileCluster);\r
+      InsertTailList (&Parent->ChildHead, &OFile->ChildLink);\r
+    } else {\r
+      //\r
+      // The newly created OFile is root\r
+      //\r
+      Volume                = VOLUME_FROM_ROOT_DIRENT (DirEnt);\r
+      Volume->Root          = OFile;\r
+      OFile->FileCluster    = Volume->RootCluster;\r
+      if (Volume->FatType  != FAT32) {\r
+        OFile->IsFixedRootDir  = TRUE;\r
+      }\r
+    }\r
+\r
+    OFile->FileCurrentCluster  = OFile->FileCluster;\r
+    OFile->Volume              = Volume;\r
+    InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);\r
+\r
+    OFile->FileSize = DirEnt->Entry.FileSize;\r
+    if ((DirEnt->Entry.Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {\r
+      if (OFile->IsFixedRootDir) {\r
+        OFile->FileSize = Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY);\r
+      } else {\r
+        OFile->FileSize = FatPhysicalDirSize (Volume, OFile->FileCluster);\r
+      }\r
+\r
+      FatRequestODir (OFile);\r
+      if (OFile->ODir == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+    }\r
+\r
+    DirEnt->OFile = OFile;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+FatCloseDirEnt (\r
+  IN FAT_DIRENT        *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Close the directory entry and free the OFile.\r
+  \r
+Arguments:\r
+\r
+  DirEnt               - The directory entry to be closed.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS          - The directory entry is successfully opened.\r
+  Other                - An error occurred when opening the directory entry.\r
+  \r
+--*/\r
+{\r
+  FAT_OFILE   *OFile;\r
+  FAT_VOLUME  *Volume;\r
+\r
+  OFile   = DirEnt->OFile;\r
+  Volume  = OFile->Volume;\r
+  ASSERT (OFile != NULL);\r
+\r
+  if (OFile->ODir != NULL) {\r
+    FatDiscardODir (OFile);\r
+  }\r
+\r
+  if (OFile->Parent == NULL) {\r
+    Volume->Root = NULL;\r
+  } else {\r
+    RemoveEntryList (&OFile->ChildLink);\r
+  }\r
+\r
+  gBS->FreePool (OFile);\r
+  DirEnt->OFile = NULL;\r
+  if (DirEnt->Invalid == TRUE) {\r
+    //\r
+    // Free directory entry itself\r
+    //\r
+    FatFreeDirEnt (DirEnt);\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+FatLocateOFile (\r
+  IN OUT FAT_OFILE        **PtrOFile,\r
+  IN     CHAR16           *FileName,\r
+  IN     UINT8            Attributes,\r
+     OUT CHAR16           *NewFileName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Traverse filename and open all OFiles that can be opened.\r
+  Update filename pointer to the component that can't be opened.\r
+  If more than one name component remains, returns an error;\r
+  otherwise, return the remaining name component so that the caller might choose to create it.\r
+\r
+Arguments:\r
+  PtrOFile              - As input, the reference OFile; as output, the located OFile.\r
+  FileName              - The file name relevant to the OFile.\r
+  Attributes            - The attribute of the destination OFile.\r
+  NewFileName           - The remaining file name.\r
+\r
+Returns:\r
+\r
+  EFI_NOT_FOUND         - The file name can't be opened and there is more than one \r
+                          components within the name left (this means the name can\r
+                          not be created either).\r
+  EFI_INVALID_PARAMETER - The parameter is not valid.\r
+  EFI_SUCCESS           - Open the file successfully.\r
+  other                 - An error occured when locating the OFile.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  FAT_VOLUME  *Volume;\r
+  CHAR16      ComponentName[EFI_FILE_STRING_LENGTH + 1];\r
+  UINTN       FileNameLen;\r
+  BOOLEAN     DirIntended;\r
+  CHAR16      *Next;\r
+  FAT_OFILE   *OFile;\r
+  FAT_DIRENT  *DirEnt;\r
+\r
+  DirEnt = NULL;\r
+  FileNameLen = EfiStrLen (FileName);\r
+  if (FileNameLen == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OFile       = *PtrOFile;\r
+  Volume      = OFile->Volume;\r
+\r
+  DirIntended = FALSE;\r
+  if (FileName[FileNameLen - 1] == PATH_NAME_SEPARATOR) {\r
+    DirIntended = TRUE;\r
+  }\r
+  //\r
+  // If name starts with path name separator, then move to root OFile\r
+  //\r
+  if (*FileName == PATH_NAME_SEPARATOR) {\r
+    OFile = Volume->Root;\r
+    FileName++;\r
+    FileNameLen--;\r
+  }\r
+  if (OFile->FullPathLen + FileNameLen > EFI_FILE_STRING_LENGTH) {\r
+    //\r
+    // Full path length can not surpass 256 \r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Start at current location\r
+  //\r
+  Next = FileName;\r
+  for (;;) {\r
+    //\r
+    // Get the next component name\r
+    //\r
+    FileName = Next;\r
+    Next     = FatGetNextNameComponent (FileName, ComponentName);\r
+\r
+    //\r
+    // If end of the file name, we're done\r
+    //\r
+    if (ComponentName[0] == 0) {\r
+      if (DirIntended && OFile->ODir == NULL) {\r
+        return EFI_NOT_FOUND;\r
+      }\r
+\r
+      NewFileName[0] = 0;\r
+      break;\r
+    }\r
+    //\r
+    // If "dot", then current\r
+    //\r
+    if (EfiStrCmp (ComponentName, L".") == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // If "dot dot", then parent\r
+    //\r
+    if (EfiStrCmp (ComponentName, L"..") == 0) {\r
+      if (OFile->Parent == NULL) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+      OFile = OFile->Parent;\r
+      continue;\r
+    }\r
+\r
+    if (!FatFileNameIsValid (ComponentName, NewFileName)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // We have a component name, try to open it\r
+    //\r
+    if (OFile->ODir == NULL) {\r
+      //\r
+      // This file isn't a directory, can't open it\r
+      //\r
+      return EFI_NOT_FOUND;\r
+    }\r
+    //\r
+    // Search the compName in the directory\r
+    //\r
+    Status = FatSearchODir (OFile, NewFileName, &DirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (DirEnt == NULL) {\r
+      //\r
+      // component name is not found in the directory\r
+      //\r
+      if (*Next != 0) {\r
+        return EFI_NOT_FOUND;\r
+      }\r
+\r
+      if (DirIntended && (Attributes & FAT_ATTRIBUTE_DIRECTORY) == 0) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+      //\r
+      // It's the last component name - return with the open\r
+      // path and the remaining name\r
+      //\r
+      break;\r
+    }\r
+\r
+    Status = FatOpenDirEnt (OFile, DirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    OFile = DirEnt->OFile;\r
+  }\r
+\r
+  *PtrOFile = OFile;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/EnhancedFat/Dxe/DiskCache.c b/EnhancedFat/Dxe/DiskCache.c
new file mode 100644 (file)
index 0000000..3ef47ba
--- /dev/null
@@ -0,0 +1,566 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  DiskCache.c\r
+    \r
+Abstract:\r
+\r
+  Cache implementation for EFI FAT File system driver\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+STATIC\r
+VOID\r
+FatFlushDataCacheRange (\r
+  IN  FAT_VOLUME         *Volume,\r
+  IN  IO_MODE            IoMode,\r
+  IN  UINTN              StartPageNo,\r
+  IN  UINTN              EndPageNo,\r
+  OUT UINT8              *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  This function is used by the Data Cache.\r
+  \r
+  When this function is called by write command, all entries in this range \r
+  are older than the contents in disk, so they are invalid; just mark them invalid.\r
+  \r
+  When this function is called by read command, if any entry in this range\r
+  is dirty, it means that the relative info directly readed from media is older than\r
+  than the info in the cache; So need to update the relative info in the Buffer.\r
+  \r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  IoMode                - This function is called by read command or write command\r
+  StartPageNo           - First PageNo to be checked in the cache.\r
+  EndPageNo             - Last PageNo to be checked in the cache.\r
+  Buffer                - The user buffer need to update. Only when doing the read command \r
+                          and there is dirty cache in the cache range, this parameter will be used.\r
+\r
+Returns: \r
+\r
+  None.\r
+\r
+--*/\r
+{\r
+  UINTN       PageNo;\r
+  UINTN       GroupNo;\r
+  UINTN       GroupMask;\r
+  UINTN       PageSize;\r
+  UINT8       PageAlignment;\r
+  DISK_CACHE  *DiskCache;\r
+  CACHE_TAG   *CacheTag;\r
+  UINT8       *BaseAddress;\r
+  EFI_TPL     EntryTpl;\r
+\r
+  DiskCache     = &Volume->DiskCache[CACHE_DATA];\r
+  BaseAddress   = DiskCache->CacheBase;\r
+  GroupMask     = DiskCache->GroupMask;\r
+  PageAlignment = DiskCache->PageAlignment;\r
+  PageSize      = 1 << PageAlignment;\r
+  //\r
+  // Make Cache Update a critical section\r
+  //\r
+  EntryTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);\r
+\r
+  for (PageNo = StartPageNo; PageNo < EndPageNo; PageNo++) {\r
+    GroupNo   = PageNo & GroupMask;\r
+    CacheTag  = &DiskCache->CacheTag[GroupNo];\r
+    if (CacheTag->RealSize > 0 && CacheTag->PageNo == PageNo) {\r
+      //\r
+      // When reading data form disk directly, if some dirty data\r
+      // in cache is in this rang, this data in the Buffer need to\r
+      // be updated with the cache's dirty data.\r
+      //\r
+      if (IoMode == READ_DISK) {\r
+        if (CacheTag->Dirty) {\r
+          EfiCopyMem (\r
+            Buffer + ((PageNo - StartPageNo) << PageAlignment),\r
+            BaseAddress + (GroupNo << PageAlignment),\r
+            PageSize\r
+            );\r
+        }\r
+      } else {\r
+        //\r
+        // Make all valid entries in this range invalid.\r
+        //\r
+        CacheTag->RealSize = 0;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // Exit Cache Update critical section\r
+  //\r
+  gBS->RestoreTPL (EntryTpl);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatExchangeCachePage (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN CACHE_DATA_TYPE    DataType,\r
+  IN IO_MODE            IoMode,\r
+  IN CACHE_TAG          *CacheTag\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Exchange the cache page with the image on the disk\r
+  \r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  DataType              - Indicate the cache type.\r
+  IoMode                - Indicate whether to load this page from disk or store this page to disk.\r
+  CacheTag              - The Cache Tag for the current cache page.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - Cache page exchanged successfully.\r
+  Others                - An error occurred when exchanging cache page.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       GroupNo;\r
+  UINTN       PageNo;\r
+  UINTN       WriteCount;\r
+  UINTN       RealSize;\r
+  UINT64      EntryPos;\r
+  UINT64      MaxSize;\r
+  DISK_CACHE  *DiskCache;\r
+  VOID        *PageAddress;\r
+  UINT8       PageAlignment;\r
+\r
+  DiskCache     = &Volume->DiskCache[DataType];\r
+  PageNo        = CacheTag->PageNo;\r
+  GroupNo       = PageNo & DiskCache->GroupMask;\r
+  PageAlignment = DiskCache->PageAlignment;\r
+  PageAddress   = DiskCache->CacheBase + (GroupNo << PageAlignment);\r
+  EntryPos      = DiskCache->BaseAddress + LShiftU64 (PageNo, PageAlignment);\r
+  RealSize      = CacheTag->RealSize;\r
+  if (IoMode == READ_DISK) {\r
+    RealSize  = 1 << PageAlignment;\r
+    MaxSize   = DiskCache->LimitAddress - EntryPos;\r
+    if (MaxSize < RealSize) {\r
+      DEBUG ((EFI_D_INFO, "FatDiskIo: Cache Page OutBound occurred! \n"));\r
+      RealSize = (UINTN) MaxSize;\r
+    }\r
+  }\r
+\r
+  WriteCount = 1;\r
+  if (DataType == CACHE_FAT && IoMode == WRITE_DISK) {\r
+    WriteCount = Volume->NumFats;\r
+  }\r
+\r
+  do {\r
+    //\r
+    // Only fat table writing will execute more than once\r
+    //\r
+    Status = FatDiskIo (Volume, IoMode, EntryPos, RealSize, PageAddress);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    EntryPos += Volume->FatSize;\r
+  } while (--WriteCount > 0);\r
+\r
+  CacheTag->Dirty     = FALSE;\r
+  CacheTag->RealSize  = RealSize;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatGetCachePage (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN CACHE_DATA_TYPE    CacheDataType,\r
+  IN UINTN              PageNo,\r
+  IN CACHE_TAG          *CacheTag\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get one cache page by specified PageNo.\r
+  \r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  CacheDataType         - The cache type: CACHE_FAT or CACHE_DATA.\r
+  PageNo                - PageNo to match with the cache.\r
+  CacheTag              - The Cache Tag for the current cache page.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - Get the cache page successfully.\r
+  other                 - An error occurred when accessing data.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       OldPageNo;\r
+  EFI_TPL     EntryTpl;\r
+\r
+  OldPageNo = CacheTag->PageNo;\r
+  if (CacheTag->RealSize > 0 && OldPageNo == PageNo) {\r
+    //\r
+    // Cache Hit occurred\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Make Cache Update a critical section\r
+  //\r
+  EntryTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);\r
+\r
+  //\r
+  // Write dirty cache page back to disk\r
+  //\r
+  if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
+    Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+  }\r
+  //\r
+  // Load new data from disk;\r
+  //\r
+  CacheTag->PageNo  = PageNo;\r
+  Status            = FatExchangeCachePage (Volume, CacheDataType, READ_DISK, CacheTag);\r
+\r
+Done:\r
+  //\r
+  // Exit Cache Update critical section\r
+  //\r
+  gBS->RestoreTPL (EntryTpl);\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatAccessUnalignedCachePage (\r
+  IN     FAT_VOLUME        *Volume,\r
+  IN     CACHE_DATA_TYPE   CacheDataType,\r
+  IN     IO_MODE           IoMode,\r
+  IN     UINTN             PageNo,\r
+  IN     UINTN             Offset,\r
+  IN     UINTN             Length,\r
+  IN OUT VOID              *Buffer\r
+  )\r
+/*++\r
+Routine Description:\r
+\r
+  Read Length bytes from the position of Offset into Buffer, or\r
+  write Length bytes from Buffer into the position of Offset.\r
+\r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  CacheDataType         - The type of cache: CACHE_DATA or CACHE_FAT.\r
+  IoMode                - Indicate the type of disk access.\r
+  PageNo                - The number of unaligned cache page.\r
+  Offset                - The starting byte of cache page.\r
+  Length                - The number of bytes that is read or written\r
+  Buffer                - Buffer containing cache data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The data was accessed correctly.\r
+  Others                - An error occurred when accessing unaligned cache page.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  VOID        *Source;\r
+  VOID        *Destination;\r
+  DISK_CACHE  *DiskCache;\r
+  CACHE_TAG   *CacheTag;\r
+  UINTN       GroupNo;\r
+\r
+  DiskCache = &Volume->DiskCache[CacheDataType];\r
+  GroupNo   = PageNo & DiskCache->GroupMask;\r
+  CacheTag  = &DiskCache->CacheTag[GroupNo];\r
+  Status    = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag);\r
+  if (!EFI_ERROR (Status)) {\r
+    Source      = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset;\r
+    Destination = Buffer;\r
+    if (IoMode != READ_DISK) {\r
+      CacheTag->Dirty   = TRUE;\r
+      DiskCache->Dirty  = TRUE;\r
+      Destination       = Source;\r
+      Source            = Buffer;\r
+    }\r
+\r
+    EfiCopyMem (Destination, Source, Length);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatAccessCache (\r
+  IN     FAT_VOLUME         *Volume,\r
+  IN     CACHE_DATA_TYPE    CacheDataType,\r
+  IN     IO_MODE            IoMode,\r
+  IN     UINT64             Offset,\r
+  IN     UINTN              BufferSize,\r
+  IN OUT UINT8              *Buffer\r
+  )\r
+/*++\r
+Routine Description:\r
+\r
+  Read BufferSize bytes from the position of Offset into Buffer, \r
+  or write BufferSize bytes from Buffer into the position of Offset.\r
+\r
+  Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into \r
+  the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):\r
+  \r
+  1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache \r
+     page hit, just return the cache page; else update the related cache page and return \r
+     the right cache page.\r
+  2. Access of Data cache (CACHE_DATA):\r
+     The access data will be divided into UnderRun data, Aligned data and OverRun data;\r
+     The UnderRun data and OverRun data will be accessed by the Data cache, \r
+     but the Aligned data will be accessed with disk directly.\r
+\r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  CacheDataType         - The type of cache: CACHE_DATA or CACHE_FAT.\r
+  IoMode                - Indicate the type of disk access.\r
+  Offset                - The starting byte offset to read from.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing cache data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The data was accessed correctly.\r
+  EFI_MEDIA_CHANGED     - The MediaId does not match the current device.\r
+  Others                - An error occurred when accessing cache.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       PageSize;\r
+  UINTN       UnderRun;\r
+  UINTN       OverRun;\r
+  UINTN       AlignedSize;\r
+  UINTN       Length;\r
+  UINTN       PageNo;\r
+  UINTN       AlignedPageCount;\r
+  UINTN       OverRunPageNo;\r
+  DISK_CACHE  *DiskCache;\r
+  UINT64      EntryPos;\r
+  UINT8       PageAlignment;\r
+\r
+  ASSERT (Volume->CacheBuffer != NULL);\r
+\r
+  Status        = EFI_SUCCESS;\r
+  DiskCache     = &Volume->DiskCache[CacheDataType];\r
+  EntryPos      = Offset - DiskCache->BaseAddress;\r
+  PageAlignment = DiskCache->PageAlignment;\r
+  PageSize      = 1 << PageAlignment;\r
+  PageNo        = (UINTN) RShiftU64 (EntryPos, PageAlignment);\r
+  UnderRun      = ((UINTN) EntryPos) & (PageSize - 1);\r
+\r
+  if (UnderRun > 0) {\r
+    Length = PageSize - UnderRun;\r
+    if (Length > BufferSize) {\r
+      Length = BufferSize;\r
+    }\r
+\r
+    Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Buffer     += Length;\r
+    BufferSize -= Length;\r
+    PageNo++;\r
+  }\r
+\r
+  AlignedPageCount  = BufferSize >> PageAlignment;\r
+  OverRunPageNo     = PageNo + AlignedPageCount;\r
+  //\r
+  // The access of the Aligned data\r
+  //\r
+  if (AlignedPageCount > 0) {\r
+    //\r
+    // Accessing fat table cannot have alignment data\r
+    //\r
+    ASSERT (CacheDataType == CACHE_DATA);\r
+\r
+    EntryPos    = Volume->RootPos + LShiftU64 (PageNo, PageAlignment);\r
+    AlignedSize = AlignedPageCount << PageAlignment;\r
+    Status      = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // If these access data over laps the relative cache range, these cache pages need\r
+    // to be updated.\r
+    //\r
+    FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer);\r
+    Buffer      += AlignedSize;\r
+    BufferSize  -= AlignedSize;\r
+  }\r
+  //\r
+  // The access of the OverRun data\r
+  //\r
+  OverRun = BufferSize;\r
+  if (OverRun > 0) {\r
+    //\r
+    // Last read is not a complete page\r
+    //\r
+    Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatVolumeFlushCache (\r
+  IN FAT_VOLUME         *Volume\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+   \r
+  Flush all the dirty cache back, include the FAT cache and the Data cache.\r
+     \r
+Arguments:\r
+  \r
+  Volume                - FAT file system volume.\r
+\r
+Returns:\r
+  \r
+  EFI_SUCCESS           - Flush all the dirty cache back successfully\r
+  other                 - An error occurred when writing the data into the disk\r
+    \r
+--*/\r
+{\r
+  EFI_STATUS      Status;\r
+  CACHE_DATA_TYPE CacheDataType;\r
+  UINTN           GroupIndex;\r
+  UINTN           GroupMask;\r
+  DISK_CACHE      *DiskCache;\r
+  CACHE_TAG       *CacheTag;\r
+  EFI_TPL         EntryTpl;\r
+\r
+  Status = EFI_SUCCESS;\r
+  //\r
+  // Make Cache Update a critical section\r
+  //\r
+  EntryTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);\r
+\r
+  for (CacheDataType = 0; CacheDataType < CACHE_MAX_TYPE; CacheDataType++) {\r
+    DiskCache = &Volume->DiskCache[CacheDataType];\r
+    if (DiskCache->Dirty) {\r
+      //\r
+      // Data cache or fat cache is dirty, write the dirty data back\r
+      //\r
+      GroupMask = DiskCache->GroupMask;\r
+      for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) {\r
+        CacheTag = &DiskCache->CacheTag[GroupIndex];\r
+        if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
+          //\r
+          // Write back all Dirty Data Cache Page to disk\r
+          //\r
+          Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag);\r
+          if (EFI_ERROR (Status)) {\r
+            goto Done;\r
+          }\r
+        }\r
+      }\r
+\r
+      DiskCache->Dirty = FALSE;\r
+    }\r
+  }\r
+\r
+Done:\r
+  //\r
+  // Exit Cache Update critical section\r
+  //\r
+  gBS->RestoreTPL (EntryTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatInitializeDiskCache (\r
+  IN FAT_VOLUME         *Volume\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+   \r
+  Initialize the disk cache according to Volume's FatType.\r
+     \r
+Arguments:\r
+  \r
+  Volume                - FAT file system volume.\r
+\r
+Returns:\r
+  \r
+  EFI_SUCCESS           - The disk cache is successfully initialized.\r
+  EFI_OUT_OF_RESOURCES  - Not enough memory to allocate disk cache.\r
+    \r
+--*/\r
+{\r
+  DISK_CACHE  *DiskCache;\r
+  UINTN       FatCacheGroupCount;\r
+  UINTN       DataCacheSize;\r
+  UINTN       FatCacheSize;\r
+  UINT8       *CacheBuffer;\r
+\r
+  DiskCache = Volume->DiskCache;\r
+  //\r
+  // Configure the parameters of disk cache\r
+  //\r
+  if (Volume->FatType == FAT12) {\r
+    FatCacheGroupCount                  = FAT_FATCACHE_GROUP_MIN_COUNT;\r
+    DiskCache[CACHE_FAT].PageAlignment  = FAT_FATCACHE_PAGE_MIN_ALIGNMENT;\r
+    DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT;\r
+  } else {\r
+    FatCacheGroupCount                  = FAT_FATCACHE_GROUP_MAX_COUNT;\r
+    DiskCache[CACHE_FAT].PageAlignment  = FAT_FATCACHE_PAGE_MAX_ALIGNMENT;\r
+    DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT;\r
+  }\r
+\r
+  DiskCache[CACHE_DATA].GroupMask     = FAT_DATACACHE_GROUP_COUNT - 1;\r
+  DiskCache[CACHE_DATA].BaseAddress   = Volume->RootPos;\r
+  DiskCache[CACHE_DATA].LimitAddress  = Volume->VolumeSize;\r
+  DiskCache[CACHE_FAT].GroupMask      = FatCacheGroupCount - 1;\r
+  DiskCache[CACHE_FAT].BaseAddress    = Volume->FatPos;\r
+  DiskCache[CACHE_FAT].LimitAddress   = Volume->FatPos + Volume->FatSize;\r
+  FatCacheSize                        = FatCacheGroupCount << DiskCache[CACHE_FAT].PageAlignment;\r
+  DataCacheSize                       = FAT_DATACACHE_GROUP_COUNT << DiskCache[CACHE_DATA].PageAlignment;\r
+  //\r
+  // Allocate the Fat Cache buffer\r
+  //\r
+  CacheBuffer = EfiLibAllocatePool (FatCacheSize + DataCacheSize);\r
+  if (CacheBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Volume->CacheBuffer             = CacheBuffer;\r
+  DiskCache[CACHE_FAT].CacheBase  = CacheBuffer;\r
+  DiskCache[CACHE_DATA].CacheBase = CacheBuffer + FatCacheSize;\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/EnhancedFat/Dxe/Fat.c b/EnhancedFat/Dxe/Fat.c
new file mode 100644 (file)
index 0000000..4b7a8a6
--- /dev/null
@@ -0,0 +1,457 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  Fat.c\r
+  \r
+Abstract:\r
+\r
+  Fat File System driver routines that support EFI driver model\r
+  \r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatEntryPoint (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatUnload (\r
+  IN EFI_HANDLE         ImageHandle\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN  EFI_HANDLE                   Controller,\r
+  IN  UINTN                        NumberOfChildren,\r
+  IN  EFI_HANDLE                   *ChildHandleBuffer\r
+  );\r
+\r
+//\r
+// DriverBinding protocol instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gFatDriverBinding = {\r
+  FatDriverBindingSupported,\r
+  FatDriverBindingStart,\r
+  FatDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+#ifndef EDK_RELEASE_VERSION\r
+\r
+EFI_DRIVER_ENTRY_POINT (FatEntryPoint)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatEntryPoint (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Register Driver Binding protocol for this driver.\r
+  \r
+Arguments:\r
\r
+  ImageHandle           - Handle for the image of this driver.\r
+  SystemTable           - Pointer to the EFI System Table.\r
+\r
+Returns: \r
\r
+  EFI_SUCCESS           - Driver loaded.\r
+  other                 - Driver not loaded.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+\r
+  //\r
+  // Initialize the EFI Driver Library\r
+  //\r
+  Status = EfiLibInstallAllDriverProtocols (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gFatDriverBinding,\r
+             ImageHandle,\r
+             &gFatComponentName,\r
+             NULL,\r
+             NULL\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Fill in the Unload() function\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ImageHandle,\r
+                  &gEfiLoadedImageProtocolGuid,\r
+                  (VOID **) &LoadedImage,\r
+                  ImageHandle,\r
+                  ImageHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    LoadedImage->Unload = FatUnload;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+#endif\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatUnload (\r
+  IN EFI_HANDLE  ImageHandle\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Unload function for this image. Uninstall DriverBinding protocol.\r
+  \r
+Arguments:\r
\r
+  ImageHandle           - Handle for the image of this driver.\r
+\r
+Returns: \r
\r
+  EFI_SUCCESS           - Driver unloaded successfully.\r
+  other                 - Driver can not unloaded.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_HANDLE  *DeviceHandleBuffer;\r
+  UINTN       DeviceHandleCount;\r
+  UINTN       Index;\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  AllHandles,\r
+                  NULL,\r
+                  NULL,\r
+                  &DeviceHandleCount,\r
+                  &DeviceHandleBuffer\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    for (Index = 0; Index < DeviceHandleCount; Index++) {\r
+      Status = gBS->DisconnectController (\r
+                      DeviceHandleBuffer[Index],\r
+                      ImageHandle,\r
+                      NULL\r
+                      );\r
+    }\r
+\r
+    if (DeviceHandleBuffer != NULL) {\r
+      gBS->FreePool (DeviceHandleBuffer);\r
+    }\r
+  }\r
+\r
+  Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                  ImageHandle,\r
+                  &gEfiDriverBindingProtocolGuid,\r
+                  &gFatDriverBinding,\r
+                  &gEfiComponentNameProtocolGuid,\r
+                  &gFatComponentName,\r
+                  NULL\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Test to see if this driver can add a file system to ControllerHandle.\r
+  ControllerHandle must support both Disk IO and Block IO protocols.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  ControllerHandle      - Handle of device to test.\r
+  RemainingDevicePath   - Not used.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - This driver supports this device.\r
+  EFI_ALREADY_STARTED   - This driver is already running on this device.\r
+  other                 - This driver does not support this device.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_DISK_IO_PROTOCOL  *DiskIo;\r
+\r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDiskIoProtocolGuid,\r
+                  (VOID **) &DiskIo,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Close the I/O Abstraction(s) used to perform the supported test\r
+  //\r
+  gBS->CloseProtocol (\r
+         ControllerHandle,\r
+         &gEfiDiskIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         ControllerHandle\r
+         );\r
+\r
+  //\r
+  // Open the IO Abstraction(s) needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  NULL,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
+  IN EFI_HANDLE                   ControllerHandle,\r
+  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
+  )\r
+/*++\r
+\r
+Routine Description:      \r
+\r
+  Start this driver on ControllerHandle by opening a Block IO and Disk IO \r
+  protocol, reading Device Path. Add a Simple File System protocol to\r
+  ControllerHandle if the media contains a valid file system.\r
+\r
+Arguments:\r
+\r
+  This                  - Protocol instance pointer.\r
+  ControllerHandle      - Handle of device to bind driver to.\r
+  RemainingDevicePath   - Not used.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - This driver is added to DeviceHandle.\r
+  EFI_ALREADY_STARTED   - This driver is already running on DeviceHandle.\r
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory.\r
+  other                 - This driver does not support this device.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+  EFI_DISK_IO_PROTOCOL  *DiskIo;\r
+  LC_ISO_639_2          *LangCode;\r
+  LC_ISO_639_2          LangCodeBuffer[MAX_LANG_CODE_SIZE];\r
+  UINTN                 Size;\r
+\r
+  //\r
+  // Initialize unicode support\r
+  //\r
+  Size      = sizeof (LangCodeBuffer);\r
+  LangCode  = LangCodeBuffer;\r
+  //\r
+  // Find current LangCode from Lang NV Variable\r
+  //\r
+  Status = gRT->GetVariable (\r
+                  L"Lang",\r
+                  &gEfiGlobalVariableGuid,\r
+                  NULL,\r
+                  &Size,\r
+                  LangCode\r
+                  );\r
+\r
+  ASSERT (Status != EFI_BUFFER_TOO_SMALL);\r
+  //\r
+  // If cannot get language code from Lang Variable,\r
+  // set language code to the default language English.\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    LangCode = "eng";\r
+    DEBUG ((EFI_D_ERROR, "Failed to get language code, so use the default!\n"));\r
+  }\r
+\r
+  Status = FatInitUnicodeCollationSupport (\r
+             This,\r
+             LangCode,\r
+             &gUnicodeCollationInterface\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Make sure gUnicodeCollationInterface is properly installed\r
+  //\r
+  ASSERT (gUnicodeCollationInterface != NULL);\r
+  //\r
+  // Open our required BlockIo and DiskIo\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  (VOID **) &BlockIo,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDiskIoProtocolGuid,\r
+                  (VOID **) &DiskIo,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Allocate Volume structure. In FatAllocateVolume(), Resources\r
+  // are allocated with protocol installed and cached initialized\r
+  //\r
+  Status = FatAllocateVolume (ControllerHandle, DiskIo, BlockIo);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->OpenProtocol (\r
+                    ControllerHandle,\r
+                    &gEfiSimpleFileSystemProtocolGuid,\r
+                    NULL,\r
+                    This->DriverBindingHandle,\r
+                    ControllerHandle,\r
+                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->CloseProtocol (\r
+             ControllerHandle,\r
+             &gEfiDiskIoProtocolGuid,\r
+             This->DriverBindingHandle,\r
+             ControllerHandle\r
+             );\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN  EFI_HANDLE                    ControllerHandle,\r
+  IN  UINTN                         NumberOfChildren,\r
+  IN  EFI_HANDLE                    *ChildHandleBuffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Stop this driver on ControllerHandle. \r
+\r
+Arguments:\r
+  This                  - Protocol instance pointer.\r
+  ControllerHandle      - Handle of device to stop driver on.\r
+  NumberOfChildren      - Not used.\r
+  ChildHandleBuffer     - Not used.\r
+\r
+Returns:\r
+  EFI_SUCCESS           - This driver is removed DeviceHandle.\r
+  other                 - This driver was not removed from this device.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;\r
+  FAT_VOLUME                      *Volume;\r
+\r
+  //\r
+  // Get our context back\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiSimpleFileSystemProtocolGuid,\r
+                  (VOID **) &FileSystem,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Volume = VOLUME_FROM_VOL_INTERFACE (FileSystem);\r
+    Status = FatAbandonVolume (Volume);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  Status = gBS->CloseProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDiskIoProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle\r
+                  );\r
+\r
+  return Status;\r
+}\r
diff --git a/EnhancedFat/Dxe/Fat.h b/EnhancedFat/Dxe/Fat.h
new file mode 100644 (file)
index 0000000..d17ca21
--- /dev/null
@@ -0,0 +1,1120 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  Fat.h\r
+\r
+Abstract:\r
+\r
+  Main header file for EFI FAT file system driver\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#ifndef _FAT_H_\r
+#define _FAT_H_\r
+\r
+//\r
+// Map R8.5 names to R9.0 names\r
+//\r
+#define EFI_LIST_ENTRY            LIST_ENTRY\r
+#define EfiCopyMem                CopyMem\r
+#define EfiStrSize                StrSize\r
+#define EfiCompareMem             CompareMem\r
+#define EfiZeroMem                ZeroMem\r
+#define EfiSetMem                 SetMem\r
+#define EfiStrCpy                 StrCpy\r
+#define EfiStrCmp                 StrCmp\r
+#define EfiStrLen                 StrLen\r
+#define EfiStrCat                 StrCat\r
+#define EfiSetMem                 SetMem\r
+#define EfiCompareGuid            CompareGuid\r
+#define EfiLibAllocatePool        AllocatePool\r
+#define EfiLibAllocateZeroPool    AllocateZeroPool\r
+#define EfiLibAllocateCopyPool    AllocateCopyPool\r
+#define Log2                      (UINT8)HighBitSet64\r
+#define EfiLibLookupUnicodeString LookupUnicodeString\r
+\r
+\r
+#include "FatFileSystem.h"\r
+\r
+//\r
+// The FAT signature\r
+//\r
+#define FAT_VOLUME_SIGNATURE         EFI_SIGNATURE_32 ('f', 'a', 't', 'v')\r
+#define FAT_IFILE_SIGNATURE          EFI_SIGNATURE_32 ('f', 'a', 't', 'i')\r
+#define FAT_ODIR_SIGNATURE           EFI_SIGNATURE_32 ('f', 'a', 't', 'd')\r
+#define FAT_DIRENT_SIGNATURE         EFI_SIGNATURE_32 ('f', 'a', 't', 'e')\r
+#define FAT_OFILE_SIGNATURE          EFI_SIGNATURE_32 ('f', 'a', 't', 'o')\r
+\r
+#define ASSERT_VOLUME_LOCKED(a)      ASSERT_LOCKED (&FatFsLock)\r
+\r
+#define IFILE_FROM_FHAND(a)          CR (a, FAT_IFILE, Handle, FAT_IFILE_SIGNATURE)\r
+\r
+#define DIRENT_FROM_LINK(a)          CR (a, FAT_DIRENT, Link, FAT_DIRENT_SIGNATURE)\r
+\r
+#define VOLUME_FROM_ROOT_DIRENT(a)   CR (a, FAT_VOLUME, RootDirEnt, FAT_VOLUME_SIGNATURE)\r
+\r
+#define VOLUME_FROM_VOL_INTERFACE(a) CR (a, FAT_VOLUME, VolumeInterface, FAT_VOLUME_SIGNATURE);\r
+\r
+#define ODIR_FROM_DIRCACHELINK(a)    CR (a, FAT_ODIR, DirCacheLink, FAT_ODIR_SIGNATURE)\r
+\r
+#define OFILE_FROM_CHECKLINK(a)      CR (a, FAT_OFILE, CheckLink, FAT_OFILE_SIGNATURE)\r
+\r
+#define OFILE_FROM_CHILDLINK(a)      CR (a, FAT_OFILE, ChildLink, FAT_OFILE_SIGNATURE)\r
+\r
+//\r
+// Minimum sector size is 512B, Maximum sector size is 4096B\r
+// Max sectors per cluster is 128\r
+//\r
+#define MAX_BLOCK_ALIGNMENT               12\r
+#define MIN_BLOCK_ALIGNMENT               9\r
+#define MAX_SECTORS_PER_CLUSTER_ALIGNMENT 7\r
+\r
+//\r
+// Efi Time Definition\r
+//\r
+#define IS_LEAP_YEAR(a)                   (((a) % 4 == 0) && (((a) % 100 != 0) || ((a) % 400 == 0)))\r
+\r
+//\r
+// Minimum fat page size is 8K, maximum fat page alignment is 32K\r
+// Minimum data page size is 8K, maximum fat page alignment is 64K\r
+//\r
+#define FAT_FATCACHE_PAGE_MIN_ALIGNMENT   13\r
+#define FAT_FATCACHE_PAGE_MAX_ALIGNMENT   15\r
+#define FAT_DATACACHE_PAGE_MIN_ALIGNMENT  13\r
+#define FAT_DATACACHE_PAGE_MAX_ALIGNMENT  16\r
+#define FAT_DATACACHE_GROUP_COUNT         64\r
+#define FAT_FATCACHE_GROUP_MIN_COUNT      1\r
+#define FAT_FATCACHE_GROUP_MAX_COUNT      16\r
+\r
+//\r
+// Used in 8.3 generation algorithm\r
+//\r
+#define MAX_SPEC_RETRY          4\r
+#define SPEC_BASE_TAG_LEN       6\r
+#define HASH_BASE_TAG_LEN       2\r
+#define HASH_VALUE_TAG_LEN      (SPEC_BASE_TAG_LEN - HASH_BASE_TAG_LEN)\r
+\r
+//\r
+// Path name separator is back slash\r
+//\r
+#define PATH_NAME_SEPARATOR     L'\\'\r
+\r
+\r
+#define EFI_FILE_STRING_LENGTH  256\r
+#define FAT_MAX_ALLOCATE_SIZE   0xA00000\r
+#define LC_ISO_639_2_ENTRY_SIZE 3\r
+#define MAX_LANG_CODE_SIZE      100\r
+\r
+#define FAT_MAX_DIR_CACHE_COUNT 8\r
+#define FAT_MAX_DIRENTRY_COUNT  0xFFFF\r
+typedef CHAR8                   LC_ISO_639_2;\r
+\r
+//\r
+// The fat types we support\r
+//\r
+typedef enum {\r
+  FAT12,\r
+  FAT16,\r
+  FAT32,\r
+  FatUndefined\r
+} FAT_VOLUME_TYPE;\r
+\r
+typedef enum {\r
+  CACHE_FAT,\r
+  CACHE_DATA,\r
+  CACHE_MAX_TYPE\r
+} CACHE_DATA_TYPE;\r
+\r
+//\r
+// Used in FatDiskIo\r
+//\r
+typedef enum {\r
+  READ_DISK     = 0,  // raw disk read\r
+  WRITE_DISK    = 1,  // raw disk write\r
+  READ_FAT      = 2,  // read fat cache\r
+  WRITE_FAT     = 3,  // write fat cache\r
+  READ_DATA     = 6,  // read data cache\r
+  WRITE_DATA    = 7   // write data cache\r
+} IO_MODE;\r
+\r
+#define CACHE_ENABLED(a)  ((a) >= 2)\r
+#define RAW_ACCESS(a)     ((a) &  0x1)\r
+#define CACHE_TYPE(a)     ((CACHE_DATA_TYPE)((a) >> 2))\r
+\r
+//\r
+// Disk cache tag\r
+//\r
+typedef struct {\r
+  UINTN   PageNo;\r
+  UINTN   RealSize;\r
+  BOOLEAN Dirty;\r
+} CACHE_TAG;\r
+\r
+typedef struct {\r
+  UINT64    BaseAddress;\r
+  UINT64    LimitAddress;\r
+  UINT8     *CacheBase;\r
+  BOOLEAN   Dirty;\r
+  UINT8     PageAlignment;\r
+  UINTN     GroupMask;\r
+  CACHE_TAG CacheTag[FAT_DATACACHE_GROUP_COUNT];\r
+} DISK_CACHE;\r
+\r
+//\r
+// Hash table size\r
+//\r
+#define HASH_TABLE_SIZE  0x400\r
+#define HASH_TABLE_MASK  (HASH_TABLE_SIZE - 1)\r
+\r
+//\r
+// The directory entry for opened directory\r
+//\r
+typedef struct _FAT_DIRENT {\r
+  UINTN               Signature;\r
+  UINT16              EntryPos;               // The position of this directory entry in the parent directory file\r
+  UINT8               EntryCount;             // The count of the directory entry in the parent directory file\r
+  BOOLEAN             Invalid;                // Indicate whether this directory entry is valid\r
+  CHAR16              *FileString;            // The unicode long file name for this directory entry\r
+  struct _FAT_OFILE   *OFile;                 // The OFile of the corresponding directory entry\r
+  struct _FAT_DIRENT  *ShortNameForwardLink;  // Hash successor link for short filename\r
+  struct _FAT_DIRENT  *LongNameForwardLink;   // Hash successor link for long filename\r
+  EFI_LIST_ENTRY      Link;                   // Connection of every directory entry\r
+  FAT_DIRECTORY_ENTRY Entry;                  // The physical directory entry stored in disk\r
+} FAT_DIRENT;\r
+\r
+typedef struct _FAT_ODIR {\r
+  UINTN               Signature;\r
+  UINT32              CurrentEndPos;          // Current end position of the directory\r
+  UINT32              CurrentPos;             // Current position of the directory\r
+  EFI_LIST_ENTRY      *CurrentCursor;         // Current directory entry pointer\r
+  EFI_LIST_ENTRY      ChildList;              // List of all directory entries\r
+  BOOLEAN             EndOfDir;               // Indicate whether we have reached the end of the directory\r
+  EFI_LIST_ENTRY      DirCacheLink;           // Linked in Volume->DirCacheList when discarded\r
+  UINTN               DirCacheTag;            // The identification of the directory when in directory cache\r
+  FAT_DIRENT          *LongNameHashTable[HASH_TABLE_SIZE];\r
+  FAT_DIRENT          *ShortNameHashTable[HASH_TABLE_SIZE];\r
+} FAT_ODIR;\r
+\r
+typedef struct {\r
+  UINTN               Signature;\r
+  EFI_FILE            Handle;\r
+  UINT64              Position;\r
+  BOOLEAN             ReadOnly;\r
+  struct _FAT_OFILE   *OFile;\r
+  EFI_LIST_ENTRY      Link;\r
+} FAT_IFILE;\r
+\r
+//\r
+// FAT_OFILE - Each opened file\r
+//\r
+typedef struct _FAT_OFILE {\r
+  UINTN               Signature;\r
+  struct _FAT_VOLUME  *Volume;\r
+  //\r
+  // A permanant error code to return to all accesses to\r
+  // this opened file\r
+  //\r
+  EFI_STATUS          Error;\r
+  //\r
+  // A list of the IFILE instances for this OFile\r
+  //\r
+  EFI_LIST_ENTRY      Opens;\r
+\r
+  //\r
+  // The dynamic infomation\r
+  //\r
+  UINTN               FileSize;\r
+  UINTN               FileCluster;\r
+  UINTN               FileCurrentCluster;\r
+  UINTN               FileLastCluster;\r
+\r
+  //\r
+  // Dirty is set if there have been any updates to the\r
+  // file\r
+  // Archive is set if the archive attribute in the file\92s\r
+  // directory entry needs to be set when performing flush\r
+  // PreserveLastMod is set if the last modification of the\r
+  // file is specified by SetInfo API\r
+  //\r
+  BOOLEAN             Dirty;\r
+  BOOLEAN             IsFixedRootDir;\r
+  BOOLEAN             PreserveLastModification;\r
+  BOOLEAN             Archive;\r
+  //\r
+  // Set by an OFile SetPosition\r
+  //\r
+  UINTN               Position; // within file\r
+  UINT64              PosDisk;  // on the disk\r
+  UINTN               PosRem;   // remaining in this disk run\r
+  //\r
+  // The opened parent, full path length and currently opened child files\r
+  //\r
+  struct _FAT_OFILE   *Parent;\r
+  UINTN               FullPathLen;\r
+  EFI_LIST_ENTRY      ChildHead;\r
+  EFI_LIST_ENTRY      ChildLink;\r
+\r
+  //\r
+  // The opened directory structure for a directory; if this\r
+  // OFile represents a file, then ODir = NULL\r
+  //\r
+  FAT_ODIR            *ODir;\r
+  //\r
+  // The directory entry for the Ofile\r
+  //\r
+  FAT_DIRENT          *DirEnt;\r
+\r
+  //\r
+  // Link in Volume's reference list\r
+  //\r
+  EFI_LIST_ENTRY      CheckLink;\r
+} FAT_OFILE;\r
+\r
+typedef struct _FAT_VOLUME {\r
+  UINTN                           Signature;\r
+\r
+  EFI_HANDLE                      Handle;\r
+  BOOLEAN                         Valid;\r
+  BOOLEAN                         DiskError;\r
+\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL VolumeInterface;\r
+\r
+  //\r
+  // If opened, the parent handle and BlockIo interface\r
+  //\r
+  EFI_BLOCK_IO_PROTOCOL           *BlockIo;\r
+  EFI_DISK_IO_PROTOCOL            *DiskIo;\r
+  UINT32                          MediaId;\r
+  BOOLEAN                         ReadOnly;\r
+\r
+  //\r
+  // Computed values from fat bpb info\r
+  //\r
+  UINT64                          VolumeSize;\r
+  UINT64                          FatPos;           // Disk pos of fat tables\r
+  UINT64                          RootPos;          // Disk pos of root directory\r
+  UINT64                          FirstClusterPos;  // Disk pos of first cluster\r
+  UINTN                           FatSize;          // Number of bytes in each fat\r
+  UINTN                           MaxCluster;       // Max cluster number\r
+  UINTN                           ClusterSize;      // Cluster size of fat partition\r
+  UINT8                           ClusterAlignment; // Equal to log_2 (clustersize);\r
+  FAT_VOLUME_TYPE                 FatType;\r
+\r
+  //\r
+  // Current part of fat table that's present\r
+  //\r
+  UINT64                          FatEntryPos;    // Location of buffer\r
+  UINTN                           FatEntrySize;   // Size of buffer\r
+  UINT32                          FatEntryBuffer; // The buffer\r
+  FAT_INFO_SECTOR                 FatInfoSector;  // Free cluster info\r
+  UINTN                           FreeInfoPos;    // Pos with the free cluster info\r
+  BOOLEAN                         FreeInfoValid;  // If free cluster info is valid\r
+  //\r
+  // Unpacked Fat BPB info\r
+  //\r
+  UINTN                           NumFats;\r
+  UINTN                           RootEntries;    // < FAT32, root dir is fixed size\r
+  UINTN                           RootCluster;    // >= FAT32, root cluster chain head\r
+  //\r
+  // info for marking the volume dirty or not\r
+  //\r
+  BOOLEAN                         FatDirty;       // If fat-entries have been updated\r
+  UINT32                          DirtyValue;\r
+  UINT32                          NotDirtyValue;\r
+\r
+  //\r
+  // The root directory entry and opened root file\r
+  //\r
+  FAT_DIRENT                      RootDirEnt;\r
+  //\r
+  // File Name of root OFile, it is empty string\r
+  //\r
+  CHAR16                          RootFileString[1];\r
+  struct _FAT_OFILE               *Root;\r
+\r
+  //\r
+  // New OFiles are added to this list so they\r
+  // can be cleaned up if they aren't referenced.\r
+  //\r
+  EFI_LIST_ENTRY                  CheckRef;\r
+\r
+  //\r
+  // Directory cache List\r
+  //\r
+  EFI_LIST_ENTRY                  DirCacheList;\r
+  UINTN                           DirCacheCount;\r
+\r
+  //\r
+  // Disk Cache for this volume\r
+  //\r
+  VOID                            *CacheBuffer;\r
+  DISK_CACHE                      DiskCache[CACHE_MAX_TYPE];\r
+} FAT_VOLUME;\r
+\r
+//\r
+// Function Prototypes\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+FatOpen (\r
+  IN  EFI_FILE          *FHand,\r
+  OUT EFI_FILE          **NewHandle,\r
+  IN  CHAR16            *FileName,\r
+  IN  UINT64            OpenMode,\r
+  IN  UINT64            Attributes\r
+  )\r
+/*++\r
+Routine Description:\r
+\r
+  Implements Open() of Simple File System Protocol.\r
+  \r
+Arguments:\r
+\r
+  FHand                 - File handle of the file serves as a starting reference point.\r
+  NewHandle             - Handle of the file that is newly opened.\r
+  FileName              - File name relative to FHand.\r
+  OpenMode              - Open mode.\r
+  Attributes            - Attributes to set if the file is created.\r
+  \r
+Returns:\r
+\r
+  EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.\r
+                          The OpenMode is not supported.\r
+                          The Attributes is not the valid attributes.\r
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory for file string.\r
+  EFI_SUCCESS           - Open the file successfully.\r
+  Others                - The status of open file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatGetPosition (\r
+  IN  EFI_FILE          *FHand,\r
+  OUT UINT64            *Position\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Get the file's position of the file\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of file.\r
+  Position              - The file's position of the file.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get the info successfully.\r
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.\r
+  EFI_UNSUPPORTED       - The open file is not a file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatGetInfo (\r
+  IN     EFI_FILE      *FHand,\r
+  IN     EFI_GUID      *Type,\r
+  IN OUT UINTN         *BufferSize,\r
+     OUT VOID          *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Get the some types info of the file into Buffer\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of file.\r
+  Type                  - The type of the info.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get the info successfully.\r
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatSetInfo (\r
+  IN EFI_FILE           *FHand,\r
+  IN EFI_GUID           *Type,\r
+  IN UINTN              BufferSize,\r
+  IN VOID               *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Set the some types info of the file into Buffer\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of file.\r
+  Type                  - The type of the info.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Set the info successfully.\r
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatFlush (\r
+  IN EFI_FILE           *FHand\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Flushes all data associated with the file handle\r
+\r
+Arguments:\r
+\r
+  FHand                 - Handle to file to flush\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS           - Flushed the file successfully\r
+  EFI_WRITE_PROTECTED   - The volume is read only\r
+  EFI_ACCESS_DENIED     - The volume is not read only\r
+                          but the file is read only\r
+  Others                - Flushing of the file is failed\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatClose (\r
+  IN EFI_FILE  *FHand\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Flushes & Closes the file handle.\r
+  \r
+Arguments:\r
+\r
+  FHand                 - Handle to the file to delete.\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS           - Closed the file successfully.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDelete (\r
+  IN EFI_FILE           *FHand\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Deletes the file & Closes the file handle.\r
+  \r
+Arguments:\r
+\r
+  FHand                    - Handle to the file to delete.\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS              - Delete the file successfully.\r
+  EFI_WARN_DELETE_FAILURE  - Fail to delete the file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatSetPosition (\r
+  IN EFI_FILE           *FHand,\r
+  IN UINT64             Position\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Set the file's position of the file\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of file\r
+  Position              - The file's position of the file \r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Set the info successfully\r
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file\r
+  EFI_UNSUPPORTED       - Set a directory with a not-zero position\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatRead (\r
+  IN     EFI_FILE   *FHand,\r
+  IN OUT UINTN      *BufferSize,\r
+     OUT VOID       *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Get the file info.\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of the file.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing read data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get the file info successfully.\r
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.\r
+  EFI_VOLUME_CORRUPTED  - The file type of open file is error.\r
+  other                 - An error occurred when operation the disk.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatWrite (\r
+  IN     EFI_FILE      *FHand,\r
+  IN OUT UINTN         *BufferSize,\r
+  IN     VOID          *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Set the file info.\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of the file.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing write data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Set the file info successfully.\r
+  EFI_WRITE_PROTECTED   - The disk is write protected.\r
+  EFI_ACCESS_DENIED     - The file is read-only.\r
+  EFI_DEVICE_ERROR      - The OFile is not valid.\r
+  EFI_UNSUPPORTED       - The open file is not a file.\r
+                        - The writing file size is larger than 4GB.\r
+  other                 - An error occurred when operation the disk.\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// DiskCache.c\r
+//\r
+EFI_STATUS\r
+FatInitializeDiskCache (\r
+  IN FAT_VOLUME              *Volume\r
+  );\r
+\r
+EFI_STATUS\r
+FatAccessCache (\r
+  IN     FAT_VOLUME          *Volume,\r
+  IN     CACHE_DATA_TYPE     CacheDataType,\r
+  IN     IO_MODE             IoMode,\r
+  IN     UINT64              Offset,\r
+  IN     UINTN               BufferSize,\r
+  IN OUT UINT8               *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+FatVolumeFlushCache (\r
+  IN FAT_VOLUME              *Volume\r
+  );\r
+\r
+//\r
+// Flush.c\r
+//\r
+EFI_STATUS\r
+FatOFileFlush (\r
+  IN FAT_OFILE          *OFile\r
+  );\r
+\r
+BOOLEAN\r
+FatCheckOFileRef (\r
+  IN FAT_OFILE          *OFile\r
+  );\r
+\r
+VOID\r
+FatSetVolumeError (\r
+  IN FAT_OFILE          *OFile,\r
+  IN EFI_STATUS         Status\r
+  );\r
+\r
+EFI_STATUS\r
+FatIFileClose (\r
+  FAT_IFILE             *IFile\r
+  );\r
+\r
+EFI_STATUS\r
+FatCleanupVolume (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN FAT_OFILE          *OFile,\r
+  IN EFI_STATUS         EfiStatus\r
+  );\r
+\r
+//\r
+// FileSpace.c\r
+//\r
+EFI_STATUS\r
+FatShrinkEof (\r
+  IN FAT_OFILE          *OFile\r
+  );\r
+\r
+EFI_STATUS\r
+FatGrowEof (\r
+  IN FAT_OFILE          *OFile,\r
+  IN UINT64             NewSizeInBytes\r
+  );\r
+\r
+UINTN\r
+FatPhysicalDirSize (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN UINTN              Cluster\r
+  );\r
+\r
+UINT64\r
+FatPhysicalFileSize (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN UINTN              RealSize\r
+  );\r
+\r
+EFI_STATUS\r
+FatOFilePosition (\r
+  IN FAT_OFILE            *OFile,\r
+  IN UINTN                Position,\r
+  IN UINTN                PosLimit\r
+  );\r
+\r
+VOID\r
+FatComputeFreeInfo (\r
+  IN FAT_VOLUME         *Volume\r
+  );\r
+\r
+//\r
+// Init.c\r
+//\r
+EFI_STATUS\r
+FatInitUnicodeCollationSupport (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN  LC_ISO_639_2                   *LangCode,\r
+  OUT EFI_UNICODE_COLLATION_PROTOCOL **UnicodeCollationInterface\r
+  );\r
+\r
+EFI_STATUS\r
+FatAllocateVolume (\r
+  IN  EFI_HANDLE                     Handle,\r
+  IN  EFI_DISK_IO_PROTOCOL           *DiskIo,\r
+  IN  EFI_BLOCK_IO_PROTOCOL          *BlockIo\r
+  );\r
+\r
+EFI_STATUS\r
+FatOpenDevice (\r
+  IN OUT FAT_VOLUME     *Volume\r
+  );\r
+\r
+EFI_STATUS\r
+FatAbandonVolume (\r
+  IN FAT_VOLUME         *Volume\r
+  );\r
+\r
+//\r
+// Misc.c\r
+//\r
+EFI_STATUS\r
+FatAccessVolumeDirty (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN IO_MODE            IoMode,\r
+  IN VOID               *DirtyValue\r
+  );\r
+\r
+EFI_STATUS\r
+FatDiskIo (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN IO_MODE            IoMode,\r
+  IN UINT64             Offset,\r
+  IN UINTN              BufferSize,\r
+  IN OUT VOID           *Buffer\r
+  );\r
+\r
+VOID\r
+FatAcquireLock (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+FatReleaseLock (\r
+  VOID\r
+  );\r
+\r
+BOOLEAN\r
+FatIsLocked (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+FatFreeDirEnt (\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+VOID\r
+FatFreeVolume (\r
+  IN FAT_VOLUME         *Volume\r
+  );\r
+\r
+VOID\r
+FatEfiTimeToFatTime (\r
+  IN EFI_TIME           *ETime,\r
+  OUT FAT_DATE_TIME     *FTime\r
+  );\r
+\r
+VOID\r
+FatFatTimeToEfiTime (\r
+  IN FAT_DATE_TIME      *FTime,\r
+  OUT EFI_TIME          *ETime\r
+  );\r
+\r
+VOID\r
+FatGetCurrentFatTime (\r
+  OUT FAT_DATE_TIME     *FatTime\r
+  );\r
+\r
+BOOLEAN\r
+FatIsValidTime (\r
+  IN EFI_TIME           *Time\r
+  );\r
+\r
+VOID\r
+FatFatToStr (\r
+  IN UINTN              FatSize,\r
+  IN CHAR8              *Fat,\r
+  OUT CHAR16            *String\r
+  );\r
+\r
+BOOLEAN\r
+FatStrToFat (\r
+  IN  CHAR16            *String,\r
+  IN  UINTN             FatSize,\r
+  OUT CHAR8             *Fat\r
+  );\r
+\r
+BOOLEAN\r
+EfiLibCompareLanguage (\r
+  IN  CHAR8  *Language1,\r
+  IN  CHAR8  *Language2\r
+  );\r
+\r
+VOID\r
+FatStrLwr (\r
+  IN CHAR16             *Str\r
+  );\r
+\r
+VOID\r
+FatStrUpr (\r
+  IN CHAR16             *Str\r
+  );\r
+\r
+INTN\r
+FatStriCmp (\r
+  IN CHAR16             *Str1,\r
+  IN CHAR16             *Str2\r
+  );\r
+\r
+//\r
+// Open.c\r
+//\r
+EFI_STATUS\r
+FatOFileOpen (\r
+  IN FAT_OFILE          *OFile,\r
+  OUT FAT_IFILE         **NewIFile,\r
+  IN CHAR16             *FileName,\r
+  IN UINT64             OpenMode,\r
+  IN UINT8              Attributes\r
+  );\r
+\r
+EFI_STATUS\r
+FatAllocateIFile (\r
+  IN FAT_OFILE          *OFile,\r
+  OUT FAT_IFILE         **PtrIFile\r
+  );\r
+\r
+//\r
+// OpenVolume.c\r
+//\r
+EFI_STATUS\r
+FatOpenVolume (\r
+  IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
+  OUT EFI_FILE                        **File\r
+  );\r
+\r
+//\r
+// ReadWrite.c\r
+//\r
+EFI_STATUS\r
+FatAccessOFile (\r
+  IN FAT_OFILE          *OFile,\r
+  IN IO_MODE            IoMode,\r
+  IN UINTN              Position,\r
+  IN UINTN              *DataBufferSize,\r
+  IN UINT8              *UserBuffer\r
+  );\r
+\r
+EFI_STATUS\r
+FatExpandOFile (\r
+  IN FAT_OFILE          *OFile,\r
+  IN UINT64             ExpandedSize\r
+  );\r
+\r
+EFI_STATUS\r
+FatWriteZeroPool (\r
+  IN FAT_OFILE          *OFile,\r
+  IN UINTN              WritePos\r
+  );\r
+\r
+EFI_STATUS\r
+FatTruncateOFile (\r
+  IN FAT_OFILE          *OFile,\r
+  IN UINTN              TruncatedSize\r
+  );\r
+\r
+//\r
+// DirectoryManage.c\r
+//\r
+VOID\r
+FatResetODirCursor (\r
+  IN FAT_OFILE          *OFile\r
+  );\r
+\r
+EFI_STATUS\r
+FatGetNextDirEnt (\r
+  IN  FAT_OFILE         *OFILE,\r
+  OUT FAT_DIRENT        **PtrDirEnt\r
+  );\r
+\r
+EFI_STATUS\r
+FatRemoveDirEnt (\r
+  IN FAT_OFILE          *OFile,\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+EFI_STATUS\r
+FatStoreDirEnt (\r
+  IN FAT_OFILE          *OFile,\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+EFI_STATUS\r
+FatCreateDirEnt (\r
+  IN  FAT_OFILE         *OFile,\r
+  IN  CHAR16            *FileName,\r
+  IN  UINT8             Attributes,\r
+  OUT FAT_DIRENT        **PtrDirEnt\r
+  );\r
+\r
+BOOLEAN\r
+FatIsDotDirEnt (\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+VOID\r
+FatUpdateDirEntClusterSizeInfo (\r
+  IN FAT_OFILE          *OFile\r
+  );\r
+\r
+VOID\r
+FatCloneDirEnt (\r
+  IN  FAT_DIRENT        *DirEnt1,\r
+  IN  FAT_DIRENT        *DirEnt2\r
+  );\r
+\r
+EFI_STATUS\r
+FatGetDirEntInfo (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN FAT_DIRENT         *DirEnt,\r
+  IN OUT UINTN          *BufferSize,\r
+  OUT VOID              *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+FatOpenDirEnt (\r
+  IN FAT_OFILE          *OFile,\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+EFI_STATUS\r
+FatCreateDotDirEnts (\r
+  IN FAT_OFILE          *OFile\r
+  );\r
+\r
+VOID\r
+FatCloseDirEnt (\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+EFI_STATUS\r
+FatLocateOFile (\r
+  IN OUT FAT_OFILE      **PtrOFile,\r
+  IN     CHAR16         *FileName,\r
+  IN     UINT8          Attributes,\r
+     OUT CHAR16         *NewFileName\r
+  );\r
+\r
+EFI_STATUS\r
+FatGetVolumeEntry (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN CHAR16             *Name\r
+  );\r
+\r
+EFI_STATUS\r
+FatSetVolumeEntry (\r
+  IN FAT_VOLUME         *Volume,\r
+  IN CHAR16             *Name\r
+  );\r
+\r
+//\r
+// Hash.c\r
+//\r
+FAT_DIRENT **\r
+FatLongNameHashSearch (\r
+  IN FAT_ODIR           *ODir,\r
+  IN CHAR16             *LongNameString\r
+  );\r
+\r
+FAT_DIRENT **\r
+FatShortNameHashSearch (\r
+  IN FAT_ODIR           *ODir,\r
+  IN CHAR8              *ShortNameString\r
+  );\r
+\r
+VOID\r
+FatInsertToHashTable (\r
+  IN FAT_ODIR           *ODir,\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+VOID\r
+FatDeleteFromHashTable (\r
+  IN FAT_ODIR           *ODir,\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+//\r
+// FileName.c\r
+//\r
+BOOLEAN\r
+FatCheckIs8Dot3Name (\r
+  IN CHAR16             *FileName,\r
+  OUT CHAR8             *File8Dot3Name\r
+  );\r
+\r
+VOID\r
+FatCreate8Dot3Name (\r
+  IN FAT_OFILE          *Parent,\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+VOID\r
+FatNameToStr (\r
+  IN CHAR8              *FatName,\r
+  IN UINTN              Len,\r
+  IN UINTN              LowerCase,\r
+  IN CHAR16             *Str\r
+  );\r
+\r
+VOID\r
+FatSetCaseFlag (\r
+  IN FAT_DIRENT         *DirEnt\r
+  );\r
+\r
+VOID\r
+FatGetFileNameViaCaseFlag (\r
+  IN  FAT_DIRENT        *DirEnt,\r
+  OUT CHAR16            *FileString\r
+  );\r
+\r
+UINT8\r
+FatCheckSum (\r
+  IN CHAR8              *ShortNameString\r
+  );\r
+\r
+CHAR16*\r
+FatGetNextNameComponent (\r
+  IN  CHAR16            *Path,\r
+  OUT CHAR16            *Name\r
+  );\r
+\r
+BOOLEAN\r
+FatFileNameIsValid (\r
+  IN  CHAR16  *InputFileName,\r
+  OUT CHAR16  *OutputFileName\r
+  );\r
+\r
+//\r
+// DirectoryCache.c\r
+//\r
+VOID\r
+FatDiscardODir (\r
+  IN FAT_OFILE    *OFile\r
+  );\r
+\r
+VOID\r
+FatRequestODir (\r
+  IN FAT_OFILE    *OFile\r
+  );\r
+\r
+VOID\r
+FatCleanupODirCache (\r
+  IN FAT_VOLUME   *Volume\r
+  );\r
+\r
+\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL    gFatDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL    gFatComponentName;\r
+extern EFI_LOCK                       FatFsLock;\r
+extern EFI_FILE                       FatFileInterface;\r
+extern EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollationInterface;\r
+\r
+#endif\r
diff --git a/EnhancedFat/Dxe/Fat.msa b/EnhancedFat/Dxe/Fat.msa
new file mode 100644 (file)
index 0000000..a6d9302
--- /dev/null
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--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.-->\r
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0">\r
+  <MsaHeader>\r
+    <ModuleName>Enhanced Fat Source Module</ModuleName>\r
+    <ModuleType>UEFI_DRIVER</ModuleType>\r
+    <GuidValue>961578FE-B6B7-44c3-AF35-6BC705CD2B1F</GuidValue>\r
+    <Version>1.0</Version>\r
+    <Abstract>Component description file for FAT module.</Abstract>\r
+    <Description>FIX ME!</Description>\r
+    <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>\r
+    <License>Redistribution and use in source and binary forms, with or without
+      modification, are permitted provided that the following conditions are
+      met:
+
+           Redistributions of source code must retain the above copyright
+           notice, this list of conditions and the following disclaimer.
+
+           Redistributions in binary form must reproduce the above copyright
+           notice, this list of conditions and the following disclaimer in 
+           the documentation and/or other materials provided with the 
+           distribution.
+
+           Neither the name of Intel nor the names of its contributors may
+           be used to endorse or promote products derived from this software
+           without specific prior written permission.
+
+      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+      "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+      LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+      A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+      OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+      SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+      LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+      DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+      THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+      (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+      OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+      Additional terms: In addition to the forgoing, redistribution and use
+      of the code is conditioned upon the FAT 32 File System Driver and all
+      derivative works thereof being used for and designed only to read
+      and/or write to a file system that is directly managed by an
+      Extensible Firmware Interface (EFI) implementation or by an emulator
+      of an EFI implementation.</License>\r
+    <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION   0x00000052</Specification>\r
+  </MsaHeader>\r
+  <ModuleDefinitions>\r
+    <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>\r
+    <BinaryModule>false</BinaryModule>\r
+    <OutputFileBasename>Fat</OutputFileBasename>\r
+  </ModuleDefinitions>\r
+  <LibraryClassDefinitions>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>DebugLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiDriverModelLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiDriverEntryPoint</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>BaseMemoryLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>MemoryAllocationLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiBootServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+    <LibraryClass Usage="ALWAYS_CONSUMED">\r
+      <Keyword>UefiRuntimeServicesTableLib</Keyword>\r
+    </LibraryClass>\r
+  </LibraryClassDefinitions>\r
+  <SourceFiles>\r
+    <Filename>Data.c</Filename>\r
+    <Filename>Delete.c</Filename>\r
+    <Filename>Fat.c</Filename>\r
+    <Filename>Flush.c</Filename>\r
+    <Filename>FileSpace.c</Filename>\r
+    <Filename>Info.c</Filename>\r
+    <Filename>Init.c</Filename>\r
+    <Filename>Misc.c</Filename>\r
+    <Filename>Open.c</Filename>\r
+    <Filename>OpenVolume.c</Filename>\r
+    <Filename>ReadWrite.c</Filename>\r
+    <Filename>Fat.c</Filename>\r
+    <Filename>ComponentName.c</Filename>\r
+    <Filename>DirectoryManage.c</Filename>\r
+    <Filename>Hash.c</Filename>\r
+    <Filename>FileName.c</Filename>\r
+    <Filename>DiskCache.c</Filename>\r
+    <Filename>DirectoryCache.c</Filename>\r
+  </SourceFiles>\r
+  <PackageDependencies>\r
+    <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>\r
+  </PackageDependencies>\r
+  <Protocols>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiBlockIoProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiDiskIoProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiUnicodeCollationProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+    <!--<Protocol Usage="ALWAYS_CONSUMED">
+      <ProtocolCName>Loadedimage</ProtocolCName>
+    </Protocol>-->\r
+    <Protocol Usage="ALWAYS_CONSUMED">\r
+      <ProtocolCName>gEfiSimpleFileSystemProtocolGuid</ProtocolCName>\r
+    </Protocol>\r
+  </Protocols>\r
+  <Guids>\r
+    <GuidCNames Usage="ALWAYS_CONSUMED">\r
+      <GuidCName>gEfiGlobalVariableGuid</GuidCName>\r
+    </GuidCNames>\r
+    <GuidCNames Usage="ALWAYS_CONSUMED">\r
+      <GuidCName>gEfiFileSystemInfoGuid</GuidCName>\r
+    </GuidCNames>\r
+    <!--<GuidCNames Usage="ALWAYS_CONSUMED">
+      <GuidCName>FileSystemVolumeLabelInfo</GuidCName>
+    </GuidCNames>-->\r
+    <GuidCNames Usage="ALWAYS_CONSUMED">\r
+      <GuidCName>gEfiFileInfoGuid</GuidCName>\r
+    </GuidCNames>\r
+    <GuidCNames Usage="ALWAYS_CONSUMED">\r
+      <GuidCName>gEfiFileSystemVolumeLabelInfoIdGuid</GuidCName>\r
+    </GuidCNames>\r
+  </Guids>\r
+  <Externs>\r
+    <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>\r
+    <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>\r
+    <Extern>\r
+      <ModuleUnloadImage>FatUnload</ModuleUnloadImage>\r
+    </Extern>\r
+    <Extern>\r
+      <DriverBinding>gFatDriverBinding</DriverBinding>\r
+    </Extern>\r
+    <Extern>\r
+      <ComponentName>gFatComponentName</ComponentName>\r
+    </Extern>\r
+  </Externs>\r
+</ModuleSurfaceArea>
\ No newline at end of file
diff --git a/EnhancedFat/Dxe/FatFileSystem.h b/EnhancedFat/Dxe/FatFileSystem.h
new file mode 100644 (file)
index 0000000..9506bb8
--- /dev/null
@@ -0,0 +1,216 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  FatFileSystem.h\r
+\r
+Abstract:\r
+\r
+  Definitions for on-disk FAT structures\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#ifndef _FATFILESYSTEM_H_\r
+#define _FATFILESYSTEM_H_\r
+\r
+#pragma pack(1)\r
+//\r
+// FAT info signature\r
+//\r
+#define FAT_INFO_SIGNATURE        0x41615252\r
+#define FAT_INFO_BEGIN_SIGNATURE  0x61417272\r
+#define FAT_INFO_END_SIGNATURE    0xAA550000\r
+//\r
+// FAT entry values\r
+//\r
+#define FAT_CLUSTER_SPECIAL_EXT       (-1 & (~0xF))\r
+#define FAT_CLUSTER_SPECIAL           ((FAT_CLUSTER_SPECIAL_EXT) | 0x07)\r
+#define FAT_CLUSTER_FREE              0\r
+#define FAT_CLUSTER_RESERVED          (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_BAD               (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_LAST              (-1)\r
+#define FAT_END_OF_FAT_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL))\r
+#define FAT_MIN_CLUSTER               2\r
+#define FAT_MAX_FAT12_CLUSTER         0xFF5\r
+#define FAT_MAX_FAT16_CLUSTER         0xFFF5\r
+#define FAT_CLUSTER_SPECIAL_FAT12     0xFF7\r
+#define FAT_CLUSTER_SPECIAL_FAT16     0xFFF7\r
+#define FAT_CLUSTER_SPECIAL_FAT32     0x0FFFFFF7\r
+#define FAT_CLUSTER_MASK_FAT12        0xFFF\r
+#define FAT_CLUSTER_UNMASK_FAT12      0xF000\r
+#define FAT_CLUSTER_MASK_FAT32        0x0FFFFFFF\r
+#define FAT_CLUSTER_UNMASK_FAT32      0xF0000000\r
+#define FAT_POS_FAT12(a)              ((a) * 3 / 2)\r
+#define FAT_POS_FAT16(a)              ((a) * 2)\r
+#define FAT_POS_FAT32(a)              ((a) * 4)\r
+#define FAT_ODD_CLUSTER_FAT12(a)      (((a) & 1) != 0)\r
+\r
+\r
+//\r
+// FAT attribute define\r
+//\r
+#define FAT_ATTRIBUTE_READ_ONLY 0x01\r
+#define FAT_ATTRIBUTE_HIDDEN    0x02\r
+#define FAT_ATTRIBUTE_SYSTEM    0x04\r
+#define FAT_ATTRIBUTE_VOLUME_ID 0x08\r
+#define FAT_ATTRIBUTE_DIRECTORY 0x10\r
+#define FAT_ATTRIBUTE_ARCHIVE   0x20\r
+#define FAT_ATTRIBUTE_DEVICE    0x40\r
+#define FAT_ATTRIBUTE_LFN       0x0F\r
+//\r
+// Some Long File Name definitions\r
+//\r
+#define FAT_LFN_LAST            0x40  // Ordinal field\r
+#define MAX_LFN_ENTRIES         20\r
+#define LFN_CHAR1_LEN           5\r
+#define LFN_CHAR2_LEN           6\r
+#define LFN_CHAR3_LEN           2\r
+#define LFN_CHAR_TOTAL          (LFN_CHAR1_LEN + LFN_CHAR2_LEN + LFN_CHAR3_LEN)\r
+#define LFN_ENTRY_NUMBER(a)     (((a) + LFN_CHAR_TOTAL - 1) / LFN_CHAR_TOTAL)\r
+//\r
+// Some 8.3 File Name definitions\r
+//\r
+#define FAT_MAIN_NAME_LEN       8\r
+#define FAT_EXTEND_NAME_LEN     3\r
+#define FAT_NAME_LEN            (FAT_MAIN_NAME_LEN + FAT_EXTEND_NAME_LEN)\r
+//\r
+// Some directory entry information\r
+//\r
+#define FAT_ENTRY_INFO_OFFSET   13\r
+#define DELETE_ENTRY_MARK       0xE5\r
+#define EMPTY_ENTRY_MARK        0x00\r
+\r
+//\r
+// Volume dirty Mask\r
+//\r
+#define FAT16_DIRTY_MASK        0x7fff\r
+#define FAT32_DIRTY_MASK        0xf7ffffff\r
+//\r
+// internal flag\r
+//\r
+#define FAT_CASE_MIXED          0x01\r
+#define FAT_CASE_NAME_LOWER     0x08\r
+#define FAT_CASE_EXT_LOWER      0x10\r
+\r
+typedef struct {\r
+  UINT8   Ia32Jump[3];\r
+  CHAR8   OemId[8];\r
+  UINT16  SectorSize;\r
+  UINT8   SectorsPerCluster;\r
+  UINT16  ReservedSectors;\r
+  UINT8   NumFats;\r
+  UINT16  RootEntries;          // < FAT32, root dir is fixed size\r
+  UINT16  Sectors;\r
+  UINT8   Media;\r
+  UINT16  SectorsPerFat;        // < FAT32\r
+  UINT16  SectorsPerTrack;      // (ignored)\r
+  UINT16  Heads;                // (ignored)\r
+  UINT32  HiddenSectors;        // (ignored)\r
+  UINT32  LargeSectors;         // Used if Sectors==0\r
+} FAT_BOOT_SECTOR_BASIC;\r
+\r
+typedef struct {\r
+  UINT8 PhysicalDriveNumber;    // (ignored)\r
+  UINT8 CurrentHead;            // holds boot_sector_dirty bit\r
+  UINT8 Signature;              // (ignored)\r
+  CHAR8 Id[4];\r
+  CHAR8 FatLabel[11];\r
+  CHAR8 SystemId[8];\r
+} FAT_BOOT_SECTOR_EXT;\r
+\r
+typedef struct {\r
+  UINT32  LargeSectorsPerFat;   // FAT32\r
+  UINT16  ExtendedFlags;        // FAT32 (ignored)\r
+  UINT16  FsVersion;            // FAT32 (ignored)\r
+  UINT32  RootDirFirstCluster;  // FAT32\r
+  UINT16  FsInfoSector;         // FAT32\r
+  UINT16  BackupBootSector;     // FAT32\r
+  UINT8   Reserved[12];         // FAT32 (ignored)\r
+  UINT8   PhysicalDriveNumber;  // (ignored)\r
+  UINT8   CurrentHead;          // holds boot_sector_dirty bit\r
+  UINT8   Signature;            // (ignored)\r
+  CHAR8   Id[4];\r
+  CHAR8   FatLabel[11];\r
+  CHAR8   SystemId[8];\r
+} FAT32_BOOT_SECTOR_EXT;\r
+\r
+typedef struct {\r
+  FAT_BOOT_SECTOR_BASIC   FatBsb;\r
+  union {\r
+    FAT_BOOT_SECTOR_EXT   FatBse;\r
+    FAT32_BOOT_SECTOR_EXT Fat32Bse;\r
+  } FatBse;\r
+} FAT_BOOT_SECTOR;\r
+\r
+//\r
+// FAT Info Structure\r
+//\r
+typedef struct {\r
+  UINT32  ClusterCount;\r
+  UINT32  NextCluster;\r
+} FAT_FREE_INFO;\r
+\r
+typedef struct {\r
+  UINT32        Signature;\r
+  UINT8         ExtraBootCode[480];\r
+  UINT32        InfoBeginSignature;\r
+  FAT_FREE_INFO FreeInfo;\r
+  UINT8         Reserved[12];\r
+  UINT32        InfoEndSignature;\r
+} FAT_INFO_SECTOR;\r
+\r
+//\r
+// Directory Entry\r
+//\r
+typedef struct {\r
+  UINT16  Day : 5;\r
+  UINT16  Month : 4;\r
+  UINT16  Year : 7;                 // From 1980\r
+} FAT_DATE;\r
+\r
+typedef struct {\r
+  UINT16  DoubleSecond : 5;\r
+  UINT16  Minute : 6;\r
+  UINT16  Hour : 5;\r
+} FAT_TIME;\r
+\r
+typedef struct {\r
+  FAT_TIME  Time;\r
+  FAT_DATE  Date;\r
+} FAT_DATE_TIME;\r
+\r
+typedef struct {\r
+  CHAR8         FileName[11];       // 8.3 filename\r
+  UINT8         Attributes;\r
+  UINT8         CaseFlag;\r
+  UINT8         CreateMillisecond;  // (creation milliseconds - ignored)\r
+  FAT_DATE_TIME FileCreateTime;\r
+  FAT_DATE      FileLastAccess;\r
+  UINT16        FileClusterHigh;    // >= FAT32\r
+  FAT_DATE_TIME FileModificationTime;\r
+  UINT16        FileCluster;\r
+  UINT32        FileSize;\r
+} FAT_DIRECTORY_ENTRY;\r
+\r
+typedef struct {\r
+  UINT8   Ordinal;\r
+  CHAR8   Name1[10];                // (Really 5 chars, but not WCHAR aligned)\r
+  UINT8   Attributes;\r
+  UINT8   Type;\r
+  UINT8   Checksum;\r
+  CHAR16  Name2[6];\r
+  UINT16  MustBeZero;\r
+  CHAR16  Name3[2];\r
+} FAT_DIRECTORY_LFN;\r
+\r
+#pragma pack()\r
+\r
+#endif\r
diff --git a/EnhancedFat/Dxe/FileName.c b/EnhancedFat/Dxe/FileName.c
new file mode 100644 (file)
index 0000000..7e58dcd
--- /dev/null
@@ -0,0 +1,569 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  FileName.c\r
+  \r
+Abstract:\r
+\r
+  Functions for manipulating file names\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+BOOLEAN\r
+FatCheckIs8Dot3Name (\r
+  IN  CHAR16    *FileName,\r
+  OUT CHAR8     *File8Dot3Name\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function checks whether the input FileName is a valid 8.3 short name.\r
+  If the input FileName is a valid 8.3, the output is the 8.3 short name;\r
+  otherwise, the output is the base tag of 8.3 short name.\r
+\r
+Arguments:\r
+\r
+  FileName              - The input unicode filename.\r
+  File8Dot3Name         - The output ascii 8.3 short name or base tag of 8.3 short name.\r
+\r
+Returns: \r
+\r
+  TRUE                  - The input unicode filename is a valid 8.3 short name.\r
+  FALSE                 - The input unicode filename is not a valid 8.3 short name.\r
+  \r
+--*/\r
+{\r
+  BOOLEAN PossibleShortName;\r
+  CHAR16  *TempName;\r
+  CHAR16  *ExtendName;\r
+  CHAR16  *SeparateDot;\r
+  UINTN   MainNameLen;\r
+  UINTN   ExtendNameLen;\r
+\r
+  PossibleShortName = TRUE;\r
+  SeparateDot       = NULL;\r
+  EfiSetMem (File8Dot3Name, FAT_NAME_LEN, ' ');\r
+  for (TempName = FileName; *TempName; TempName++) {\r
+    if (*TempName == L'.') {\r
+      SeparateDot = TempName;\r
+    }\r
+  }\r
+\r
+  if (SeparateDot == NULL) {\r
+    //\r
+    // Extended filename is not detected\r
+    //\r
+    MainNameLen   = TempName - FileName;\r
+    ExtendName    = TempName;\r
+    ExtendNameLen = 0;\r
+  } else {\r
+    //\r
+    // Extended filename is detected\r
+    //\r
+    MainNameLen   = SeparateDot - FileName;\r
+    ExtendName    = SeparateDot + 1;\r
+    ExtendNameLen = TempName - ExtendName;\r
+  }\r
+  //\r
+  // We scan the filename for the second time\r
+  // to check if there exists any extra blanks and dots\r
+  //\r
+  while (--TempName >= FileName) {\r
+    if ((*TempName == L'.' || *TempName == L' ') && (TempName != SeparateDot)) {\r
+      //\r
+      // There exist extra blanks and dots\r
+      //\r
+      PossibleShortName = FALSE;\r
+    }\r
+  }\r
+\r
+  if (MainNameLen == 0) {\r
+    PossibleShortName = FALSE;\r
+  }\r
+\r
+  if (MainNameLen > FAT_MAIN_NAME_LEN) {\r
+    PossibleShortName = FALSE;\r
+    MainNameLen       = FAT_MAIN_NAME_LEN;\r
+  }\r
+\r
+  if (ExtendNameLen > FAT_EXTEND_NAME_LEN) {\r
+    PossibleShortName = FALSE;\r
+    ExtendNameLen     = FAT_EXTEND_NAME_LEN;\r
+  }\r
+\r
+  if (FatStrToFat (FileName, MainNameLen, File8Dot3Name)) {\r
+    PossibleShortName = FALSE;\r
+  }\r
+\r
+  if (FatStrToFat (ExtendName, ExtendNameLen, File8Dot3Name + FAT_MAIN_NAME_LEN)) {\r
+    PossibleShortName = FALSE;\r
+  }\r
+\r
+  return PossibleShortName;\r
+}\r
+\r
+STATIC\r
+UINTN\r
+FatTrimAsciiTrailingBlanks (\r
+  IN CHAR8        *Name,\r
+  IN UINTN        Len\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Trim the trailing blanks of fat name.\r
+  \r
+Arguments:\r
+\r
+  Name                  - The Char8 string needs to be trimed.\r
+  Len                   - The length of the fat name.\r
+  \r
+Returns: \r
+\r
+  The real length of the fat name after the trailing blanks are trimmed.\r
+  \r
+--*/\r
+{\r
+  while (Len > 0 && Name[Len - 1] == ' ') {\r
+    Len--;\r
+  }\r
+\r
+  return Len;\r
+}\r
+\r
+VOID\r
+FatNameToStr (\r
+  IN  CHAR8            *FatName,\r
+  IN  UINTN            Len,\r
+  IN  UINTN            LowerCase,\r
+  OUT CHAR16           *Str\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the ascii fat name to the unicode string and strip trailing spaces, \r
+  and if necessary, convert the unicode string to lower case.\r
+  \r
+Arguments:\r
+\r
+  FatName               - The Char8 string needs to be converted.\r
+  Len                   - The length of the fat name.\r
+  LowerCase             - Indicate whether to convert the string to lower case.\r
+  Str                   - The result of the convertion.\r
+  \r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  //\r
+  // First, trim the trailing blanks\r
+  //\r
+  Len = FatTrimAsciiTrailingBlanks (FatName, Len);\r
+  //\r
+  // Convert fat string to unicode string\r
+  //\r
+  FatFatToStr (Len, FatName, Str);\r
+\r
+  //\r
+  // If the name is to be lower cased, do it now\r
+  //\r
+  if (LowerCase != 0) {\r
+    FatStrLwr (Str);\r
+  }\r
+}\r
+\r
+VOID\r
+FatCreate8Dot3Name (\r
+  IN FAT_OFILE    *Parent,\r
+  IN FAT_DIRENT   *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This function generates 8Dot3 name from user specified name for a newly created file.\r
+\r
+Arguments:\r
+\r
+  Parent                - The parent directory.\r
+  DirEnt                - The directory entry whose 8Dot3Name needs to be generated.\r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  CHAR8 *ShortName;\r
+  CHAR8 *ShortNameChar;\r
+  UINTN BaseTagLen;\r
+  UINTN Index;\r
+  UINTN Retry;\r
+  UINT8 Segment;\r
+  union {\r
+    UINT32  Crc;\r
+    struct HEX_DATA {\r
+      UINT8 Segment : HASH_VALUE_TAG_LEN;\r
+    } Hex[HASH_VALUE_TAG_LEN];\r
+  } HashValue;\r
+  //\r
+  // Make sure the whole directory has been loaded\r
+  //\r
+  ASSERT (Parent->ODir->EndOfDir);\r
+  ShortName = DirEnt->Entry.FileName;\r
+\r
+  //\r
+  // Trim trailing blanks of 8.3 name\r
+  //\r
+  BaseTagLen = FatTrimAsciiTrailingBlanks (ShortName, FAT_MAIN_NAME_LEN);\r
+  if (BaseTagLen > SPEC_BASE_TAG_LEN) {\r
+    BaseTagLen = SPEC_BASE_TAG_LEN;\r
+  }\r
+  //\r
+  // We first use the algorithm described by spec.\r
+  //\r
+  ShortNameChar     = ShortName + BaseTagLen;\r
+  *ShortNameChar++  = '~';\r
+  *ShortNameChar    = '1';\r
+  Retry = 0;\r
+  while (*FatShortNameHashSearch (Parent->ODir, ShortName) != NULL) {\r
+    *ShortNameChar = *ShortNameChar + 1;\r
+    if (++Retry == MAX_SPEC_RETRY) {\r
+      //\r
+      // We use new algorithm to generate 8.3 name\r
+      //\r
+      ASSERT (DirEnt->FileString != NULL);\r
+      gBS->CalculateCrc32 (DirEnt->FileString, EfiStrSize (DirEnt->FileString), &HashValue.Crc);\r
+\r
+      if (BaseTagLen > HASH_BASE_TAG_LEN) {\r
+        BaseTagLen = HASH_BASE_TAG_LEN;\r
+      }\r
+\r
+      ShortNameChar = ShortName + BaseTagLen;\r
+      for (Index = 0; Index < HASH_VALUE_TAG_LEN; Index++) {\r
+        Segment = HashValue.Hex[Index].Segment;\r
+        if (Segment > 9) {\r
+          *ShortNameChar++ = Segment - 10 + 'A';\r
+        } else {\r
+          *ShortNameChar++ = Segment + '0';\r
+        }\r
+      }\r
+\r
+      *ShortNameChar++  = '~';\r
+      *ShortNameChar    = '1';\r
+    }\r
+  }\r
+}\r
+\r
+STATIC\r
+UINT8\r
+FatCheckNameCase (\r
+  IN CHAR16           *Str,\r
+  IN UINT8            InCaseFlag\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check the string is lower case or upper case\r
+  and it is used by fatname to dir entry count\r
+\r
+Arguments:\r
+\r
+  Str                   - The string which needs to be checked.\r
+  InCaseFlag            - The input case flag which is returned when the string is lower case.\r
+\r
+Returns: \r
+\r
+  OutCaseFlag           - The output case flag.\r
+  \r
+--*/\r
+{\r
+  CHAR16  Buffer[FAT_MAIN_NAME_LEN + 1];\r
+  UINT8   OutCaseFlag;\r
+\r
+  ASSERT (EfiStrSize (Str) <= sizeof (Buffer));\r
+  //\r
+  // Assume the case of input string is mixed\r
+  //\r
+  OutCaseFlag = FAT_CASE_MIXED;\r
+  //\r
+  // Lower case a copy of the string, if it matches the\r
+  // original then the string is lower case\r
+  //\r
+  EfiStrCpy (Buffer, Str);\r
+  FatStrLwr (Buffer);\r
+  if (EfiStrCmp (Str, Buffer) == 0) {\r
+    OutCaseFlag = InCaseFlag;\r
+  }\r
+  //\r
+  // Upper case a copy of the string, if it matches the\r
+  // original then the string is upper case\r
+  //\r
+  EfiStrCpy (Buffer, Str);\r
+  FatStrUpr (Buffer);\r
+  if (EfiStrCmp (Str, Buffer) == 0) {\r
+    OutCaseFlag = 0;\r
+  }\r
+\r
+  return OutCaseFlag;\r
+}\r
+\r
+VOID\r
+FatSetCaseFlag (\r
+  IN FAT_DIRENT   *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Set the caseflag value for the directory entry.\r
+  \r
+Arguments:\r
\r
+  DirEnt                - The logical directory entry whose caseflag value is to be set.\r
+  \r
+Returns:\r
+  \r
+  None.\r
+  \r
+--*/\r
+{\r
+  CHAR16  LfnBuffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1];\r
+  CHAR16  *TempCharPtr;\r
+  CHAR16  *ExtendName;\r
+  CHAR16  *FileNameCharPtr;\r
+  UINT8   CaseFlag;\r
+\r
+  ExtendName      = NULL;\r
+  TempCharPtr     = LfnBuffer;\r
+  FileNameCharPtr = DirEnt->FileString;\r
+  ASSERT (EfiStrSize (DirEnt->FileString) <= sizeof (LfnBuffer));\r
+  while ((*TempCharPtr = *FileNameCharPtr) != 0) {\r
+    if (*TempCharPtr == L'.') {\r
+      ExtendName = TempCharPtr;\r
+    }\r
+\r
+    TempCharPtr++;\r
+    FileNameCharPtr++;\r
+  }\r
+\r
+  CaseFlag = 0;\r
+  if (ExtendName != NULL) {\r
+    *ExtendName = 0;\r
+    ExtendName++;\r
+    CaseFlag |= FatCheckNameCase (ExtendName, FAT_CASE_EXT_LOWER);\r
+  }\r
+\r
+  CaseFlag |= FatCheckNameCase (LfnBuffer, FAT_CASE_NAME_LOWER);\r
+  if ((CaseFlag & FAT_CASE_MIXED) == 0) {\r
+    //\r
+    // We just need one directory entry to store this file name entry\r
+    //\r
+    DirEnt->Entry.CaseFlag = CaseFlag;\r
+  } else {\r
+    //\r
+    // We need one extra directory entry to store the mixed case entry\r
+    //\r
+    DirEnt->Entry.CaseFlag = 0;\r
+    DirEnt->EntryCount++;\r
+  }\r
+}\r
+\r
+VOID\r
+FatGetFileNameViaCaseFlag (\r
+  IN  FAT_DIRENT    *DirEnt,\r
+  OUT CHAR16        *FileString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Convert the 8.3 ASCII fat name to cased Unicode string according to case flag.\r
+  \r
+Arguments:\r
+\r
+  DirEnt                     - The corresponding directory entry.\r
+  FileString             - The output Unicode file name.\r
+  \r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  UINT8   CaseFlag;\r
+  CHAR8   *File8Dot3Name;\r
+  CHAR16  TempExt[1 + FAT_EXTEND_NAME_LEN + 1];\r
+  //\r
+  // Store file extension like ".txt"\r
+  //\r
+  CaseFlag      = DirEnt->Entry.CaseFlag;\r
+  File8Dot3Name = DirEnt->Entry.FileName;\r
+\r
+  FatNameToStr (File8Dot3Name, FAT_MAIN_NAME_LEN, CaseFlag & FAT_CASE_NAME_LOWER, FileString);\r
+  FatNameToStr (File8Dot3Name + FAT_MAIN_NAME_LEN, FAT_EXTEND_NAME_LEN, CaseFlag & FAT_CASE_EXT_LOWER, &TempExt[1]);\r
+  if (TempExt[1] != 0) {\r
+    TempExt[0] = L'.';\r
+    EfiStrCat (FileString, TempExt);\r
+  }\r
+}\r
+\r
+UINT8\r
+FatCheckSum (\r
+  IN CHAR8  *ShortNameString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get the Check sum for a short name.\r
+  \r
+Arguments:\r
+\r
+  ShortNameString       - The short name for a file.\r
+\r
+Returns: \r
+\r
+  Sum                   - UINT8 checksum.\r
+  \r
+--*/\r
+{\r
+  UINTN ShortNameLen;\r
+  UINT8 Sum;\r
+  Sum = 0;\r
+  for (ShortNameLen = FAT_NAME_LEN; ShortNameLen != 0; ShortNameLen--) {\r
+    Sum = ((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *ShortNameString++;\r
+  }\r
+\r
+  return Sum;\r
+}\r
+\r
+CHAR16 *\r
+FatGetNextNameComponent (\r
+  IN  CHAR16      *Path,\r
+  OUT CHAR16      *Name\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Takes Path as input, returns the next name component\r
+  in Name, and returns the position after Name (e.g., the\r
+  start of the next name component)\r
+    \r
+Arguments:\r
+\r
+  Path                  - The path of one file.\r
+  Name                  - The next name component in Path.\r
+\r
+Returns: \r
+\r
+  The position after Name in the Path\r
+   \r
+--*/\r
+{\r
+  while (*Path != 0 && *Path != PATH_NAME_SEPARATOR) {\r
+    *Name++ = *Path++;\r
+  }\r
+  *Name = 0;\r
+  //\r
+  // Get off of trailing path name separator\r
+  //\r
+  while (*Path == PATH_NAME_SEPARATOR) {\r
+    Path++;\r
+  }\r
+\r
+  return Path;\r
+}\r
+\r
+BOOLEAN\r
+FatFileNameIsValid (\r
+  IN  CHAR16  *InputFileName,\r
+  OUT CHAR16  *OutputFileName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check whether the IFileName is valid long file name. If the IFileName is a valid\r
+  long file name, then we trim the possible leading blanks and leading/trailing dots.\r
+  the trimmed filename is stored in OutputFileName\r
+  \r
+Arguments:\r
+\r
+  InputFileName         - The input file name.\r
+  OutputFileName        - The output file name.\r
\r
+  \r
+Returns: \r
+\r
+  TRUE                  - The InputFileName is a valid long file name.\r
+  FALSE                 - The InputFileName is not a valid long file name.\r
+  \r
+--*/\r
+{\r
+  CHAR16  *TempNamePointer;\r
+  CHAR16  TempChar;\r
+  //\r
+  // Trim Leading blanks\r
+  //\r
+  while (*InputFileName == L' ') {\r
+    InputFileName++;\r
+  }\r
+\r
+  TempNamePointer = OutputFileName;\r
+  while (*InputFileName != 0) {\r
+    *TempNamePointer++ = *InputFileName++;\r
+  }\r
+  //\r
+  // Trim Trailing blanks and dots\r
+  //\r
+  while (TempNamePointer > OutputFileName) {\r
+    TempChar = *(TempNamePointer - 1);\r
+    if (TempChar != L' ' && TempChar != L'.') {\r
+      break;\r
+    }\r
+\r
+    TempNamePointer--;\r
+  }\r
+\r
+  *TempNamePointer = 0;\r
+  //\r
+  // See if there is any illegal characters within the name\r
+  //\r
+  do {\r
+    if (*OutputFileName < 0x20 ||\r
+        *OutputFileName == '\"' ||\r
+        *OutputFileName == '*' ||\r
+        *OutputFileName == '/' ||\r
+        *OutputFileName == ':' ||\r
+        *OutputFileName == '<' ||\r
+        *OutputFileName == '>' ||\r
+        *OutputFileName == '?' ||\r
+        *OutputFileName == '\\' ||\r
+        *OutputFileName == '|'\r
+        ) {\r
+      return FALSE;\r
+    }\r
+\r
+    OutputFileName++;\r
+  } while (*OutputFileName != 0);\r
+  return TRUE;\r
+}\r
diff --git a/EnhancedFat/Dxe/FileSpace.c b/EnhancedFat/Dxe/FileSpace.c
new file mode 100644 (file)
index 0000000..405d57e
--- /dev/null
@@ -0,0 +1,814 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  FileSpace.c\r
+  \r
+Abstract:\r
+\r
+  Routines dealing with disk spaces and FAT table entries\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+\r
+STATIC\r
+VOID *\r
+FatLoadFatEntry (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN UINTN            Index\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+   \r
+  Get the FAT entry of the volume, which is identified with the Index.\r
+     \r
+Arguments:\r
+  \r
+  Volume                - FAT file system volume.\r
+  Index                 - The index of the FAT entry of the volume.\r
+\r
+Returns:\r
+  \r
+  The buffer of the FAT entry\r
+    \r
+--*/\r
+{\r
+  UINTN       Pos;\r
+  EFI_STATUS  Status;\r
+\r
+  if (Index > (Volume->MaxCluster + 1)) {\r
+    Volume->FatEntryBuffer = (UINT32) -1;\r
+    return &Volume->FatEntryBuffer;\r
+  }\r
+  //\r
+  // Compute buffer position needed\r
+  //\r
+  switch (Volume->FatType) {\r
+  case FAT12:\r
+    Pos = FAT_POS_FAT12 (Index);\r
+    break;\r
+\r
+  case FAT16:\r
+    Pos = FAT_POS_FAT16 (Index);\r
+    break;\r
+\r
+  default:\r
+    Pos = FAT_POS_FAT32 (Index);\r
+  }\r
+  //\r
+  // Set the position and read the buffer\r
+  //\r
+  Volume->FatEntryPos = Volume->FatPos + Pos;\r
+  Status = FatDiskIo (\r
+             Volume,\r
+             READ_FAT,\r
+             Volume->FatEntryPos,\r
+             Volume->FatEntrySize,\r
+             &Volume->FatEntryBuffer\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    Volume->FatEntryBuffer = (UINT32) -1;\r
+  }\r
+\r
+  return &Volume->FatEntryBuffer;\r
+}\r
+\r
+STATIC\r
+UINTN\r
+FatGetFatEntry (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN UINTN            Index\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+   \r
+  Get the FAT entry value of the volume, which is identified with the Index.\r
+     \r
+Arguments:\r
+  \r
+  Volume                - FAT file system volume.\r
+  Index                 - The index of the FAT entry of the volume.\r
+\r
+Returns:\r
+  \r
+  The value of the FAT entry.\r
+    \r
+--*/\r
+{\r
+  VOID    *Pos;\r
+  UINT8   *E12;\r
+  UINT16  *E16;\r
+  UINT32  *E32;\r
+  UINTN   Accum;\r
+\r
+  Pos = FatLoadFatEntry (Volume, Index);\r
+\r
+  if (Index > (Volume->MaxCluster + 1)) {\r
+    return (UINTN) -1;\r
+  }\r
+\r
+  switch (Volume->FatType) {\r
+  case FAT12:\r
+    E12   = Pos;\r
+    Accum = E12[0] | (E12[1] << 8);\r
+    Accum = FAT_ODD_CLUSTER_FAT12 (Index) ? (Accum >> 4) : (Accum & FAT_CLUSTER_MASK_FAT12);\r
+    Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT12) ? FAT_CLUSTER_SPECIAL_EXT : 0);\r
+    break;\r
+\r
+  case FAT16:\r
+    E16   = Pos;\r
+    Accum = *E16;\r
+    Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT16) ? FAT_CLUSTER_SPECIAL_EXT : 0);\r
+    break;\r
+\r
+  default:\r
+    E32   = Pos;\r
+    Accum = *E32 & FAT_CLUSTER_MASK_FAT32;\r
+    Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT32) ? FAT_CLUSTER_SPECIAL_EXT : 0);\r
+  }\r
+\r
+  return Accum;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatSetFatEntry (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN UINTN            Index,\r
+  IN UINTN            Value\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+   \r
+  Set the FAT entry value of the volume, which is identified with the Index.\r
+     \r
+Arguments:\r
+  \r
+  Volume                - FAT file system volume.\r
+  Index                 - The index of the FAT entry of the volume.\r
+  Value                 - The new value of the FAT entry.\r
+\r
+Returns:\r
+  \r
+  EFI_SUCCESS           - Set the new FAT entry value sucessfully.\r
+  EFI_VOLUME_CORRUPTED  - The FAT type of the volume is error.\r
+  other                 - An error occurred when operation the FAT entries.\r
+    \r
+--*/\r
+{\r
+  VOID        *Pos;\r
+  UINT8       *E12;\r
+  UINT16      *E16;\r
+  UINT32      *E32;\r
+  UINTN       Accum;\r
+  EFI_STATUS  Status;\r
+  UINTN       OriginalVal;\r
+\r
+  if (Index < FAT_MIN_CLUSTER) {\r
+    return EFI_VOLUME_CORRUPTED;\r
+  }\r
+\r
+  OriginalVal = FatGetFatEntry (Volume, Index);\r
+  if (Value == FAT_CLUSTER_FREE && OriginalVal != FAT_CLUSTER_FREE) {\r
+    Volume->FatInfoSector.FreeInfo.ClusterCount += 1;\r
+    if (Index < Volume->FatInfoSector.FreeInfo.NextCluster) {\r
+      Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;\r
+    }\r
+  } else if (Value != FAT_CLUSTER_FREE && OriginalVal == FAT_CLUSTER_FREE) {\r
+    if (Volume->FatInfoSector.FreeInfo.ClusterCount != 0) {\r
+      Volume->FatInfoSector.FreeInfo.ClusterCount -= 1;\r
+    }\r
+  }\r
+  //\r
+  // Make sure the entry is in memory\r
+  //\r
+  Pos = FatLoadFatEntry (Volume, Index);\r
+\r
+  //\r
+  // Update the value\r
+  //\r
+  switch (Volume->FatType) {\r
+  case FAT12:\r
+    E12   = Pos;\r
+    Accum = E12[0] | (E12[1] << 8);\r
+    Value = Value & FAT_CLUSTER_MASK_FAT12;\r
+\r
+    if (FAT_ODD_CLUSTER_FAT12 (Index)) {\r
+      Accum = (Value << 4) | (Accum & 0xF);\r
+    } else {\r
+      Accum = Value | (Accum & FAT_CLUSTER_UNMASK_FAT12);\r
+    }\r
+\r
+    E12[0]  = (UINT8) (Accum & 0xFF);\r
+    E12[1]  = (UINT8) (Accum >> 8);\r
+    break;\r
+\r
+  case FAT16:\r
+    E16   = Pos;\r
+    *E16  = (UINT16) Value;\r
+    break;\r
+\r
+  default:\r
+    E32   = Pos;\r
+    *E32  = (*E32 & FAT_CLUSTER_UNMASK_FAT32) | (UINT32) (Value & FAT_CLUSTER_MASK_FAT32);\r
+  }\r
+  //\r
+  // If the volume's dirty bit is not set, set it now\r
+  //\r
+  if (!Volume->FatDirty && Volume->FatType != FAT12) {\r
+    Volume->FatDirty = TRUE;\r
+    FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->DirtyValue);\r
+  }\r
+  //\r
+  // Write the updated fat entry value to the volume\r
+  // The fat is the first fat, and other fat will be in sync\r
+  // when the FAT cache flush back.\r
+  //\r
+  Status = FatDiskIo (\r
+             Volume,\r
+             WRITE_FAT,\r
+             Volume->FatEntryPos,\r
+             Volume->FatEntrySize,\r
+             &Volume->FatEntryBuffer\r
+             );\r
+  return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatFreeClusters (\r
+  IN FAT_VOLUME           *Volume,\r
+  IN UINTN                Cluster\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Free the cluster clain.\r
+  \r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  Cluster               - The first cluster of cluster chain.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - The cluster chain is freed successfully.\r
+  EFI_VOLUME_CORRUPTED  - There are errors in the file's clusters.\r
+  \r
+--*/\r
+{\r
+  UINTN LastCluster;\r
+\r
+  while (!FAT_END_OF_FAT_CHAIN (Cluster)) {\r
+    if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {\r
+\r
+      DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));\r
+      return EFI_VOLUME_CORRUPTED;\r
+    }\r
+\r
+    LastCluster = Cluster;\r
+    Cluster     = FatGetFatEntry (Volume, Cluster);\r
+    FatSetFatEntry (Volume, LastCluster, FAT_CLUSTER_FREE);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+UINTN\r
+FatAllocateCluster (\r
+  IN FAT_VOLUME   *Volume\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+   \r
+  Allocate a free cluster and return the cluster index.\r
+     \r
+Arguments:\r
+  \r
+  Volume                - FAT file system volume.\r
+\r
+Returns:\r
+  \r
+  The index of the free cluster\r
+    \r
+--*/\r
+{\r
+  UINTN Cluster;\r
+\r
+  //\r
+  // Start looking at FatFreePos for the next unallocated cluster\r
+  //\r
+  if (Volume->DiskError) {\r
+    return (UINTN) FAT_CLUSTER_LAST;\r
+  }\r
+\r
+  for (;;) {\r
+    //\r
+    // If the end of the list, return no available cluster\r
+    //\r
+    if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {\r
+      if (Volume->FreeInfoValid && 0 < (INT32) (Volume->FatInfoSector.FreeInfo.ClusterCount)) {\r
+        Volume->FreeInfoValid = FALSE;\r
+      }\r
+\r
+      FatComputeFreeInfo (Volume);\r
+      if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {\r
+        return (UINTN) FAT_CLUSTER_LAST;\r
+      }\r
+    }\r
+\r
+    Cluster = FatGetFatEntry (Volume, Volume->FatInfoSector.FreeInfo.NextCluster);\r
+    if (Cluster == FAT_CLUSTER_FREE) {\r
+      break;\r
+    }\r
+    //\r
+    // Try the next cluster\r
+    //\r
+    Volume->FatInfoSector.FreeInfo.NextCluster += 1;\r
+  }\r
+\r
+  Cluster = Volume->FatInfoSector.FreeInfo.NextCluster;\r
+  Volume->FatInfoSector.FreeInfo.NextCluster += 1;\r
+  return Cluster;\r
+}\r
+\r
+STATIC\r
+UINTN\r
+FatSizeToClusters (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN UINTN            Size\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Count the number of clusters given a size\r
+  \r
+Arguments: \r
+\r
+  Volume                - The file system volume.\r
+  Size                  - The size in bytes.\r
+  \r
+Returns:\r
\r
+  The number of the clusters.\r
+  \r
+--*/\r
+{\r
+  UINTN Clusters;\r
+\r
+  Clusters = Size >> Volume->ClusterAlignment;\r
+  if ((Size & (Volume->ClusterSize - 1)) > 0) {\r
+    Clusters += 1;\r
+  }\r
+\r
+  return Clusters;\r
+}\r
+\r
+EFI_STATUS\r
+FatShrinkEof (\r
+  IN FAT_OFILE            *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Shrink the end of the open file base on the file size.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The open file.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - Shrinked sucessfully.\r
+  EFI_VOLUME_CORRUPTED  - There are errors in the file's clusters.\r
+  \r
+--*/\r
+{\r
+  FAT_VOLUME  *Volume;\r
+  FAT_DIRENT  *DirEnt;\r
+  UINTN       NewSize;\r
+  UINTN       CurSize;\r
+  UINTN       Cluster;\r
+  UINTN       LastCluster;\r
+\r
+  DirEnt  = OFile->DirEnt;\r
+  Volume  = OFile->Volume;\r
+  ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+  NewSize = FatSizeToClusters (Volume, OFile->FileSize);\r
+\r
+  //\r
+  // Find the address of the last cluster\r
+  //\r
+  Cluster     = OFile->FileCluster;\r
+  LastCluster = FAT_CLUSTER_FREE;\r
+\r
+  if (NewSize != 0) {\r
+\r
+    for (CurSize = 0; CurSize < NewSize; CurSize++) {\r
+      if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {\r
+\r
+        DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));\r
+        return EFI_VOLUME_CORRUPTED;\r
+      }\r
+\r
+      LastCluster = Cluster;\r
+      Cluster     = FatGetFatEntry (Volume, Cluster);\r
+    }\r
+\r
+    FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);\r
+\r
+  } else {\r
+    //\r
+    // Check to see if the file is already completely truncated\r
+    //\r
+    if (Cluster == FAT_CLUSTER_FREE) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // The file is being completely truncated.\r
+    //\r
+    OFile->FileCluster      = FAT_CLUSTER_FREE;\r
+  }\r
+  //\r
+  // Set CurrentCluster == FileCluster\r
+  // to force a recalculation of Position related stuffs\r
+  //\r
+  OFile->FileCurrentCluster = OFile->FileCluster;\r
+  OFile->FileLastCluster    = LastCluster;\r
+  OFile->Dirty              = TRUE;\r
+  //\r
+  // Free the remaining cluster chain\r
+  //\r
+  return FatFreeClusters (Volume, Cluster);\r
+}\r
+\r
+EFI_STATUS\r
+FatGrowEof (\r
+  IN FAT_OFILE            *OFile,\r
+  IN UINT64               NewSizeInBytes\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Grow the end of the open file base on the NewSizeInBytes.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The open file.\r
+  NewSizeInBytes        - The new size in bytes of the open file.\r
+\r
+Returns: \r
+\r
+  EFI_SUCCESS           - The file is grown sucessfully.\r
+  EFI_UNSUPPORTED       - The file size is larger than 4GB.\r
+  EFI_VOLUME_CORRUPTED  - There are errors in the files' clusters.\r
+  EFI_VOLUME_FULL       - The volume is full and can not grow the file.  \r
+\r
+--*/\r
+{\r
+  FAT_VOLUME  *Volume;\r
+  EFI_STATUS  Status;\r
+  UINTN       Cluster;\r
+  UINTN       CurSize;\r
+  UINTN       NewSize;\r
+  UINTN       LastCluster;\r
+  UINTN       NewCluster;\r
+  UINTN       ClusterCount;\r
+\r
+  //\r
+  // For FAT file system, the max file is 4GB.\r
+  //\r
+  if (NewSizeInBytes > 0x0FFFFFFFFL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Volume = OFile->Volume;\r
+  ASSERT_VOLUME_LOCKED (Volume);\r
+  //\r
+  // If the file is already large enough, do nothing\r
+  //\r
+  CurSize = FatSizeToClusters (Volume, OFile->FileSize);\r
+  NewSize = FatSizeToClusters (Volume, (UINTN) NewSizeInBytes);\r
+\r
+  if (CurSize < NewSize) {\r
+    //\r
+    // If we haven't found the files last cluster do it now\r
+    //\r
+    if ((OFile->FileCluster != 0) && (OFile->FileLastCluster == 0)) {\r
+      Cluster       = OFile->FileCluster;\r
+      ClusterCount  = 0;\r
+\r
+      while (!FAT_END_OF_FAT_CHAIN (Cluster)) {\r
+        if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {\r
+\r
+          DEBUG (\r
+            (EFI_D_INIT | EFI_D_ERROR,\r
+            "FatGrowEof: cluster chain corrupt\n")\r
+            );\r
+          Status = EFI_VOLUME_CORRUPTED;\r
+          goto Done;\r
+        }\r
+\r
+        ClusterCount++;\r
+        OFile->FileLastCluster  = Cluster;\r
+        Cluster                 = FatGetFatEntry (Volume, Cluster);\r
+      }\r
+\r
+      if (ClusterCount != CurSize) {\r
+        DEBUG (\r
+          (EFI_D_INIT | EFI_D_ERROR,\r
+          "FatGrowEof: cluster chain size does not match file size\n")\r
+          );\r
+        Status = EFI_VOLUME_CORRUPTED;\r
+        goto Done;\r
+      }\r
+\r
+    }\r
+    //\r
+    // Loop until we've allocated enough space\r
+    //\r
+    LastCluster = OFile->FileLastCluster;\r
+\r
+    while (CurSize < NewSize) {\r
+      NewCluster = FatAllocateCluster (Volume);\r
+      if (FAT_END_OF_FAT_CHAIN (NewCluster)) {\r
+        if (LastCluster != FAT_CLUSTER_FREE) {\r
+          FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);\r
+          OFile->FileLastCluster = LastCluster;\r
+        }\r
+\r
+        Status = EFI_VOLUME_FULL;\r
+        goto Done;\r
+      }\r
+\r
+      if (LastCluster != 0) {\r
+        FatSetFatEntry (Volume, LastCluster, NewCluster);\r
+      } else {\r
+        OFile->FileCluster        = NewCluster;\r
+        OFile->FileCurrentCluster = NewCluster;\r
+      }\r
+\r
+      LastCluster = NewCluster;\r
+      CurSize += 1;\r
+    }\r
+    //\r
+    // Terminate the cluster list\r
+    //\r
+    FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);\r
+    OFile->FileLastCluster = LastCluster;\r
+  }\r
+\r
+  OFile->FileSize = (UINTN) NewSizeInBytes;\r
+  OFile->Dirty    = TRUE;\r
+  return EFI_SUCCESS;\r
+\r
+Done:\r
+  FatShrinkEof (OFile);\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatOFilePosition (\r
+  IN FAT_OFILE            *OFile,\r
+  IN UINTN                Position,\r
+  IN UINTN                PosLimit\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Seek OFile to requested position, and calculate the number of\r
+  consecutive clusters from the position in the file\r
+\r
+Arguments:\r
+\r
+  OFile                 - The open file.\r
+  Position              - The file's position which will be accessed.\r
+  PosLimit              - The maximum length current reading/writing may access\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Set the info successfully.\r
+  EFI_VOLUME_CORRUPTED  - Cluster chain corrupt.\r
+\r
+--*/\r
+{\r
+  FAT_VOLUME  *Volume;\r
+  UINTN       ClusterSize;\r
+  UINTN       Cluster;\r
+  UINTN       StartPos;\r
+  UINTN       Run;\r
+\r
+  Volume      = OFile->Volume;\r
+  ClusterSize = Volume->ClusterSize;\r
+\r
+  ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+  //\r
+  // If this is the fixed root dir, then compute it's position\r
+  // from it's fixed info in the fat bpb\r
+  //\r
+  if (OFile->IsFixedRootDir) {\r
+    OFile->PosDisk  = Volume->RootPos + Position;\r
+    Run             = OFile->FileSize - Position;\r
+  } else {\r
+    //\r
+    // Run the file's cluster chain to find the current position\r
+    // If possible, run from the current cluster rather than\r
+    // start from beginning\r
+    // Assumption: OFile->Position is always consistent with\r
+    // OFile->FileCurrentCluster.\r
+    // OFile->Position is not modified outside this function;\r
+    // OFile->FileCurrentCluster is modified outside this function\r
+    // to be the same as OFile->FileCluster\r
+    // when OFile->FileCluster is updated, so make a check of this\r
+    // and invalidate the original OFile->Position in this case\r
+    //\r
+    Cluster     = OFile->FileCurrentCluster;\r
+    StartPos    = OFile->Position;\r
+    if (Position < StartPos || OFile->FileCluster == Cluster) {\r
+      StartPos  = 0;\r
+      Cluster   = OFile->FileCluster;\r
+    }\r
+\r
+    while (StartPos + ClusterSize <= Position) {\r
+      StartPos += ClusterSize;\r
+      if (Cluster == FAT_CLUSTER_FREE || (Cluster >= FAT_CLUSTER_SPECIAL)) {\r
+        DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatOFilePosition:"" cluster chain corrupt\n"));\r
+        return EFI_VOLUME_CORRUPTED;\r
+      }\r
+\r
+      Cluster = FatGetFatEntry (Volume, Cluster);\r
+    }\r
+\r
+    if (Cluster < FAT_MIN_CLUSTER) {\r
+      return EFI_VOLUME_CORRUPTED;\r
+    }\r
+\r
+    OFile->PosDisk            = Volume->FirstClusterPos + \r
+                                LShiftU64 (Cluster - FAT_MIN_CLUSTER, Volume->ClusterAlignment) + \r
+                                Position - StartPos;\r
+    OFile->FileCurrentCluster = Cluster;\r
+    OFile->Position           = StartPos;\r
+\r
+    //\r
+    // Compute the number of consecutive clusters in the file\r
+    //\r
+    Run = StartPos + ClusterSize - Position;\r
+    if (!FAT_END_OF_FAT_CHAIN (Cluster)) {\r
+      while ((FatGetFatEntry (Volume, Cluster) == Cluster + 1) && Run < PosLimit) {\r
+        Run     += ClusterSize;\r
+        Cluster += 1;\r
+      }\r
+    }\r
+  }\r
+\r
+  OFile->PosRem = Run;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+UINTN\r
+FatPhysicalDirSize (\r
+  IN FAT_VOLUME            *Volume,\r
+  IN UINTN                 Cluster\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the size of directory of the open file\r
+  \r
+Arguments:\r
+\r
+  Volume                - The File System Volume.\r
+  Cluster               - The Starting cluster.\r
+\r
+Returns: \r
+\r
+  The physical size of the file starting at the input cluster, if there is error in the \r
+  cluster chain, the return value is 0.\r
+  \r
+--*/\r
+{\r
+  UINTN Size;\r
+  ASSERT_VOLUME_LOCKED (Volume);\r
+  //\r
+  // Run the cluster chain for the OFile\r
+  //\r
+  Size = 0;\r
+  //\r
+  // N.B. ".." directories on some media do not contain a starting\r
+  // cluster.  In the case of "." or ".." we don't need the size anyway.\r
+  //\r
+  if (Cluster != 0) {\r
+    while (!FAT_END_OF_FAT_CHAIN (Cluster)) {\r
+      if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {\r
+        DEBUG (\r
+          (EFI_D_INIT | EFI_D_ERROR,\r
+          "FATDirSize: cluster chain corrupt\n")\r
+          );\r
+        return 0;\r
+      }\r
+\r
+      Size += Volume->ClusterSize;\r
+      Cluster = FatGetFatEntry (Volume, Cluster);\r
+    }\r
+  }\r
+\r
+  return Size;\r
+}\r
+\r
+UINT64\r
+FatPhysicalFileSize (\r
+  IN FAT_VOLUME            *Volume,\r
+  IN UINTN                 RealSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the physical size of a file on the disk.\r
+  \r
+Arguments:\r
+\r
+  Volume                - The file system volume.\r
+  RealSize              - The real size of a file.\r
+\r
+Returns: \r
+\r
+  The physical size of a file on the disk.\r
+  \r
+--*/\r
+{\r
+  UINTN   ClusterSizeMask;\r
+  UINT64  PhysicalSize;\r
+  ClusterSizeMask = Volume->ClusterSize - 1;\r
+  PhysicalSize    = (RealSize + ClusterSizeMask) & (~((UINT64) ClusterSizeMask));\r
+  return PhysicalSize;\r
+}\r
+\r
+VOID\r
+FatComputeFreeInfo (\r
+  IN FAT_VOLUME *Volume\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+   \r
+  Update the free cluster info of FatInfoSector of the volume.\r
+     \r
+Arguments:\r
+  \r
+  Volume                - FAT file system volume.\r
+\r
+Returns:\r
+  \r
+  None.\r
+      \r
+--*/\r
+{\r
+  UINTN Index;\r
+\r
+  //\r
+  // If we don't have valid info, compute it now\r
+  //\r
+  if (!Volume->FreeInfoValid) {\r
+\r
+    Volume->FreeInfoValid                        = TRUE;\r
+    Volume->FatInfoSector.FreeInfo.ClusterCount  = 0;\r
+    for (Index = Volume->MaxCluster + 1; Index >= FAT_MIN_CLUSTER; Index--) {\r
+      if (Volume->DiskError) {\r
+        break;\r
+      }\r
+\r
+      if (FatGetFatEntry (Volume, Index) == FAT_CLUSTER_FREE) {\r
+        Volume->FatInfoSector.FreeInfo.ClusterCount += 1;\r
+        Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;\r
+      }\r
+    }\r
+\r
+    Volume->FatInfoSector.Signature          = FAT_INFO_SIGNATURE;\r
+    Volume->FatInfoSector.InfoBeginSignature = FAT_INFO_BEGIN_SIGNATURE;\r
+    Volume->FatInfoSector.InfoEndSignature   = FAT_INFO_END_SIGNATURE;\r
+  }\r
+}\r
diff --git a/EnhancedFat/Dxe/Flush.c b/EnhancedFat/Dxe/Flush.c
new file mode 100644 (file)
index 0000000..b8e0647
--- /dev/null
@@ -0,0 +1,481 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  flush.c\r
+\r
+Abstract:\r
+\r
+  Routines that check references and flush OFiles\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatFlush (\r
+  IN EFI_FILE  *FHand\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Flushes all data associated with the file handle.\r
+\r
+Arguments:\r
+\r
+  FHand                 - Handle to file to flush.\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS           - Flushed the file successfully.\r
+  EFI_WRITE_PROTECTED   - The volume is read only.\r
+  EFI_ACCESS_DENIED     - The file is read only.\r
+  Others                - Flushing of the file failed.\r
+\r
+--*/\r
+{\r
+  FAT_IFILE   *IFile;\r
+  FAT_OFILE   *OFile;\r
+  FAT_VOLUME  *Volume;\r
+  EFI_STATUS  Status;\r
+\r
+  IFile   = IFILE_FROM_FHAND (FHand);\r
+  OFile   = IFile->OFile;\r
+  Volume  = OFile->Volume;\r
+\r
+  //\r
+  // If the file has a permanent error, return it\r
+  //\r
+  if (EFI_ERROR (OFile->Error)) {\r
+    return OFile->Error;\r
+  }\r
+\r
+  if (Volume->ReadOnly) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+  //\r
+  // If read only, return error\r
+  //\r
+  if (IFile->ReadOnly) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  //\r
+  // Flush the OFile\r
+  //\r
+  FatAcquireLock ();\r
+  Status  = FatOFileFlush (OFile);\r
+  Status  = FatCleanupVolume (OFile->Volume, OFile, Status);\r
+  FatReleaseLock ();\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatClose (\r
+  IN EFI_FILE  *FHand\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Flushes & Closes the file handle.\r
+  \r
+Arguments:\r
+\r
+  FHand                 - Handle to the file to delete.\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS           - Closed the file successfully.\r
+\r
+--*/\r
+{\r
+  FAT_IFILE   *IFile;\r
+  FAT_OFILE   *OFile;\r
+  FAT_VOLUME  *Volume;\r
+\r
+  IFile   = IFILE_FROM_FHAND (FHand);\r
+  OFile   = IFile->OFile;\r
+  Volume  = OFile->Volume;\r
+\r
+  //\r
+  // Lock the volume\r
+  //\r
+  FatAcquireLock ();\r
+\r
+  //\r
+  // Close the file instance handle\r
+  //\r
+  FatIFileClose (IFile);\r
+\r
+  //\r
+  // Done. Unlock the volume\r
+  //\r
+  FatCleanupVolume (Volume, OFile, EFI_SUCCESS);\r
+  FatReleaseLock ();\r
+\r
+  //\r
+  // Close always succeed\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatIFileClose (\r
+  FAT_IFILE           *IFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Close the open file instance.\r
+  \r
+Arguments:\r
+\r
+  IFile                 - Open file instance.\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS           - Closed the file successfully.\r
+\r
+--*/\r
+{\r
+  FAT_OFILE   *OFile;\r
+  FAT_VOLUME  *Volume;\r
+\r
+  OFile   = IFile->OFile;\r
+  Volume  = OFile->Volume;\r
+\r
+  ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+  //\r
+  // Remove the IFile struct\r
+  //\r
+  RemoveEntryList (&IFile->Link);\r
+\r
+  //\r
+  // Add the OFile to the check reference list\r
+  //\r
+  if (OFile->CheckLink.ForwardLink == NULL) {\r
+    InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);\r
+  }\r
+  //\r
+  // Done. Free the open instance structure\r
+  //\r
+  gBS->FreePool (IFile);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatOFileFlush (\r
+  IN FAT_OFILE    *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Flush the data associated with an open file.\r
+  In this implementation, only last Mod/Access time is updated.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The open file.\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS           - The OFile is flushed successfully.\r
+  Others                - An error occurred when flushing this OFile.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS    Status;\r
+  FAT_OFILE     *Parent;\r
+  FAT_DIRENT    *DirEnt;\r
+  FAT_DATE_TIME FatNow;\r
+\r
+  //\r
+  // Flush each entry up the tree while dirty\r
+  //\r
+  do {\r
+    //\r
+    // If the file has a permanant error, then don't write any\r
+    // of its data to the device (may be from different media)\r
+    //\r
+    if (EFI_ERROR (OFile->Error)) {\r
+      return OFile->Error;\r
+    }\r
+\r
+    Parent  = OFile->Parent;\r
+    DirEnt  = OFile->DirEnt;\r
+    if (OFile->Dirty) {\r
+      //\r
+      // Update the last modification time\r
+      //\r
+      FatGetCurrentFatTime (&FatNow);\r
+      EfiCopyMem (&DirEnt->Entry.FileLastAccess, &FatNow.Date, sizeof (FAT_DATE));\r
+      if (!OFile->PreserveLastModification) {\r
+        FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime);\r
+      }\r
+\r
+      OFile->PreserveLastModification = FALSE;\r
+      if (OFile->Archive) {\r
+        DirEnt->Entry.Attributes |= FAT_ATTRIBUTE_ARCHIVE;\r
+        OFile->Archive = FALSE;\r
+      }\r
+      //\r
+      // Write the directory entry\r
+      //\r
+      if (Parent != NULL && !DirEnt->Invalid) {\r
+        //\r
+        // Write the OFile's directory entry\r
+        //\r
+        Status = FatStoreDirEnt (Parent, DirEnt);\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+      }\r
+\r
+      OFile->Dirty = FALSE;\r
+    }\r
+    //\r
+    // Check the parent\r
+    //\r
+    OFile = Parent;\r
+  } while (OFile != NULL);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+FatCheckOFileRef (\r
+  IN FAT_OFILE   *OFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check the references of the OFile.\r
+  If the OFile (that is checked) is no longer\r
+  referenced, then it is freed.\r
+  \r
+Arguments:\r
+\r
+  OFile                 - The OFile to be checked.\r
+  \r
+Returns:\r
+\r
+  TRUE                  - The OFile is not referenced and freed.\r
+  FALSE                 - The OFile is kept.\r
+\r
+--*/\r
+{\r
+  //\r
+  // If the OFile is on the check ref list, remove it\r
+  //\r
+  if (OFile->CheckLink.ForwardLink != NULL) {\r
+    RemoveEntryList (&OFile->CheckLink);\r
+    OFile->CheckLink.ForwardLink = NULL;\r
+  }\r
+\r
+  FatOFileFlush (OFile);\r
+  //\r
+  // Are there any references to this OFile?\r
+  //\r
+  if (!IsListEmpty (&OFile->Opens) || !IsListEmpty (&OFile->ChildHead)) {\r
+    //\r
+    // The OFile cannot be freed\r
+    //\r
+    return FALSE;\r
+  }\r
+  //\r
+  // Free the Ofile\r
+  //\r
+  FatCloseDirEnt (OFile->DirEnt);\r
+  return TRUE;\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatCheckVolumeRef (\r
+  IN FAT_VOLUME   *Volume\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Check the references of all open files on the volume.\r
+  Any open file (that is checked) that is no longer\r
+  referenced, is freed - and it's parent open file\r
+  is then referenced checked.\r
+  \r
+Arguments:\r
+\r
+  Volume                - The volume to check the pending open file list.\r
+  \r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  FAT_OFILE *OFile;\r
+  FAT_OFILE *Parent;\r
+\r
+  //\r
+  // Check all files on the pending check list\r
+  //\r
+  while (!IsListEmpty (&Volume->CheckRef)) {\r
+    //\r
+    // Start with the first file listed\r
+    //\r
+    Parent = OFILE_FROM_CHECKLINK (Volume->CheckRef.ForwardLink);\r
+    //\r
+    // Go up the tree cleaning up any un-referenced OFiles\r
+    //\r
+    while (Parent != NULL) {\r
+      OFile   = Parent;\r
+      Parent  = OFile->Parent;\r
+      if (!FatCheckOFileRef (OFile)) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+FatCleanupVolume (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN FAT_OFILE        *OFile,\r
+  IN EFI_STATUS       EfiStatus\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set error status for a specific OFile, reference checking the volume.\r
+  If volume is already marked as invalid, and all resources are freed \r
+  after reference checking, the file system protocol is uninstalled and\r
+  the volume structure is freed.\r
+  \r
+Arguments:\r
+\r
+  Volume                - the Volume that is to be reference checked and unlocked.\r
+  OFile                 - the OFile whose permanent error code is to be set.\r
+  EfiStatus             - error code to be set.\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS           - Clean up the volume successfully.\r
+  Others                - Cleaning up of the volume is failed.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  //\r
+  // Flag the OFile\r
+  //\r
+  if (OFile != NULL) {\r
+    FatSetVolumeError (OFile, EfiStatus);\r
+  }\r
+  //\r
+  // Clean up any dangling OFiles that don't have IFiles\r
+  // we don't check return status here because we want the\r
+  // volume be cleaned up even the volume is invalid.\r
+  //\r
+  FatCheckVolumeRef (Volume);\r
+  if (Volume->Valid) {\r
+    //\r
+    // Update the free hint info. Volume->FreeInfoPos != 0\r
+    // indicates this a FAT32 volume\r
+    //\r
+    if (Volume->FreeInfoValid && Volume->FatDirty && Volume->FreeInfoPos) {\r
+      Status = FatDiskIo (Volume, WRITE_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+    //\r
+    // Update that the volume is not dirty\r
+    //\r
+    if (Volume->FatDirty && Volume->FatType != FAT12) {\r
+      Volume->FatDirty  = FALSE;\r
+      Status            = FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->NotDirtyValue);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+    //\r
+    // Flush all dirty cache entries to disk\r
+    //\r
+    FatVolumeFlushCache (Volume);\r
+\r
+    //\r
+    // Flush block device\r
+    //\r
+    Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // If the volume is cleared , remove it.\r
+  // The only time volume be invalidated is in DriverBindingStop.\r
+  //\r
+  if (Volume->Root == NULL && !Volume->Valid) {\r
+    //\r
+    // Free the volume structure\r
+    //\r
+    FatFreeVolume (Volume);\r
+  }\r
+\r
+  return EfiStatus;\r
+}\r
+\r
+VOID\r
+FatSetVolumeError (\r
+  IN FAT_OFILE            *OFile,\r
+  IN EFI_STATUS           Status\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set the OFile and its child OFile with the error Status\r
+\r
+Arguments:\r
+\r
+  OFile                 - The OFile whose permanent error code is to be set.\r
+  Status                - Error code to be set.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  EFI_LIST_ENTRY  *Link;\r
+  FAT_OFILE       *ChildOFile;\r
+\r
+  //\r
+  // If this OFile doesn't already have an error, set one\r
+  //\r
+  if (!EFI_ERROR (OFile->Error)) {\r
+    OFile->Error = Status;\r
+  }\r
+  //\r
+  // Set the error on each child OFile\r
+  //\r
+  for (Link = OFile->ChildHead.ForwardLink; Link != &OFile->ChildHead; Link = Link->ForwardLink) {\r
+    ChildOFile = OFILE_FROM_CHILDLINK (Link);\r
+    FatSetVolumeError (ChildOFile, Status);\r
+  }\r
+}\r
diff --git a/EnhancedFat/Dxe/Hash.c b/EnhancedFat/Dxe/Hash.c
new file mode 100644 (file)
index 0000000..81cd873
--- /dev/null
@@ -0,0 +1,213 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  Hash.c\r
+  \r
+Abstract:\r
+\r
+  Hash table operations\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+STATIC\r
+UINT32\r
+FatHashLongName (\r
+  IN CHAR16   *LongNameString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get hash value for long name.\r
+  \r
+Arguments:\r
+\r
+  LongNameString        - The long name string to be hashed.\r
+\r
+Returns:\r
+\r
+  HashValue.\r
+  \r
+--*/\r
+{\r
+  UINT32  HashValue;\r
+  CHAR16  UpCasedLongFileName[EFI_FILE_STRING_LENGTH + 1];\r
+  EfiStrCpy (UpCasedLongFileName, LongNameString);\r
+  FatStrUpr (UpCasedLongFileName);\r
+  gBS->CalculateCrc32 (UpCasedLongFileName, EfiStrSize (UpCasedLongFileName), &HashValue);\r
+  return (HashValue & HASH_TABLE_MASK);\r
+}\r
+\r
+STATIC\r
+UINT32\r
+FatHashShortName (\r
+  IN CHAR8   *ShortNameString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get hash value for short name.\r
+  \r
+Arguments:\r
+\r
+  ShortNameString       - The short name string to be hashed.\r
+\r
+Returns: \r
+\r
+  HashValue\r
+  \r
+--*/\r
+{\r
+  UINT32  HashValue;\r
+  gBS->CalculateCrc32 (ShortNameString, FAT_NAME_LEN, &HashValue);\r
+  return (HashValue & HASH_TABLE_MASK);\r
+}\r
+\r
+FAT_DIRENT **\r
+FatLongNameHashSearch (\r
+  IN FAT_ODIR       *ODir,\r
+  IN CHAR16         *LongNameString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Search the long name hash table for the directory entry.\r
+  \r
+Arguments:\r
+\r
+  ODir                  - The directory to be searched.\r
+  LongNameString        - The long name string to search.\r
+\r
+Returns: \r
+\r
+  The previous long name hash node of the directory entry.\r
+  \r
+--*/\r
+{\r
+  FAT_DIRENT  **PreviousHashNode;\r
+  for (PreviousHashNode   = &ODir->LongNameHashTable[FatHashLongName (LongNameString)];\r
+       *PreviousHashNode != NULL;\r
+       PreviousHashNode   = &(*PreviousHashNode)->LongNameForwardLink\r
+      ) {\r
+    if (FatStriCmp (LongNameString, (*PreviousHashNode)->FileString) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  return PreviousHashNode;\r
+}\r
+\r
+FAT_DIRENT **\r
+FatShortNameHashSearch (\r
+  IN FAT_ODIR      *ODir,\r
+  IN CHAR8         *ShortNameString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Search the short name hash table for the directory entry.\r
+  \r
+Arguments:\r
+\r
+  ODir                  - The directory to be searched.\r
+  ShortNameString       - The short name string to search.\r
+\r
+Returns: \r
+\r
+  The previous short name hash node of the directory entry.\r
+  \r
+--*/\r
+{\r
+  FAT_DIRENT  **PreviousHashNode;\r
+  for (PreviousHashNode   = &ODir->ShortNameHashTable[FatHashShortName (ShortNameString)];\r
+       *PreviousHashNode != NULL;\r
+       PreviousHashNode   = &(*PreviousHashNode)->ShortNameForwardLink\r
+      ) {\r
+    if (EfiCompareMem (ShortNameString, (*PreviousHashNode)->Entry.FileName, FAT_NAME_LEN) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  return PreviousHashNode;\r
+}\r
+\r
+VOID\r
+FatInsertToHashTable (\r
+  IN FAT_ODIR     *ODir,\r
+  IN FAT_DIRENT   *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Insert directory entry to hash table. \r
+  \r
+Arguments:\r
+\r
+  ODir                  - The parent directory.\r
+  DirEnt                - The directory entry node.\r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  FAT_DIRENT  **HashTable;\r
+  UINT32      HashTableIndex;\r
+  \r
+  //\r
+  // Insert hash table index for short name\r
+  //\r
+  HashTableIndex                = FatHashShortName (DirEnt->Entry.FileName);\r
+  HashTable                     = ODir->ShortNameHashTable;\r
+  DirEnt->ShortNameForwardLink  = HashTable[HashTableIndex];\r
+  HashTable[HashTableIndex]     = DirEnt;\r
+  //\r
+  // Insert hash table index for long name\r
+  //\r
+  HashTableIndex                = FatHashLongName (DirEnt->FileString);\r
+  HashTable                     = ODir->LongNameHashTable;\r
+  DirEnt->LongNameForwardLink   = HashTable[HashTableIndex];\r
+  HashTable[HashTableIndex]     = DirEnt;\r
+}\r
+\r
+VOID\r
+FatDeleteFromHashTable (\r
+  IN FAT_ODIR     *ODir,\r
+  IN FAT_DIRENT   *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Delete directory entry from hash table.\r
+  \r
+Arguments:\r
+\r
+  ODir                  - The parent directory.\r
+  DirEnt                - The directory entry node.\r
+\r
+Returns: \r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  *FatShortNameHashSearch (ODir, DirEnt->Entry.FileName) = DirEnt->ShortNameForwardLink;\r
+  *FatLongNameHashSearch (ODir, DirEnt->FileString)      = DirEnt->LongNameForwardLink;\r
+}\r
diff --git a/EnhancedFat/Dxe/Info.c b/EnhancedFat/Dxe/Info.c
new file mode 100644 (file)
index 0000000..30148fc
--- /dev/null
@@ -0,0 +1,621 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  Info.c\r
+  \r
+Abstract:\r
+\r
+  Routines dealing with setting/getting file/volume info\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+FatGetVolumeInfo (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN OUT UINTN        *BufferSize,\r
+  OUT VOID            *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+FatSetVolumeInfo (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN OUT UINTN        BufferSize,\r
+  OUT VOID            *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+FatSetOrGetInfo (\r
+  IN BOOLEAN    IsSet,\r
+  IN EFI_FILE   *FHand,\r
+  IN EFI_GUID   *Type,\r
+  IN OUT UINTN  *BufferSize,\r
+  IN OUT VOID   *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+FatGetFileInfo (\r
+  IN FAT_OFILE        *OFile,\r
+  IN OUT UINTN        *BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Get the open file's info into Buffer.\r
+\r
+Arguments:\r
+\r
+  OFile                 - The open file.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing file info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get the file info successfully.\r
+  EFI_BUFFER_TOO_SMALL  - The buffer is too small.\r
+\r
+--*/\r
+{\r
+  return FatGetDirEntInfo (OFile->Volume, OFile->DirEnt, BufferSize, Buffer);\r
+}\r
+\r
+EFI_STATUS\r
+FatGetVolumeInfo (\r
+  IN     FAT_VOLUME     *Volume,\r
+  IN OUT UINTN          *BufferSize,\r
+     OUT VOID           *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Get the volume's info into Buffer.\r
+\r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get the volume info successfully.\r
+  EFI_BUFFER_TOO_SMALL  - The buffer is too small.\r
+\r
+--*/\r
+{\r
+  UINTN                 Size;\r
+  UINTN                 NameSize;\r
+  UINTN                 ResultSize;\r
+  CHAR16                Name[FAT_NAME_LEN + 1];\r
+  EFI_STATUS            Status;\r
+  EFI_FILE_SYSTEM_INFO  *Info;\r
+  UINT8                 ClusterAlignment;\r
+\r
+  Size              = SIZE_OF_EFI_FILE_SYSTEM_INFO;\r
+  Status            = FatGetVolumeEntry (Volume, Name);\r
+  NameSize          = EfiStrSize (Name);\r
+  ResultSize        = Size + NameSize;\r
+  ClusterAlignment  = Volume->ClusterAlignment;\r
+\r
+  //\r
+  // If we don't have valid info, compute it now\r
+  //\r
+  FatComputeFreeInfo (Volume);\r
+\r
+  Status = EFI_BUFFER_TOO_SMALL;\r
+  if (*BufferSize >= ResultSize) {\r
+    Status  = EFI_SUCCESS;\r
+\r
+    Info    = Buffer;\r
+    EfiZeroMem (Info, SIZE_OF_EFI_FILE_SYSTEM_INFO);\r
+\r
+    Info->Size        = ResultSize;\r
+    Info->ReadOnly    = Volume->ReadOnly;\r
+    Info->BlockSize   = (UINT32) Volume->ClusterSize;\r
+    Info->VolumeSize  = LShiftU64 (Volume->MaxCluster, ClusterAlignment);\r
+    Info->FreeSpace   = LShiftU64 (\r
+                          Volume->FatInfoSector.FreeInfo.ClusterCount,\r
+                          ClusterAlignment\r
+                          );\r
+    EfiCopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);\r
+  }\r
+\r
+  *BufferSize = ResultSize;\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatGetVolumeLabelInfo (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN OUT UINTN        *BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Get the volume's label info into Buffer.\r
+\r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing volume's label info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get the volume's label info successfully.\r
+  EFI_BUFFER_TOO_SMALL  - The buffer is too small.\r
+\r
+--*/\r
+{\r
+  UINTN                             Size;\r
+  UINTN                             NameSize;\r
+  UINTN                             ResultSize;\r
+  CHAR16                            Name[FAT_NAME_LEN + 1];\r
+  EFI_STATUS                        Status;\r
+\r
+  Size        = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO;\r
+  Status      = FatGetVolumeEntry (Volume, Name);\r
+  NameSize    = EfiStrSize (Name);\r
+  ResultSize  = Size + NameSize;\r
+\r
+  Status      = EFI_BUFFER_TOO_SMALL;\r
+  if (*BufferSize >= ResultSize) {\r
+    Status  = EFI_SUCCESS;\r
+    EfiCopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);\r
+  }\r
+\r
+  *BufferSize = ResultSize;\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatSetVolumeInfo (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN UINTN            BufferSize,\r
+  IN VOID             *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Set the volume's info.\r
+\r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing the new volume info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Set the volume info successfully.\r
+  EFI_BAD_BUFFER_SIZE   - The buffer size is error.\r
+  EFI_WRITE_PROTECTED   - The volume is read only.\r
+  other                 - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+  EFI_FILE_SYSTEM_INFO  *Info;\r
+\r
+  Info = (EFI_FILE_SYSTEM_INFO *) Buffer;\r
+\r
+  if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + 2 || Info->Size > BufferSize) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  return FatSetVolumeEntry (Volume, Info->VolumeLabel);\r
+}\r
+\r
+EFI_STATUS\r
+FatSetVolumeLabelInfo (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN UINTN            BufferSize,\r
+  IN VOID             *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Set the volume's label info\r
+\r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing the new volume label info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Set the volume label info successfully.\r
+  EFI_WRITE_PROTECTED   - The disk is write protected.\r
+  EFI_BAD_BUFFER_SIZE   - The buffer size is error.\r
+  other                 - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+  EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Info;\r
+\r
+  Info = (EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *) Buffer;\r
+\r
+  if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 2) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  return FatSetVolumeEntry (Volume, Info->VolumeLabel);\r
+}\r
+\r
+EFI_STATUS\r
+FatSetFileInfo (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN FAT_IFILE        *IFile,\r
+  IN FAT_OFILE        *OFile,\r
+  IN UINTN            BufferSize,\r
+  IN VOID             *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Set the file info.\r
+\r
+Arguments:\r
+\r
+  Volume                - FAT file system volume.\r
+  IFile                 - The instance of the open file.\r
+  OFile                 - The open file.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing the new file info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Set the file info successfully.\r
+  EFI_ACCESS_DENIED     - It is the root directory\r
+                          or the directory attribute bit can not change \r
+                          or try to change a directory size\r
+                          or something else.\r
+  EFI_UNSUPPORTED       - The new file size is larger than 4GB.\r
+  EFI_WRITE_PROTECTED   - The disk is write protected.\r
+  EFI_BAD_BUFFER_SIZE   - The buffer size is error.\r
+  EFI_INVALID_PARAMETER - The time info or attributes info is error.\r
+  EFI_OUT_OF_RESOURCES  - Can not allocate new memory.\r
+  EFI_VOLUME_CORRUPTED  - The volume is corrupted.\r
+  other                 - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_FILE_INFO *NewInfo;\r
+  FAT_OFILE     *DotOFile;\r
+  FAT_OFILE     *Parent;\r
+  CHAR16        NewFileName[EFI_FILE_STRING_LENGTH + 1];\r
+  EFI_TIME      ZeroTime;\r
+  FAT_DIRENT    *DirEnt;\r
+  FAT_DIRENT    *TempDirEnt;\r
+  UINT8         NewAttribute;\r
+  BOOLEAN       ReadOnly;\r
+\r
+  EfiZeroMem (&ZeroTime, sizeof (EFI_TIME));\r
+  Parent  = OFile->Parent;\r
+  DirEnt  = OFile->DirEnt;\r
+  //\r
+  // If this is the root directory, we can't make any updates\r
+  //\r
+  if (Parent == NULL) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  //\r
+  // Make sure there's a valid input buffer\r
+  //\r
+  NewInfo = Buffer;\r
+  if (BufferSize < SIZE_OF_EFI_FILE_INFO + 2 || NewInfo->Size > BufferSize) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  ReadOnly = IFile->ReadOnly || (DirEnt->Entry.Attributes & EFI_FILE_READ_ONLY);\r
+  //\r
+  // if a zero time is specified, then the original time is preserved\r
+  //\r
+  if (EfiCompareMem (&ZeroTime, &NewInfo->CreateTime, sizeof (EFI_TIME)) != 0) {\r
+    if (!FatIsValidTime (&NewInfo->CreateTime)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (!ReadOnly) {\r
+      FatEfiTimeToFatTime (&NewInfo->CreateTime, &DirEnt->Entry.FileCreateTime);\r
+    }\r
+  }\r
+\r
+  if (EfiCompareMem (&ZeroTime, &NewInfo->ModificationTime, sizeof (EFI_TIME)) != 0) {\r
+    if (!FatIsValidTime (&NewInfo->ModificationTime)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (!ReadOnly) {\r
+      FatEfiTimeToFatTime (&NewInfo->ModificationTime, &DirEnt->Entry.FileModificationTime);\r
+    }\r
+\r
+    OFile->PreserveLastModification = TRUE;\r
+  }\r
+\r
+  if (NewInfo->Attribute & (~EFI_FILE_VALID_ATTR)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NewAttribute = (UINT8) NewInfo->Attribute;\r
+  //\r
+  // Can not change the directory attribute bit\r
+  //\r
+  if ((NewAttribute ^ DirEnt->Entry.Attributes) & EFI_FILE_DIRECTORY) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  //\r
+  // Set the current attributes even if the IFile->ReadOnly is TRUE\r
+  //\r
+  DirEnt->Entry.Attributes = (UINT8) ((DirEnt->Entry.Attributes &~EFI_FILE_VALID_ATTR) | NewAttribute);\r
+  //\r
+  // Open the filename and see if it refers to an existing file\r
+  //\r
+  Status = FatLocateOFile (&Parent, NewInfo->FileName, DirEnt->Entry.Attributes, NewFileName);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (*NewFileName != 0) {\r
+    //\r
+    // File was not found.  We do not allow rename of the current directory if\r
+    // there are open files below the current directory\r
+    //\r
+    if (!IsListEmpty (&OFile->ChildHead) || Parent == OFile) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+\r
+    if (ReadOnly) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+\r
+    Status = FatRemoveDirEnt (OFile->Parent, DirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Create new dirent\r
+    //\r
+    Status = FatCreateDirEnt (Parent, NewFileName, DirEnt->Entry.Attributes, &TempDirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    FatCloneDirEnt (TempDirEnt, DirEnt);\r
+    FatFreeDirEnt (DirEnt);\r
+    DirEnt        = TempDirEnt;\r
+    DirEnt->OFile = OFile;\r
+    OFile->DirEnt = DirEnt;\r
+    OFile->Parent = Parent;\r
+    RemoveEntryList (&OFile->ChildLink);\r
+    InsertHeadList (&Parent->ChildHead, &OFile->ChildLink);\r
+    //\r
+    // If this is a directory, synchronize its dot directory entry\r
+    //\r
+    if (OFile->ODir != NULL) {\r
+      //\r
+      // Syncronize its dot entry\r
+      //\r
+      FatResetODirCursor (OFile);\r
+      ASSERT (OFile->Parent != NULL);\r
+      for (DotOFile = OFile; DotOFile != OFile->Parent->Parent; DotOFile = DotOFile->Parent) {\r
+        Status = FatGetNextDirEnt (OFile, &DirEnt);\r
+        if (EFI_ERROR (Status) || DirEnt == NULL || !FatIsDotDirEnt (DirEnt)) {\r
+          return EFI_VOLUME_CORRUPTED;\r
+        }\r
+\r
+        FatCloneDirEnt (DirEnt, DotOFile->DirEnt);\r
+        Status = FatStoreDirEnt (OFile, DirEnt);\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+      }\r
+    }\r
+    //\r
+    // If the file is renamed, we should append the ARCHIVE attribute\r
+    //\r
+    OFile->Archive = TRUE;\r
+  } else if (Parent != OFile) {\r
+    //\r
+    // filename is to a different filename that already exists\r
+    //\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  //\r
+  // If the file size has changed, apply it\r
+  //\r
+  if (NewInfo->FileSize != OFile->FileSize) {\r
+    if (OFile->ODir != NULL || ReadOnly) {\r
+      //\r
+      // If this is a directory or the file is read only, we can't change the file size\r
+      //\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+\r
+    if (NewInfo->FileSize > OFile->FileSize) {\r
+      Status = FatExpandOFile (OFile, NewInfo->FileSize);\r
+    } else {\r
+      Status = FatTruncateOFile (OFile, (UINTN) NewInfo->FileSize);\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    FatUpdateDirEntClusterSizeInfo (OFile);\r
+  }\r
+\r
+  OFile->Dirty = TRUE;\r
+  return FatOFileFlush (OFile);\r
+}\r
+\r
+EFI_STATUS\r
+FatSetOrGetInfo (\r
+  IN     BOOLEAN        IsSet,\r
+  IN     EFI_FILE       *FHand,\r
+  IN     EFI_GUID       *Type,\r
+  IN OUT UINTN          *BufferSize,\r
+  IN OUT VOID           *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Set or Get the some types info of the file into Buffer\r
+\r
+Arguments:\r
+\r
+  IsSet      - TRUE:The access is set, else is get\r
+  FHand      - The handle of file\r
+  Type       - The type of the info\r
+  BufferSize - Size of Buffer\r
+  Buffer     - Buffer containing volume info\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS       - Get the info successfully\r
+  EFI_DEVICE_ERROR  - Can not find the OFile for the file\r
+\r
+--*/\r
+{\r
+  FAT_IFILE   *IFile;\r
+  FAT_OFILE   *OFile;\r
+  FAT_VOLUME  *Volume;\r
+  EFI_STATUS  Status;\r
+\r
+  IFile   = IFILE_FROM_FHAND (FHand);\r
+  OFile   = IFile->OFile;\r
+  Volume  = OFile->Volume;\r
+\r
+  Status  = OFile->Error;\r
+  if (Status == EFI_NOT_FOUND) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  FatAcquireLock ();\r
+\r
+  //\r
+  // Verify the file handle isn't in an error state\r
+  //\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Get the proper information based on the request\r
+    //\r
+    Status = EFI_UNSUPPORTED;\r
+    if (IsSet) {\r
+      if (Volume->ReadOnly) {\r
+        Status = EFI_WRITE_PROTECTED;\r
+      } else {\r
+        if (EfiCompareGuid (Type, &gEfiFileInfoGuid)) {\r
+          Status = FatSetFileInfo (Volume, IFile, OFile, *BufferSize, Buffer);\r
+        }\r
+\r
+        if (EfiCompareGuid (Type, &gEfiFileSystemInfoGuid)) {\r
+          Status = FatSetVolumeInfo (Volume, *BufferSize, Buffer);\r
+        }\r
+\r
+        if (EfiCompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
+          Status = FatSetVolumeLabelInfo (Volume, *BufferSize, Buffer);\r
+        }\r
+      }\r
+    } else {\r
+      if (EfiCompareGuid (Type, &gEfiFileInfoGuid)) {\r
+        Status = FatGetFileInfo (OFile, BufferSize, Buffer);\r
+      }\r
+\r
+      if (EfiCompareGuid (Type, &gEfiFileSystemInfoGuid)) {\r
+        Status = FatGetVolumeInfo (Volume, BufferSize, Buffer);\r
+      }\r
+\r
+      if (EfiCompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
+        Status = FatGetVolumeLabelInfo (Volume, BufferSize, Buffer);\r
+      }\r
+    }\r
+  }\r
+\r
+  Status = FatCleanupVolume (Volume, NULL, Status);\r
+\r
+  FatReleaseLock ();\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatGetInfo (\r
+  IN     EFI_FILE       *FHand,\r
+  IN     EFI_GUID       *Type,\r
+  IN OUT UINTN          *BufferSize,\r
+     OUT VOID           *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Get the some types info of the file into Buffer.\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of file.\r
+  Type                  - The type of the info.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get the info successfully.\r
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.\r
+\r
+--*/\r
+{\r
+  return FatSetOrGetInfo (FALSE, FHand, Type, BufferSize, Buffer);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatSetInfo (\r
+  IN EFI_FILE  *FHand,\r
+  IN EFI_GUID  *Type,\r
+  IN UINTN     BufferSize,\r
+  IN VOID      *Buffer\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Set the some types info of the file into Buffer.\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of file.\r
+  Type                  - The type of the info.\r
+  BufferSize            - Size of Buffer\r
+  Buffer                - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Set the info successfully.\r
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.\r
+\r
+--*/\r
+{\r
+  return FatSetOrGetInfo (TRUE, FHand, Type, &BufferSize, Buffer);\r
+}\r
diff --git a/EnhancedFat/Dxe/Init.c b/EnhancedFat/Dxe/Init.c
new file mode 100644 (file)
index 0000000..c38ed85
--- /dev/null
@@ -0,0 +1,536 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  Init.c\r
+  \r
+Abstract:\r
+\r
+  Initialization routines\r
+  \r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+FatInitUnicodeCollationSupport (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL    *This,\r
+  IN  LC_ISO_639_2                   *LangCode,\r
+  OUT EFI_UNICODE_COLLATION_PROTOCOL **UnicodeCollationInterface\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initializes Unicode Collation support.\r
+    \r
+Arguments:\r
+\r
+  This                       - Protocol instance pointer.    \r
+  LangCode                   - Language Code specified.\r
+  UnicodeCollationInterface  - Unicode Collation protocol interface returned.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS                - Successfully get the Unicode Collation protocol interface by \r
+                               specified LangCode.\r
+  EFI_NOT_FOUND              - Specified Unicode Collation protocol is not found.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                      Status;\r
+  LC_ISO_639_2                    *Languages;\r
+  UINTN                           Index;\r
+  UINTN                           NoHandles;\r
+  EFI_HANDLE                      *Handles;\r
+  EFI_UNICODE_COLLATION_PROTOCOL  *Uci;\r
+  EFI_UNICODE_COLLATION_PROTOCOL  *EngUci;\r
+  EFI_UNICODE_COLLATION_PROTOCOL  *FoundUci;\r
+\r
+  ASSERT (LangCode != NULL);\r
+  //\r
+  // Locate all Unicode Collation drivers.\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiUnicodeCollationProtocolGuid,\r
+                  NULL,\r
+                  &NoHandles,\r
+                  &Handles\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  FoundUci  = NULL;\r
+  EngUci    = NULL;\r
+\r
+  //\r
+  // Check all Unicode Collation drivers for a matching language code.\r
+  //\r
+  for (Index = 0; Index < NoHandles; Index++) {\r
+    //\r
+    // Open Unicode Collation Protocol\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    Handles[Index],\r
+                    &gEfiUnicodeCollationProtocolGuid,\r
+                    (VOID **) &Uci,\r
+                    This->DriverBindingHandle,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+    //\r
+    // Check for a matching language code.\r
+    //\r
+    for (Languages = Uci->SupportedLanguages; *Languages != 0; Languages += LC_ISO_639_2_ENTRY_SIZE) {\r
+      //\r
+      // If this code matches, use this driver\r
+      //\r
+      if (EfiLibCompareLanguage (Languages, LangCode)) {\r
+        FoundUci = Uci;\r
+        goto Done;\r
+      }\r
+\r
+      if (EfiLibCompareLanguage (Languages, "eng")) {\r
+        EngUci = Uci;\r
+      }\r
+    }\r
+  }\r
+\r
+Done:\r
+  //\r
+  // Cleanup\r
+  //\r
+  if (Handles != NULL) {\r
+    gBS->FreePool (Handles);\r
+  }\r
+\r
+  if (FoundUci == NULL) {\r
+    FoundUci = EngUci;\r
+  }\r
+\r
+  *UnicodeCollationInterface = FoundUci;\r
+  return FoundUci != NULL ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+}\r
+\r
+EFI_STATUS\r
+FatAllocateVolume (\r
+  IN  EFI_HANDLE                Handle,\r
+  IN  EFI_DISK_IO_PROTOCOL      *DiskIo,\r
+  IN  EFI_BLOCK_IO_PROTOCOL     *BlockIo\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Allocates volume structure, detects FAT file system, installs protocol,\r
+  and initialize cache.\r
+  \r
+Arguments:\r
\r
+  Handle                - The handle of parent device.\r
+  DiskIo                - The DiskIo of parent device.\r
+  BlockIo               - The BlockIo of parent devicel\r
+  \r
+Returns:\r
+\r
+  EFI_SUCCESS           - Allocate a new volume successfully.\r
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory.\r
+  Others                - Allocating a new volume failed.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  FAT_VOLUME  *Volume;\r
+  BOOLEAN     LockedByMe;\r
+  LockedByMe = FALSE;\r
+  //\r
+  // Allocate a volume structure\r
+  //\r
+  Volume = EfiLibAllocateZeroPool (sizeof (FAT_VOLUME));\r
+  if (Volume == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Acquire the lock.\r
+  // If caller has already acquired the lock, cannot lock it again.\r
+  //\r
+  if (!FatIsLocked ()) {\r
+    FatAcquireLock ();\r
+    LockedByMe = TRUE;\r
+  }\r
+  //\r
+  // Initialize the structure\r
+  //\r
+  Volume->Signature                   = FAT_VOLUME_SIGNATURE;\r
+  Volume->Handle                      = Handle;\r
+  Volume->DiskIo                      = DiskIo;\r
+  Volume->BlockIo                     = BlockIo;\r
+  Volume->MediaId                     = BlockIo->Media->MediaId;\r
+  Volume->ReadOnly                    = BlockIo->Media->ReadOnly;\r
+  Volume->VolumeInterface.Revision    = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;\r
+  Volume->VolumeInterface.OpenVolume  = FatOpenVolume;\r
+  InitializeListHead (&Volume->CheckRef);\r
+  InitializeListHead (&Volume->DirCacheList);\r
+  //\r
+  // Initialize Root Directory entry\r
+  //\r
+  Volume->RootDirEnt.FileString       = Volume->RootFileString;\r
+  Volume->RootDirEnt.Entry.Attributes = FAT_ATTRIBUTE_DIRECTORY;\r
+  //\r
+  // Check to see if there's a file system on the volume\r
+  //\r
+  Status = FatOpenDevice (Volume);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Initialize cache\r
+  //\r
+  Status = FatInitializeDiskCache (Volume);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Install our protocol interfaces on the device's handle\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Volume->Handle,\r
+                  &gEfiSimpleFileSystemProtocolGuid,\r
+                  &Volume->VolumeInterface,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Volume installed\r
+  //\r
+  DEBUG ((EFI_D_INIT, "%HInstalled Fat filesystem on %x%N\n", Handle));\r
+  Volume->Valid = TRUE;\r
+\r
+Done:\r
+  //\r
+  // Unlock if locked by myself.\r
+  //\r
+  if (LockedByMe) {\r
+    FatReleaseLock ();\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FatFreeVolume (Volume);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatAbandonVolume (\r
+  IN FAT_VOLUME *Volume\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
\r
+  Called by FatDriverBindingStop(), Abandon the volume.\r
+  \r
+Arguments:\r
\r
+  Volume                - The volume to be abandoned.\r
+  \r
+Returns:\r
\r
+  EFI_SUCCESS           - Abandoned the volume successfully.\r
+  Others                - Can not uninstall the protocol interfaces.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  BOOLEAN     LockedByMe;\r
+\r
+  //\r
+  // Uninstall the protocol interface.\r
+  //\r
+  if (Volume->Handle != NULL) {\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    Volume->Handle,\r
+                    &gEfiSimpleFileSystemProtocolGuid,\r
+                    &Volume->VolumeInterface,\r
+                    NULL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  LockedByMe = FALSE;\r
+\r
+  //\r
+  // Acquire the lock.\r
+  // If the caller has already acquired the lock (which\r
+  // means we are in the process of some Fat operation),\r
+  // we can not acquire again.\r
+  //\r
+  if (!FatIsLocked ()) {\r
+    LockedByMe = TRUE;\r
+    FatAcquireLock ();\r
+  }\r
+  //\r
+  // The volume is still being used. Hence, set error flag for all OFiles still in\r
+  // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is\r
+  // EFI_NO_MEDIA.\r
+  //\r
+  if (Volume->Root != NULL) {\r
+    FatSetVolumeError (\r
+      Volume->Root,\r
+      Volume->BlockIo->Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA\r
+      );\r
+  }\r
+\r
+  Volume->Valid = FALSE;\r
+\r
+  //\r
+  // Release the lock.\r
+  // If locked by me, this means DriverBindingStop is NOT\r
+  // called within an on-going Fat operation, so we should\r
+  // take responsibility to cleanup and free the volume.\r
+  // Otherwise, the DriverBindingStop is called within an on-going\r
+  // Fat operation, we shouldn't check reference, so just let outer\r
+  // FatCleanupVolume do the task.\r
+  //\r
+  if (LockedByMe) {\r
+    FatCleanupVolume (Volume, NULL, EFI_SUCCESS);\r
+    FatReleaseLock ();\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatOpenDevice (\r
+  IN OUT FAT_VOLUME           *Volume\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+  Detects FAT file system on Disk and set relevant fields of Volume\r
+  \r
+Arguments:\r
\r
+  Volume                - The volume structure.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The Fat File System is detected successfully\r
+  EFI_UNSUPPORTED       - The volume is not FAT file system.\r
+  EFI_VOLUME_CORRUPTED  - The volume is corrupted.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT32                BlockSize;\r
+  UINT32                DirtyMask;\r
+  EFI_DISK_IO_PROTOCOL  *DiskIo;\r
+  FAT_BOOT_SECTOR       FatBs;\r
+  FAT_VOLUME_TYPE       FatType;\r
+  UINTN                 RootDirSectors;\r
+  UINTN                 RootSize;\r
+  UINTN                 FatLba;\r
+  UINTN                 RootLba;\r
+  UINTN                 FirstClusterLba;\r
+  UINTN                 Sectors;\r
+  UINTN                 SectorsPerFat;\r
+  UINT8                 SectorsPerClusterAlignment;\r
+  UINT8                 BlockAlignment;\r
+\r
+  //\r
+  // Read the FAT_BOOT_SECTOR BPB info\r
+  // This is the only part of FAT code that uses parent DiskIo,\r
+  // Others use FatDiskIo which utilizes a Cache.\r
+  //\r
+  DiskIo  = Volume->DiskIo;\r
+  Status  = DiskIo->ReadDisk (DiskIo, Volume->MediaId, 0, sizeof (FatBs), &FatBs);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INIT, "FatOpenDevice: read of part_lba failed %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  FatType = FatUndefined;\r
+\r
+  //\r
+  // Use LargeSectors if Sectors is 0\r
+  //\r
+  Sectors = FatBs.FatBsb.Sectors;\r
+  if (Sectors == 0) {\r
+    Sectors = FatBs.FatBsb.LargeSectors;\r
+  }\r
+\r
+  SectorsPerFat = FatBs.FatBsb.SectorsPerFat;\r
+  if (SectorsPerFat == 0) {\r
+    SectorsPerFat = FatBs.FatBse.Fat32Bse.LargeSectorsPerFat;\r
+    FatType       = FAT32;\r
+  }\r
+  //\r
+  // Is boot sector a fat sector?\r
+  // (Note that so far we only know if the sector is FAT32 or not, we don't\r
+  // know if the sector is Fat16 or Fat12 until later when we can compute\r
+  // the volume size)\r
+  //\r
+  if (FatBs.FatBsb.ReservedSectors == 0 || FatBs.FatBsb.NumFats == 0 || Sectors == 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if ((FatBs.FatBsb.SectorSize & (FatBs.FatBsb.SectorSize - 1)) != 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  BlockAlignment = Log2 (FatBs.FatBsb.SectorSize);\r
+  if (BlockAlignment > MAX_BLOCK_ALIGNMENT || BlockAlignment < MIN_BLOCK_ALIGNMENT) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if ((FatBs.FatBsb.SectorsPerCluster & (FatBs.FatBsb.SectorsPerCluster - 1)) != 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  SectorsPerClusterAlignment = Log2 (FatBs.FatBsb.SectorsPerCluster);\r
+  if (SectorsPerClusterAlignment > MAX_SECTORS_PER_CLUSTER_ALIGNMENT) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (FatBs.FatBsb.Media <= 0xf7 &&\r
+      FatBs.FatBsb.Media != 0xf0 &&\r
+      FatBs.FatBsb.Media != 0x00 &&\r
+      FatBs.FatBsb.Media != 0x01\r
+      ) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Initialize fields the volume information for this FatType\r
+  //\r
+  if (FatType != FAT32) {\r
+    if (FatBs.FatBsb.RootEntries == 0) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+    //\r
+    // Unpack fat12, fat16 info\r
+    //\r
+    Volume->RootEntries = FatBs.FatBsb.RootEntries;\r
+  } else {\r
+    //\r
+    // If this is fat32, refuse to mount mirror-disabled volumes\r
+    //\r
+    if ((SectorsPerFat == 0 || FatBs.FatBse.Fat32Bse.FsVersion != 0) || (FatBs.FatBse.Fat32Bse.ExtendedFlags & 0x80)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+    //\r
+    // Unpack fat32 info\r
+    //\r
+    Volume->RootCluster = FatBs.FatBse.Fat32Bse.RootDirFirstCluster;\r
+  }\r
+\r
+  Volume->NumFats           = FatBs.FatBsb.NumFats;\r
+  //\r
+  // Compute some fat locations\r
+  //\r
+  BlockSize                 = FatBs.FatBsb.SectorSize;\r
+  RootDirSectors            = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (BlockSize - 1)) / BlockSize;\r
+  RootSize                  = RootDirSectors * BlockSize;\r
+\r
+  FatLba                    = FatBs.FatBsb.ReservedSectors;\r
+  RootLba                   = FatBs.FatBsb.NumFats * SectorsPerFat + FatLba;\r
+  FirstClusterLba           = RootLba + RootDirSectors;\r
+\r
+  Volume->FatPos            = FatLba * BlockSize;\r
+  Volume->FatSize           = SectorsPerFat * BlockSize;\r
+\r
+  Volume->VolumeSize        = LShiftU64 (Sectors, BlockAlignment);\r
+  Volume->RootPos           = LShiftU64 (RootLba, BlockAlignment);\r
+  Volume->FirstClusterPos   = LShiftU64 (FirstClusterLba, BlockAlignment);\r
+  Volume->MaxCluster        = (Sectors - FirstClusterLba) >> SectorsPerClusterAlignment;\r
+  Volume->ClusterAlignment  = BlockAlignment + SectorsPerClusterAlignment;\r
+  Volume->ClusterSize       = 1 << (Volume->ClusterAlignment);\r
+\r
+  //\r
+  // If this is not a fat32, determine if it's a fat16 or fat12\r
+  //\r
+  if (FatType != FAT32) {\r
+    if (Volume->MaxCluster >= FAT_MAX_FAT16_CLUSTER) {\r
+      return EFI_VOLUME_CORRUPTED;\r
+    }\r
+\r
+    FatType = Volume->MaxCluster < FAT_MAX_FAT12_CLUSTER ? FAT12 : FAT16;\r
+    //\r
+    // fat12 & fat16 fat-entries are 2 bytes\r
+    //\r
+    Volume->FatEntrySize = sizeof (UINT16);\r
+    DirtyMask            = FAT16_DIRTY_MASK;\r
+  } else {\r
+    if (Volume->MaxCluster < FAT_MAX_FAT16_CLUSTER) {\r
+      return EFI_VOLUME_CORRUPTED;\r
+    }\r
+    //\r
+    // fat32 fat-entries are 4 bytes\r
+    //\r
+    Volume->FatEntrySize = sizeof (UINT32);\r
+    DirtyMask            = FAT32_DIRTY_MASK;\r
+  }\r
+  //\r
+  // Get the DirtyValue and NotDirtyValue\r
+  // We should keep the initial value as the NotDirtyValue\r
+  // in case the volume is dirty already\r
+  //\r
+  if (FatType != FAT12) {\r
+    Status = FatAccessVolumeDirty (Volume, READ_DISK, &Volume->NotDirtyValue);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Volume->DirtyValue = Volume->NotDirtyValue & DirtyMask;\r
+    Volume->FatDirty   = (BOOLEAN) (Volume->DirtyValue == Volume->NotDirtyValue);\r
+  }\r
+  //\r
+  // If present, read the fat hint info\r
+  //\r
+  if (FatType == FAT32) {\r
+    Volume->FreeInfoPos = FatBs.FatBse.Fat32Bse.FsInfoSector * BlockSize;\r
+    if (FatBs.FatBse.Fat32Bse.FsInfoSector != 0) {\r
+      FatDiskIo (Volume, READ_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector);\r
+      if (Volume->FatInfoSector.Signature == FAT_INFO_SIGNATURE &&\r
+          Volume->FatInfoSector.InfoBeginSignature == FAT_INFO_BEGIN_SIGNATURE &&\r
+          Volume->FatInfoSector.InfoEndSignature == FAT_INFO_END_SIGNATURE &&\r
+          Volume->FatInfoSector.FreeInfo.ClusterCount <= Volume->MaxCluster\r
+          ) {\r
+        Volume->FreeInfoValid = TRUE;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // Just make up a FreeInfo.NextCluster for use by allocate cluster\r
+  //\r
+  if (FAT_MIN_CLUSTER > Volume->FatInfoSector.FreeInfo.NextCluster ||\r
+     Volume->FatInfoSector.FreeInfo.NextCluster > Volume->MaxCluster + 1\r
+     ) {\r
+    Volume->FatInfoSector.FreeInfo.NextCluster = FAT_MIN_CLUSTER;\r
+  }\r
+  //\r
+  // We are now defining FAT Type\r
+  //\r
+  Volume->FatType = FatType;\r
+  ASSERT (FatType != FatUndefined);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/EnhancedFat/Dxe/Misc.c b/EnhancedFat/Dxe/Misc.c
new file mode 100644 (file)
index 0000000..66af2b6
--- /dev/null
@@ -0,0 +1,584 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  Misc.c\r
+  \r
+Abstract:\r
+\r
+  Miscellaneous functions\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+FatAccessVolumeDirty (\r
+  IN FAT_VOLUME       *Volume,\r
+  IN IO_MODE          IoMode,\r
+  IN VOID             *DirtyValue\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Set the volume as dirty or not\r
+  \r
+Arguments: \r
+\r
+  Volume                - FAT file system volume.\r
+  IoMode                - The access mode.\r
+  DirtyValue            - Set the volume as dirty or not.\r
+  \r
+Returns:\r
+  \r
+  EFI_SUCCESS           - Set the new FAT entry value sucessfully.\r
+  other                 - An error occurred when operation the FAT entries.\r
+\r
+--*/\r
+{\r
+  UINTN WriteCount;\r
+\r
+  WriteCount = Volume->FatEntrySize;\r
+  return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue);\r
+}\r
+\r
+EFI_STATUS\r
+FatDiskIo (\r
+  IN     FAT_VOLUME       *Volume,\r
+  IN     IO_MODE          IoMode,\r
+  IN     UINT64           Offset,\r
+  IN     UINTN            BufferSize,\r
+  IN OUT VOID             *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  General disk access function\r
+  \r
+Arguments: \r
+\r
+  Volume                - FAT file system volume.\r
+  IoMode                - The access mode (disk read/write or cache access).\r
+  Offset                - The starting byte offset to read from.\r
+  BufferSize            - Size of Buffer.\r
+  Buffer                - Buffer containing read data.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - The operation is performed successfully.\r
+  EFI_VOLUME_CORRUPTED  - The accesss is\r
+  Others                - The status of read/write the disk\r
+\r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_DISK_IO_PROTOCOL  *DiskIo;\r
+  EFI_DISK_READ         IoFunction;\r
+\r
+  //\r
+  // Verify the IO is in devices range\r
+  //\r
+  Status = EFI_VOLUME_CORRUPTED;\r
+  if (Offset + BufferSize <= Volume->VolumeSize) {\r
+    if (CACHE_ENABLED (IoMode)) {\r
+      //\r
+      // Access cache\r
+      //\r
+      Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer);\r
+    } else {\r
+      //\r
+      // Access disk directly\r
+      //\r
+      DiskIo      = Volume->DiskIo;\r
+      IoFunction  = (IoMode == READ_DISK) ? DiskIo->ReadDisk : DiskIo->WriteDisk;\r
+      Status      = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Volume->DiskError = TRUE;\r
+    DEBUG ((EFI_D_INFO, "FatDiskIo: error %r\n", Status));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+VOID\r
+FatAcquireLock (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+  Lock the volume.\r
+\r
+Arguments:\r
\r
+  None.\r
+  \r
+Returns:\r
+  \r
+  None.\r
+  \r
+--*/\r
+{\r
+  EfiAcquireLock (&FatFsLock);\r
+}\r
+\r
+BOOLEAN\r
+FatIsLocked (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Get the locking status of the volume.\r
+  \r
+Arguments:\r
\r
+  None.\r
+  \r
+Returns:\r
+  \r
+  TRUE                  - The volume is locked.\r
+  FALSE                 - The volume is not locked.\r
+  \r
+--*/\r
+{\r
+  return (BOOLEAN) (FatFsLock.Lock);\r
+}\r
+\r
+VOID\r
+FatReleaseLock (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Unlock the volume.\r
+  \r
+Arguments:\r
+  \r
+  Null.\r
+  \r
+Returns:\r
+  \r
+  None.\r
+  \r
+--*/\r
+{\r
+  EfiReleaseLock (&FatFsLock);\r
+}\r
+\r
+VOID\r
+FatFreeDirEnt (\r
+  IN FAT_DIRENT       *DirEnt\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Free directory entry.\r
+  \r
+Arguments:\r
+  \r
+  DirEnt                - The directory entry to be freed.\r
+  \r
+Returns:\r
+  \r
+  None.\r
+  \r
+--*/\r
+{\r
+  if (DirEnt->FileString != NULL) {\r
+    gBS->FreePool (DirEnt->FileString);\r
+  }\r
+\r
+  gBS->FreePool (DirEnt);\r
+}\r
+\r
+VOID\r
+FatFreeVolume (\r
+  IN FAT_VOLUME       *Volume\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Free volume structure (including the contents of directory cache and disk cache).\r
+  \r
+Arguments:\r
+  \r
+  Volume                - The volume structure to be freed.\r
+  \r
+Returns:\r
+  \r
+  None.\r
+  \r
+--*/\r
+{\r
+  //\r
+  // Free disk cache\r
+  //\r
+  if (Volume->CacheBuffer != NULL) {\r
+    gBS->FreePool (Volume->CacheBuffer);\r
+  }\r
+  //\r
+  // Free directory cache\r
+  //\r
+  FatCleanupODirCache (Volume);\r
+  gBS->FreePool (Volume);\r
+}\r
+\r
+VOID\r
+FatEfiTimeToFatTime (\r
+  IN  EFI_TIME        *ETime,\r
+  OUT FAT_DATE_TIME   *FTime\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Translate EFI time to FAT time.\r
+  \r
+Arguments: \r
+  \r
+  ETime                 - The time of EFI_TIME.\r
+  FTime                 - The time of FAT_DATE_TIME.\r
+  \r
+Returns:\r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  //\r
+  // ignores timezone info in source ETime\r
+  //\r
+  if (ETime->Year > 1980) {\r
+    FTime->Date.Year = (UINT16) (ETime->Year - 1980);\r
+  }\r
+\r
+  if (ETime->Year >= 1980 + 128) {\r
+    FTime->Date.Year = (UINT16)0x7f;\r
+  }\r
+\r
+  FTime->Date.Month         = ETime->Month;\r
+  FTime->Date.Day           = ETime->Day;\r
+  FTime->Time.Hour          = ETime->Hour;\r
+  FTime->Time.Minute        = ETime->Minute;\r
+  FTime->Time.DoubleSecond  = (UINT16) (ETime->Second / 2);\r
+}\r
+\r
+VOID\r
+FatFatTimeToEfiTime (\r
+  IN  FAT_DATE_TIME     *FTime,\r
+  OUT EFI_TIME          *ETime\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Translate Fat time to EFI time.\r
+  \r
+Arguments: \r
+\r
+  FTime                 - The time of FAT_DATE_TIME.\r
+  ETime                 - The time of EFI_TIME.\r
+  \r
+Returns:\r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  ETime->Year       = (UINT16) (FTime->Date.Year + 1980);\r
+  ETime->Month      = (UINT8) FTime->Date.Month;\r
+  ETime->Day        = (UINT8) FTime->Date.Day;\r
+  ETime->Hour       = (UINT8) FTime->Time.Hour;\r
+  ETime->Minute     = (UINT8) FTime->Time.Minute;\r
+  ETime->Second     = (UINT8) (FTime->Time.DoubleSecond * 2);\r
+  ETime->Nanosecond = 0;\r
+  ETime->TimeZone   = EFI_UNSPECIFIED_TIMEZONE;\r
+  ETime->Daylight   = 0;\r
+}\r
+\r
+VOID\r
+FatGetCurrentFatTime (\r
+  OUT FAT_DATE_TIME   *FatNow\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Get Current FAT time.\r
+  \r
+Arguments: \r
+\r
+  FatNow                - Current FAT time.\r
+  \r
+Returns:\r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  EFI_TIME  Now;\r
+  gRT->GetTime (&Now, NULL);\r
+  FatEfiTimeToFatTime (&Now, FatNow);\r
+}\r
+\r
+BOOLEAN\r
+FatIsValidTime (\r
+  IN EFI_TIME         *Time\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+  Check whether a time is valid.\r
+  \r
+Arguments: \r
\r
+  Time                  - The time of EFI_TIME.\r
+  \r
+Returns:\r
+  \r
+  TRUE                  - The time is valid.\r
+  FALSE                 - The time is not valid.\r
+\r
+--*/\r
+{\r
+  static UINT8  MonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
+  UINTN         Day;\r
+  BOOLEAN       ValidTime;\r
+\r
+  ValidTime = TRUE;\r
+\r
+  //\r
+  // Check the fields for range problems\r
+  // Fat can only support from 1980\r
+  //\r
+  if (Time->Year < 1980 ||\r
+      Time->Month < 1 ||\r
+      Time->Month > 12 ||\r
+      Time->Day < 1 ||\r
+      Time->Day > 31 ||\r
+      Time->Hour > 23 ||\r
+      Time->Minute > 59 ||\r
+      Time->Second > 59 ||\r
+      Time->Nanosecond > 999999999\r
+      ) {\r
+\r
+    ValidTime = FALSE;\r
+\r
+  } else {\r
+    //\r
+    // Perform a more specific check of the day of the month\r
+    //\r
+    Day = MonthDays[Time->Month - 1];\r
+    if (Time->Month == 2 && IS_LEAP_YEAR (Time->Year)) {\r
+      Day += 1;\r
+      //\r
+      // 1 extra day this month\r
+      //\r
+    }\r
+    if (Time->Day > Day) {\r
+      ValidTime = FALSE;\r
+    }\r
+  }\r
+\r
+  return ValidTime;\r
+}\r
+\r
+VOID\r
+FatStrUpr (\r
+  IN CHAR16   *Str\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Uppercase a string.\r
+  \r
+Arguments: \r
+  \r
+  Str                   - The string which will be upper-cased.\r
+  \r
+Returns:\r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  ASSERT (gUnicodeCollationInterface != NULL);\r
+  gUnicodeCollationInterface->StrUpr (gUnicodeCollationInterface, Str);\r
+}\r
+\r
+VOID\r
+FatStrLwr (\r
+  IN CHAR16   *Str\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Lowercase a string\r
+  \r
+Arguments: \r
+  \r
+  Str                   - The string which will be lower-cased.\r
+  \r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  ASSERT (gUnicodeCollationInterface != NULL);\r
+  gUnicodeCollationInterface->StrLwr (gUnicodeCollationInterface, Str);\r
+}\r
+\r
+INTN\r
+FatStriCmp (\r
+  IN CHAR16   *Str1,\r
+  IN CHAR16   *Str2\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Case insensitive string comparison.\r
+  \r
+Arguments: \r
+\r
+  Str1                  - The first string which will be compared.\r
+  Str2                  - The second string which will be compared.\r
+  \r
+Returns:\r
+  \r
+  The comparing result\r
+  \r
+--*/\r
+{\r
+  ASSERT (gUnicodeCollationInterface != NULL);\r
+  return gUnicodeCollationInterface->StriColl (\r
+                                       gUnicodeCollationInterface,\r
+                                       Str1,\r
+                                       Str2\r
+                                       );\r
+}\r
+\r
+VOID\r
+FatFatToStr (\r
+  IN  UINTN                            FatSize,\r
+  IN  CHAR8                            *Fat,\r
+  OUT CHAR16                           *String\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Convert FAT string to unicode string.\r
+  \r
+Arguments:    \r
+\r
+  FatSize               - The size of FAT string.\r
+  Fat                   - The FAT string.\r
+  String                - The unicode string.\r
+\r
+Returns:\r
+\r
+  None.\r
+  \r
+--*/\r
+{\r
+  ASSERT (gUnicodeCollationInterface != NULL);\r
+  gUnicodeCollationInterface->FatToStr (\r
+                                gUnicodeCollationInterface,\r
+                                FatSize,\r
+                                Fat,\r
+                                String\r
+                                );\r
+}\r
+\r
+BOOLEAN\r
+FatStrToFat (\r
+  IN  CHAR16                          *String,\r
+  IN  UINTN                           FatSize,\r
+  OUT CHAR8                           *Fat\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
\r
+  Convert unicode string to Fat string.\r
+  \r
+Arguments: \r
\r
+  String                - The unicode string.\r
+  FatSize               - The size of the FAT string.\r
+  Fat                   - The FAT string.\r
+  \r
+Returns:\r
+\r
+  TRUE                  - Convert successfully.\r
+  FALSE                 - Convert error.\r
+  \r
+--*/\r
+{\r
+  ASSERT (gUnicodeCollationInterface != NULL);\r
+  return gUnicodeCollationInterface->StrToFat (\r
+                                       gUnicodeCollationInterface,\r
+                                       String,\r
+                                       FatSize,\r
+                                       Fat\r
+                                       );\r
+}\r
+\r
+BOOLEAN\r
+EfiLibCompareLanguage (\r
+  IN  CHAR8  *Language1,\r
+  IN  CHAR8  *Language2\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Compare whether two names of languages are identical.\r
+\r
+Arguments:\r
+\r
+  Language1 - Name of language 1\r
+  Language2 - Name of language 2\r
+\r
+Returns:\r
+\r
+  TRUE      - same\r
+  FALSE     - not same\r
+\r
+--*/\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; Index < 3; Index++) {\r
+    if (Language1[Index] != Language2[Index]) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
diff --git a/EnhancedFat/Dxe/Open.c b/EnhancedFat/Dxe/Open.c
new file mode 100644 (file)
index 0000000..3c8eacf
--- /dev/null
@@ -0,0 +1,281 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  open.c\r
+  \r
+Abstract:\r
+\r
+  Routines dealing with file open\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+FatAllocateIFile (\r
+  IN FAT_OFILE    *OFile,\r
+  OUT FAT_IFILE   **PtrIFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create an Open instance for the existing OFile.\r
+  The IFile of the newly opened file is passed out.\r
+\r
+Arguments:\r
+\r
+  OFile                 - The file that serves as a starting reference point.\r
+  PtrIFile              - The newly generated IFile instance.\r
+\r
+Returns:\r
+\r
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory for the IFile\r
+  EFI_SUCCESS           - Create the new IFile for the OFile successfully\r
+\r
+--*/\r
+{\r
+  FAT_IFILE *IFile;\r
+\r
+  ASSERT_VOLUME_LOCKED (OFile->Volume);\r
+\r
+  //\r
+  // Allocate a new open instance\r
+  //\r
+  IFile = EfiLibAllocateZeroPool (sizeof (FAT_IFILE));\r
+  if (IFile == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  IFile->Signature = FAT_IFILE_SIGNATURE;\r
+\r
+  EfiCopyMem (&(IFile->Handle), &FatFileInterface, sizeof (EFI_FILE));\r
+\r
+  IFile->OFile = OFile;\r
+  InsertTailList (&OFile->Opens, &IFile->Link);\r
+\r
+  *PtrIFile = IFile;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatOFileOpen (\r
+  IN  FAT_OFILE            *OFile,\r
+  OUT FAT_IFILE            **NewIFile,\r
+  IN  CHAR16               *FileName,\r
+  IN  UINT64               OpenMode,\r
+  IN  UINT8                Attributes\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Open a file for a file name relative to an existing OFile.\r
+  The IFile of the newly opened file is passed out.\r
+\r
+Arguments:\r
+\r
+  OFile                 - The file that serves as a starting reference point.\r
+  NewIFile              - The newly generated IFile instance.\r
+  FileName              - The file name relative to the OFile.\r
+  OpenMode              - Open mode.\r
+  Attributes            - Attributes to set if the file is created.\r
+\r
+Returns:\r
+  \r
+  EFI_SUCCESS           - Open the file successfully.\r
+  EFI_INVALID_PARAMETER - The open mode is conflict with the attributes\r
+                          or the file name is not valid.\r
+  EFI_NOT_FOUND         - Conficts between dir intention and attribute.\r
+  EFI_WRITE_PROTECTED   - Can't open for write if the volume is read only.\r
+  EFI_ACCESS_DENIED     - If the file's attribute is read only, and the \r
+                          open is for read-write fail it.\r
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory.\r
+\r
+--*/\r
+{\r
+  FAT_VOLUME  *Volume;\r
+  EFI_STATUS  Status;\r
+  CHAR16      NewFileName[EFI_FILE_STRING_LENGTH + 1];\r
+  FAT_DIRENT  *DirEnt;\r
+  UINT8       FileAttributes;\r
+  BOOLEAN     WriteMode;\r
+\r
+  Volume = OFile->Volume;\r
+  ASSERT_VOLUME_LOCKED (Volume);\r
+  WriteMode = (BOOLEAN) (OpenMode & EFI_FILE_MODE_WRITE);\r
+  if (Volume->ReadOnly && WriteMode) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+  //\r
+  // Verify the source file handle isn't in an error state\r
+  //\r
+  Status = OFile->Error;\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Get new OFile for the file\r
+  //\r
+  Status = FatLocateOFile (&OFile, FileName, Attributes, NewFileName);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (*NewFileName != 0) {\r
+    //\r
+    // If there's a remaining part of the name, then we had\r
+    // better be creating the file in the directory\r
+    //\r
+    if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    Status = FatCreateDirEnt (OFile, NewFileName, Attributes, &DirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = FatOpenDirEnt (OFile, DirEnt);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    OFile = DirEnt->OFile;\r
+    if (OFile->ODir != NULL) {\r
+      //\r
+      // If we just created a directory, we need to create "." and ".."\r
+      //\r
+      Status = FatCreateDotDirEnts (OFile);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // If the file's attribute is read only, and the open is for\r
+  // read-write, then the access is denied.\r
+  //\r
+  FileAttributes = OFile->DirEnt->Entry.Attributes;\r
+  if ((FileAttributes & EFI_FILE_READ_ONLY) != 0 && (FileAttributes & FAT_ATTRIBUTE_DIRECTORY) == 0 && WriteMode) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  //\r
+  // Create an open instance of the OFile\r
+  //\r
+  Status = FatAllocateIFile (OFile, NewIFile);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  (*NewIFile)->ReadOnly = !WriteMode;\r
+\r
+  DEBUG ((EFI_D_INFO, "FSOpen: Open '%S' %r\n", FileName, Status));\r
+  return FatOFileFlush (OFile);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatOpen (\r
+  IN  EFI_FILE   *FHand,\r
+  OUT EFI_FILE   **NewHandle,\r
+  IN  CHAR16     *FileName,\r
+  IN  UINT64     OpenMode,\r
+  IN  UINT64     Attributes\r
+  )\r
+/*++\r
+Routine Description:\r
+\r
+  Implements Open() of Simple File System Protocol.\r
+  \r
+Arguments:\r
+\r
+  FHand                 - File handle of the file serves as a starting reference point.\r
+  NewHandle             - Handle of the file that is newly opened.\r
+  FileName              - File name relative to FHand.\r
+  OpenMode              - Open mode.\r
+  Attributes            - Attributes to set if the file is created.\r
+  \r
+Returns:\r
+\r
+  EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.\r
+                          The OpenMode is not supported.\r
+                          The Attributes is not the valid attributes.\r
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory for file string.\r
+  EFI_SUCCESS           - Open the file successfully.\r
+  Others                - The status of open file.\r
+\r
+--*/\r
+{\r
+  FAT_IFILE   *IFile;\r
+  FAT_IFILE   *NewIFile;\r
+  FAT_OFILE   *OFile;\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Perform some parameter checking\r
+  //\r
+  if (FileName == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Check for a valid mode\r
+  //\r
+  switch (OpenMode) {\r
+  case EFI_FILE_MODE_READ:\r
+  case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:\r
+  case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:\r
+    break;\r
+\r
+  default:\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Check for valid attributes\r
+  //\r
+  if (Attributes & (~EFI_FILE_VALID_ATTR)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Can't open for create and apply the read only attribute\r
+  //\r
+  if ((OpenMode & EFI_FILE_MODE_CREATE) && (Attributes & EFI_FILE_READ_ONLY)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  IFile = IFILE_FROM_FHAND (FHand);\r
+  OFile = IFile->OFile;\r
+\r
+  //\r
+  // Lock\r
+  //\r
+  FatAcquireLock ();\r
+\r
+  //\r
+  // Open the file\r
+  //\r
+  Status = FatOFileOpen (OFile, &NewIFile, FileName, OpenMode, (UINT8) Attributes);\r
+\r
+  //\r
+  // If the file was opened, return the handle to the caller\r
+  //\r
+  if (!EFI_ERROR (Status)) {\r
+    *NewHandle = &NewIFile->Handle;\r
+  }\r
+  //\r
+  // Unlock\r
+  //\r
+  Status = FatCleanupVolume (OFile->Volume, NULL, Status);\r
+  FatReleaseLock ();\r
+\r
+  return Status;\r
+}\r
diff --git a/EnhancedFat/Dxe/OpenVolume.c b/EnhancedFat/Dxe/OpenVolume.c
new file mode 100644 (file)
index 0000000..4e7841e
--- /dev/null
@@ -0,0 +1,76 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  OpenVolume.c\r
+  \r
+Abstract:\r
+\r
+  OpenVolume() function of Simple File System Protocol\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatOpenVolume (\r
+  IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *This,\r
+  OUT EFI_FILE                         **File\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Implements Simple File System Protocol interface function OpenVolume().\r
+  \r
+Arguments:\r
+\r
+  This                  - Calling context.\r
+  File                  - the Root Directory of the volume.\r
+\r
+Returns:\r
+\r
+  EFI_OUT_OF_RESOURCES  - Can not allocate the memory.\r
+  EFI_VOLUME_CORRUPTED  - The FAT type is error.\r
+  EFI_SUCCESS           - Open the volume successfully.\r
+  \r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  FAT_VOLUME  *Volume;\r
+  FAT_IFILE   *IFile;\r
+\r
+  Volume = VOLUME_FROM_VOL_INTERFACE (This);\r
+  FatAcquireLock ();\r
+\r
+  //\r
+  // Open Root file\r
+  //\r
+  Status = FatOpenDirEnt (NULL, &Volume->RootDirEnt);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Open a new instance to the root\r
+  //\r
+  Status = FatAllocateIFile (Volume->Root, &IFile);\r
+  if (!EFI_ERROR (Status)) {\r
+    *File = &IFile->Handle;\r
+  }\r
+\r
+Done:\r
+\r
+  Status = FatCleanupVolume (Volume, Volume->Root, Status);\r
+  FatReleaseLock ();\r
+\r
+  return Status;\r
+}\r
diff --git a/EnhancedFat/Dxe/ReadWrite.c b/EnhancedFat/Dxe/ReadWrite.c
new file mode 100644 (file)
index 0000000..219653f
--- /dev/null
@@ -0,0 +1,608 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the Software \r
+License Agreement which accompanies this distribution.\r
+\r
+\r
+Module Name:\r
+\r
+  ReadWrite.c\r
+  \r
+Abstract:\r
+\r
+  Functions that perform file read/write\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatGetPosition (\r
+  IN  EFI_FILE          *FHand,\r
+  OUT UINT64            *Position\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Get the file's position of the file.\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of file.\r
+  Position              - The file's position of the file.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Get the info successfully.\r
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.\r
+  EFI_UNSUPPORTED       - The open file is not a file.\r
+\r
+--*/\r
+{\r
+  FAT_IFILE *IFile;\r
+  FAT_OFILE *OFile;\r
+\r
+  IFile = IFILE_FROM_FHAND (FHand);\r
+  OFile = IFile->OFile;\r
+\r
+  if (OFile->Error == EFI_NOT_FOUND) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (OFile->ODir != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  *Position = IFile->Position;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatSetPosition (\r
+  IN EFI_FILE  *FHand,\r
+  IN UINT64    Position\r
+  )\r
+/*++\r
+   \r
+Routine Description:\r
+\r
+  Set the file's position of the file.\r
+\r
+Arguments:\r
+\r
+  FHand                 - The handle of file.\r
+  Position              - The file's position of the file. \r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Set the info successfully.\r
+  EFI_DEVICE_ERROR      - Can not find the OFile for the file.\r
+  EFI_UNSUPPORTED       - Set a directory with a not-zero position.\r
+\r
+--*/\r
+{\r
+  FAT_IFILE *IFile;\r
+  FAT_OFILE *OFile;\r
+\r
+  IFile = IFILE_FROM_FHAND (FHand);\r
+  OFile = IFile->OFile;\r
+\r
+  if (OFile->Error == EFI_NOT_FOUND) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // If this is a directory, we can only set back to position 0\r
+  //\r
+  if (OFile->ODir != NULL) {\r
+    if (Position != 0) {\r
+      //\r
+      // Reset current directory cursor;\r
+      //\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    FatResetODirCursor (OFile);\r
+  }\r
+  //\r