summaryrefslogtreecommitdiff
path: root/FatPkg
diff options
context:
space:
mode:
authorQing Huang <qing.huang@intel.com>2007-12-20 09:16:45 +0000
committerJordan Justen <jordan.l.justen@intel.com>2016-04-06 23:22:43 -0700
commitb9ec93308b33bcb0bb37d6213a76c3fed0b5bc0b (patch)
treeed4cc299df8f82781a6e6fae2022d2411ddc9c89 /FatPkg
parentf0dc69e61bf2316dcf7cc75eb7e4ba374a5b2832 (diff)
downloadedk2-platforms-b9ec93308b33bcb0bb37d6213a76c3fed0b5bc0b.tar.xz
Add EDK II Prime FatPkg New Feature: Support both Unicode Collation and Unicode Collation 2 Protocols Support both Component Name and Component Name 2 Protocol.
(based on FatPkg commit e51cd032db84a6fb1f44a0605f80d96f5fdf4bc6) [jordan.l.justen@intel.com: Use script to relicense to 2-clause BSD] Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen <jordan.l.justen@intel.com> Acked-by: Mark Doran <mark.doran@intel.com> Acked-by: Laszlo Ersek <lersek@redhat.com>
Diffstat (limited to 'FatPkg')
-rw-r--r--FatPkg/EnhancedFatDxe/ComponentName.c355
-rw-r--r--FatPkg/EnhancedFatDxe/Data.c50
-rw-r--r--FatPkg/EnhancedFatDxe/Debug.c80
-rw-r--r--FatPkg/EnhancedFatDxe/Delete.c138
-rw-r--r--FatPkg/EnhancedFatDxe/DirectoryCache.c238
-rw-r--r--FatPkg/EnhancedFatDxe/DirectoryManage.c1563
-rw-r--r--FatPkg/EnhancedFatDxe/DiskCache.c541
-rw-r--r--FatPkg/EnhancedFatDxe/Fat.c393
-rw-r--r--FatPkg/EnhancedFatDxe/Fat.h1119
-rw-r--r--FatPkg/EnhancedFatDxe/Fat.inf98
-rw-r--r--FatPkg/EnhancedFatDxe/FatFileSystem.h221
-rw-r--r--FatPkg/EnhancedFatDxe/FileName.c583
-rw-r--r--FatPkg/EnhancedFatDxe/FileSpace.c816
-rw-r--r--FatPkg/EnhancedFatDxe/Flush.c480
-rw-r--r--FatPkg/EnhancedFatDxe/Hash.c217
-rw-r--r--FatPkg/EnhancedFatDxe/Info.c625
-rw-r--r--FatPkg/EnhancedFatDxe/Init.c431
-rw-r--r--FatPkg/EnhancedFatDxe/Misc.c409
-rw-r--r--FatPkg/EnhancedFatDxe/Open.c285
-rw-r--r--FatPkg/EnhancedFatDxe/OpenVolume.c80
-rw-r--r--FatPkg/EnhancedFatDxe/ReadWrite.c612
-rw-r--r--FatPkg/EnhancedFatDxe/UnicodeCollation.c324
-rw-r--r--FatPkg/FatPkg.dec29
-rw-r--r--FatPkg/FatPkg.dsc49
-rw-r--r--FatPkg/License.txt11
-rw-r--r--FatPkg/ReadMe.txt7
26 files changed, 9754 insertions, 0 deletions
diff --git a/FatPkg/EnhancedFatDxe/ComponentName.c b/FatPkg/EnhancedFatDxe/ComponentName.c
new file mode 100644
index 0000000000..ef06c8db11
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/ComponentName.c
@@ -0,0 +1,355 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ ComponentName.c
+
+Abstract:
+
+--*/
+
+#include "Fat.h"
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 3066 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+FatComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 3066 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+FatComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gFatComponentName = {
+ FatComponentNameGetDriverName,
+ FatComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gFatComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) FatComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) FatComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFatDriverNameTable[] = {
+ {
+ "eng;en",
+ L"FAT File System Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFatControllerNameTable[] = {
+ {
+ "eng;en",
+ L"FAT File System"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 3066 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+FatComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mFatDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gFatComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 3066 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+FatComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gFatDriverBinding.DriverBindingHandle,
+ &gEfiDiskIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mFatControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gFatComponentName)
+ );
+}
diff --git a/FatPkg/EnhancedFatDxe/Data.c b/FatPkg/EnhancedFatDxe/Data.c
new file mode 100644
index 0000000000..2f8faa819b
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Data.c
@@ -0,0 +1,50 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Data.c
+
+Abstract:
+
+ Global data in the FAT Filesystem driver
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+//
+// Globals
+//
+//
+// FatFsLock - Global lock for synchronizing all requests.
+//
+EFI_LOCK FatFsLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_CALLBACK);
+
+//
+// Filesystem interface functions
+//
+EFI_FILE FatFileInterface = {
+ EFI_FILE_PROTOCOL_REVISION,
+ FatOpen,
+ FatClose,
+ FatDelete,
+ FatRead,
+ FatWrite,
+ FatGetPosition,
+ FatSetPosition,
+ FatGetInfo,
+ FatSetInfo,
+ FatFlush
+};
diff --git a/FatPkg/EnhancedFatDxe/Debug.c b/FatPkg/EnhancedFatDxe/Debug.c
new file mode 100644
index 0000000000..6eb116ed12
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Debug.c
@@ -0,0 +1,80 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ debug.c
+
+Abstract:
+
+ Debug functions for fat driver
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+VOID
+FatDumpFatTable (
+ IN FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Dump all the FAT Entry of the FAT table in the volume
+
+Arguments:
+
+ Volume - The volume whose FAT info will be dumped
+
+Returns:
+
+ None
+
+--*/
+{
+ UINTN EntryValue;
+ UINTN MaxIndex;
+ UINTN Index;
+ CHAR16 *Pointer;
+
+ MaxIndex = Volume->MaxCluster + 2;
+
+ Print (L"Dump of Fat Table, MaxCluster %x\n", MaxIndex);
+ for (Index = 0; Index < MaxIndex; Index++) {
+ EntryValue = FatGetFatEntry (Volume, Index);
+ if (EntryValue != FAT_CLUSTER_FREE) {
+ Pointer = NULL;
+ switch (EntryValue) {
+ case FAT_CLUSTER_RESERVED:
+ Pointer = L"RESREVED";
+ break;
+
+ case FAT_CLUSTER_BAD:
+ Pointer = L"BAD";
+ break;
+ }
+
+ if (FAT_END_OF_FAT_CHAIN (EntryValue)) {
+ Pointer = L"LAST";
+ }
+
+ if (Pointer != NULL) {
+ Print (L"Entry %x = %s\n", Index, Pointer);
+ } else {
+ Print (L"Entry %x = %x\n", Index, EntryValue);
+ }
+ }
+ }
+}
diff --git a/FatPkg/EnhancedFatDxe/Delete.c b/FatPkg/EnhancedFatDxe/Delete.c
new file mode 100644
index 0000000000..b76fe45eca
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Delete.c
@@ -0,0 +1,138 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ delete.c
+
+Abstract:
+
+ Function that deletes a file
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatDelete (
+ IN EFI_FILE *FHand
+ )
+/*++
+
+Routine Description:
+
+ Deletes the file & Closes the file handle.
+
+Arguments:
+
+ FHand - Handle to the file to delete.
+
+Returns:
+
+ EFI_SUCCESS - Delete the file successfully.
+ EFI_WARN_DELETE_FAILURE - Fail to delete the file.
+
+--*/
+{
+ FAT_IFILE *IFile;
+ FAT_OFILE *OFile;
+ FAT_DIRENT *DirEnt;
+ EFI_STATUS Status;
+ UINTN Round;
+
+ IFile = IFILE_FROM_FHAND (FHand);
+ OFile = IFile->OFile;
+
+ //
+ // Lock the volume
+ //
+ FatAcquireLock ();
+
+ //
+ // If the file is read-only, then don't delete it
+ //
+ if (IFile->ReadOnly) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+ //
+ // If the file is the root dir, then don't delete it
+ //
+ if (OFile->Parent == NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ //
+ // If the file has a permanant error, skip the delete
+ //
+ Status = OFile->Error;
+ if (!EFI_ERROR (Status)) {
+ //
+ // If this is a directory, make sure it's empty before
+ // allowing it to be deleted
+ //
+ if (OFile->ODir != NULL) {
+ //
+ // We do not allow to delete nonempty directory
+ //
+ FatResetODirCursor (OFile);
+ for (Round = 0; Round < 3; Round++) {
+ Status = FatGetNextDirEnt (OFile, &DirEnt);
+ if ((EFI_ERROR (Status)) ||
+ ((Round < 2) && (DirEnt == NULL || !FatIsDotDirEnt (DirEnt))) ||
+ ((Round == 2) && (DirEnt != NULL))
+ ) {
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ }
+ }
+ //
+ // Return the file's space by setting its size to 0
+ //
+ FatTruncateOFile (OFile, 0);
+ //
+ // Free the directory entry for this file
+ //
+ Status = FatRemoveDirEnt (OFile->Parent, OFile->DirEnt);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Set a permanent error for this OFile in case there
+ // are still opened IFiles attached
+ //
+ OFile->Error = EFI_NOT_FOUND;
+ } else if (OFile->Error == EFI_NOT_FOUND) {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ //
+ // Always close the handle
+ //
+ FatIFileClose (IFile);
+ //
+ // Done
+ //
+ Status = FatCleanupVolume (OFile->Volume, NULL, Status);
+ FatReleaseLock ();
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_WARN_DELETE_FAILURE;
+ }
+
+ return Status;
+}
diff --git a/FatPkg/EnhancedFatDxe/DirectoryCache.c b/FatPkg/EnhancedFatDxe/DirectoryCache.c
new file mode 100644
index 0000000000..1cb8b9f117
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/DirectoryCache.c
@@ -0,0 +1,238 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ DirectoryCache.c
+
+Abstract:
+
+ Functions for directory cache operation
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+STATIC
+VOID
+FatFreeODir (
+ IN FAT_ODIR *ODir
+ )
+/*++
+
+Routine Description:
+
+ Free the directory structure and release the memory.
+
+Arguments:
+
+ ODir - The directory to be freed.
+
+Returns:
+
+ None.
+
+--*/
+{
+ FAT_DIRENT *DirEnt;
+
+ //
+ // Release Directory Entry Nodes
+ //
+ while (!IsListEmpty (&ODir->ChildList)) {
+ DirEnt = DIRENT_FROM_LINK (ODir->ChildList.ForwardLink);
+ RemoveEntryList (&DirEnt->Link);
+ //
+ // Make sure the OFile has been closed
+ //
+ ASSERT (DirEnt->OFile == NULL);
+ FatFreeDirEnt (DirEnt);
+ }
+
+ FreePool (ODir);
+}
+
+STATIC
+FAT_ODIR *
+FatAllocateODir (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Allocate the directory structure.
+
+Arguments:
+
+ OFile - The corresponding OFile.
+
+Returns:
+
+ None.
+
+--*/
+{
+ FAT_ODIR *ODir;
+
+ ODir = AllocateZeroPool (sizeof (FAT_ODIR));
+ if (ODir != NULL) {
+ //
+ // Initialize the directory entry list
+ //
+ ODir->Signature = FAT_ODIR_SIGNATURE;
+ InitializeListHead (&ODir->ChildList);
+ ODir->CurrentCursor = &ODir->ChildList;
+ }
+
+ return ODir;
+}
+
+VOID
+FatDiscardODir (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Discard the directory structure when an OFile will be freed.
+ Volume will cache this directory if the OFile does not represent a deleted file.
+
+Arguments:
+
+ OFile - The OFile whose directory structure is to be discarded.
+
+Returns:
+
+ None.
+
+--*/
+{
+ FAT_ODIR *ODir;
+ FAT_VOLUME *Volume;
+
+ Volume = OFile->Volume;
+ ODir = OFile->ODir;
+ if (!OFile->DirEnt->Invalid) {
+ //
+ // If OFile does not represent a deleted file, then we will cache the directory
+ // We use OFile's first cluster as the directory's tag
+ //
+ ODir->DirCacheTag = OFile->FileCluster;
+ InsertHeadList (&Volume->DirCacheList, &ODir->DirCacheLink);
+ if (Volume->DirCacheCount == FAT_MAX_DIR_CACHE_COUNT) {
+ //
+ // Replace the least recent used directory
+ //
+ ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);
+ RemoveEntryList (&ODir->DirCacheLink);
+ } else {
+ //
+ // No need to find a replace
+ //
+ Volume->DirCacheCount++;
+ ODir = NULL;
+ }
+ }
+ //
+ // Release ODir Structure
+ //
+ if (ODir != NULL) {
+ FatFreeODir (ODir);
+ }
+}
+
+VOID
+FatRequestODir (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Request the directory structure when an OFile is newly generated.
+ If the directory structure is cached by volume, then just return this directory;
+ Otherwise, allocate a new one for OFile.
+
+Arguments:
+
+ OFile - The OFile which requests directory structure.
+
+Returns:
+
+ None.
+
+--*/
+{
+ UINTN DirCacheTag;
+ FAT_VOLUME *Volume;
+ FAT_ODIR *ODir;
+ FAT_ODIR *CurrentODir;
+ LIST_ENTRY *CurrentODirLink;
+
+ Volume = OFile->Volume;
+ ODir = NULL;
+ DirCacheTag = OFile->FileCluster;
+ for (CurrentODirLink = Volume->DirCacheList.ForwardLink;
+ CurrentODirLink != &Volume->DirCacheList;
+ CurrentODirLink = CurrentODirLink->ForwardLink
+ ) {
+ CurrentODir = ODIR_FROM_DIRCACHELINK (CurrentODirLink);
+ if (CurrentODir->DirCacheTag == DirCacheTag) {
+ RemoveEntryList (&CurrentODir->DirCacheLink);
+ Volume->DirCacheCount--;
+ ODir = CurrentODir;
+ break;
+ }
+ }
+
+ if (ODir == NULL) {
+ //
+ // This directory is not cached, then allocate a new one
+ //
+ ODir = FatAllocateODir (OFile);
+ }
+
+ OFile->ODir = ODir;
+}
+
+VOID
+FatCleanupODirCache (
+ IN FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Clean up all the cached directory structures when the volume is going to be abandoned.
+
+Arguments:
+
+ Volume - FAT file system volume.
+
+Returns:
+
+ None.
+
+--*/
+{
+ FAT_ODIR *ODir;
+ while (Volume->DirCacheCount > 0) {
+ ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);
+ RemoveEntryList (&ODir->DirCacheLink);
+ FatFreeODir (ODir);
+ Volume->DirCacheCount--;
+ }
+}
diff --git a/FatPkg/EnhancedFatDxe/DirectoryManage.c b/FatPkg/EnhancedFatDxe/DirectoryManage.c
new file mode 100644
index 0000000000..5e9d1e3240
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/DirectoryManage.c
@@ -0,0 +1,1563 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ DirectoryManage.c
+
+Abstract:
+
+ Functions for performing directory entry io
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+STATIC
+EFI_STATUS
+FatAccessEntry (
+ IN FAT_OFILE *Parent,
+ IN IO_MODE IoMode,
+ IN UINTN EntryPos,
+ IN OUT VOID *Entry
+ )
+/*++
+
+Routine Description:
+
+ Get a directory entry from disk for the Ofile.
+
+Arguments:
+
+ Parent - The parent of the OFile which need to update.
+ IoMode - Indicate whether to read directory entry or write directroy entry.
+ EntryPos - The position of the directory entry to be accessed.
+ Entry - The directory entry read or written.
+
+Returns:
+
+ EFI_SUCCESS - Access the directory entry sucessfully.
+ other - An error occurred when reading the directory entry.
+
+--*/
+{
+ UINTN Position;
+ UINTN BufferSize;
+
+ Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY);
+ if (Position >= Parent->FileSize) {
+ //
+ // End of directory
+ //
+ ASSERT (IoMode == READ_DATA);
+ ((FAT_DIRECTORY_ENTRY *) Entry)->FileName[0] = EMPTY_ENTRY_MARK;
+ ((FAT_DIRECTORY_ENTRY *) Entry)->Attributes = 0;
+ return EFI_SUCCESS;
+ }
+
+ BufferSize = sizeof (FAT_DIRECTORY_ENTRY);
+ return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry);
+}
+
+EFI_STATUS
+FatStoreDirEnt (
+ IN FAT_OFILE *OFile,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Save the directory entry to disk.
+
+Arguments:
+
+ OFile - The parent OFile which needs to update.
+ DirEnt - The directory entry to be saved.
+
+Returns:
+
+ EFI_SUCCESS - Store the directory entry successfully.
+ other - An error occurred when writing the directory entry.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_DIRECTORY_LFN LfnEntry;
+ UINTN EntryPos;
+ CHAR16 *LfnBufferPointer;
+ CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
+ UINT8 EntryCount;
+ UINT8 LfnOrdinal;
+
+ EntryPos = DirEnt->EntryPos;
+ EntryCount = DirEnt->EntryCount;
+ //
+ // Write directory entry
+ //
+ Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &DirEnt->Entry);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (--EntryCount > 0) {
+ //
+ // Write LFN directory entry
+ //
+ SetMem (LfnBuffer, sizeof (CHAR16) * LFN_CHAR_TOTAL * EntryCount, 0xff);
+ StrCpy (LfnBuffer, DirEnt->FileString);
+ LfnBufferPointer = LfnBuffer;
+ LfnEntry.Attributes = FAT_ATTRIBUTE_LFN;
+ LfnEntry.Type = 0;
+ LfnEntry.MustBeZero = 0;
+ LfnEntry.Checksum = FatCheckSum (DirEnt->Entry.FileName);
+ for (LfnOrdinal = 1; LfnOrdinal <= EntryCount; LfnOrdinal++) {
+ LfnEntry.Ordinal = LfnOrdinal;
+ if (LfnOrdinal == EntryCount) {
+ LfnEntry.Ordinal |= FAT_LFN_LAST;
+ }
+
+ CopyMem (LfnEntry.Name1, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR1_LEN);
+ LfnBufferPointer += LFN_CHAR1_LEN;
+ CopyMem (LfnEntry.Name2, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR2_LEN);
+ LfnBufferPointer += LFN_CHAR2_LEN;
+ CopyMem (LfnEntry.Name3, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR3_LEN);
+ LfnBufferPointer += LFN_CHAR3_LEN;
+ EntryPos--;
+ if (DirEnt->Invalid) {
+ LfnEntry.Ordinal = DELETE_ENTRY_MARK;
+ }
+
+ Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &LfnEntry);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+FatIsDotDirEnt (
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Determine whether the directory entry is "." or ".." entry.
+
+Arguments:
+
+ DirEnt - The corresponding directory entry.
+
+Returns:
+
+ TRUE - The directory entry is "." or ".." directory entry
+ FALSE - The directory entry is not "." or ".." directory entry
+
+--*/
+{
+ CHAR16 *FileString;
+ FileString = DirEnt->FileString;
+ if (StrCmp (FileString, L".") == 0 || StrCmp (FileString, L"..") == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+STATIC
+VOID
+FatSetDirEntCluster (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Set the OFile's cluster info in its directory entry.
+
+Arguments:
+
+ OFile - The corresponding OFile.
+
+Returns:
+
+ None.
+
+--*/
+{
+ UINTN Cluster;
+ FAT_DIRENT *DirEnt;
+
+ DirEnt = OFile->DirEnt;
+ Cluster = OFile->FileCluster;
+ DirEnt->Entry.FileClusterHigh = (UINT16) (Cluster >> 16);
+ DirEnt->Entry.FileCluster = (UINT16) Cluster;
+}
+
+VOID
+FatUpdateDirEntClusterSizeInfo (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Set the OFile's cluster and size info in its directory entry.
+
+Arguments:
+
+ OFile - The corresponding OFile.
+
+Returns:
+
+ None.
+
+--*/
+{
+ ASSERT (OFile->ODir == NULL);
+ OFile->DirEnt->Entry.FileSize = (UINT32) OFile->FileSize;
+ FatSetDirEntCluster (OFile);
+}
+
+VOID
+FatCloneDirEnt (
+ IN FAT_DIRENT *DirEnt1,
+ IN FAT_DIRENT *DirEnt2
+ )
+/*++
+
+Routine Description:
+
+ Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
+
+Arguments:
+
+ DirEnt1 - The destination directory entry.
+ DirEnt2 - The source directory entry.
+
+Returns:
+
+ None.
+
+--*/
+{
+ UINT8 *Entry1;
+ UINT8 *Entry2;
+ Entry1 = (UINT8 *) &DirEnt1->Entry;
+ Entry2 = (UINT8 *) &DirEnt2->Entry;
+ CopyMem (
+ Entry1 + FAT_ENTRY_INFO_OFFSET,
+ Entry2 + FAT_ENTRY_INFO_OFFSET,
+ sizeof (FAT_DIRECTORY_ENTRY) - FAT_ENTRY_INFO_OFFSET
+ );
+}
+
+STATIC
+VOID
+FatLoadLongNameEntry (
+ IN FAT_OFILE *Parent,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Get the LFN for the directory entry.
+
+Arguments:
+
+ Parent - The parent directory.
+ DirEnt - The directory entry to get LFN.
+
+Returns:
+
+ None.
+
+--*/
+{
+ CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
+ CHAR16 *LfnBufferPointer;
+ CHAR8 *File8Dot3Name;
+ UINTN EntryPos;
+ UINT8 LfnOrdinal;
+ UINT8 LfnChecksum;
+ FAT_DIRECTORY_LFN LfnEntry;
+ EFI_STATUS Status;
+
+ EntryPos = DirEnt->EntryPos;
+ File8Dot3Name = DirEnt->Entry.FileName;
+ LfnBufferPointer = LfnBuffer;
+ //
+ // Computes checksum for LFN
+ //
+ LfnChecksum = FatCheckSum (File8Dot3Name);
+ LfnOrdinal = 1;
+ do {
+ if (EntryPos == 0) {
+ LfnBufferPointer = LfnBuffer;
+ break;
+ }
+
+ EntryPos--;
+ Status = FatAccessEntry (Parent, READ_DATA, EntryPos, &LfnEntry);
+ if (EFI_ERROR (Status) ||
+ LfnEntry.Attributes != FAT_ATTRIBUTE_LFN ||
+ LfnEntry.MustBeZero != 0 ||
+ LfnEntry.Checksum != LfnChecksum ||
+ (LfnEntry.Ordinal & (~FAT_LFN_LAST)) != LfnOrdinal ||
+ LfnOrdinal > MAX_LFN_ENTRIES
+ ) {
+ //
+ // The directory entry does not have a long file name or
+ // some error occurs when loading long file name for a directory entry,
+ // and then we load the long name from short name
+ //
+ LfnBufferPointer = LfnBuffer;
+ break;
+ }
+
+ CopyMem (LfnBufferPointer, LfnEntry.Name1, sizeof (CHAR16) * LFN_CHAR1_LEN);
+ LfnBufferPointer += LFN_CHAR1_LEN;
+ CopyMem (LfnBufferPointer, LfnEntry.Name2, sizeof (CHAR16) * LFN_CHAR2_LEN);
+ LfnBufferPointer += LFN_CHAR2_LEN;
+ CopyMem (LfnBufferPointer, LfnEntry.Name3, sizeof (CHAR16) * LFN_CHAR3_LEN);
+ LfnBufferPointer += LFN_CHAR3_LEN;
+ LfnOrdinal++;
+ } while ((LfnEntry.Ordinal & FAT_LFN_LAST) == 0);
+ DirEnt->EntryCount = LfnOrdinal;
+ //
+ // Terminate current Lfnbuffer
+ //
+ *LfnBufferPointer = 0;
+ if (LfnBufferPointer == LfnBuffer) {
+ //
+ // Fail to get the long file name from long file name entry,
+ // get the file name from short name
+ //
+ FatGetFileNameViaCaseFlag (DirEnt, LfnBuffer);
+ }
+
+ DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer);
+}
+
+STATIC
+VOID
+FatAddDirEnt (
+ IN FAT_ODIR *ODir,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Add this directory entry node to the list of directory entries and hash table.
+
+Arguments:
+
+ ODir - The parent OFile which needs to be updated.
+ DirEnt - The directory entry to be added.
+
+Returns:
+
+ None.
+
+--*/
+{
+ if (DirEnt->Link.BackLink == NULL) {
+ DirEnt->Link.BackLink = &ODir->ChildList;
+ }
+ InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link);
+ FatInsertToHashTable (ODir, DirEnt);
+}
+
+STATIC
+EFI_STATUS
+FatLoadNextDirEnt (
+ IN FAT_OFILE *OFile,
+ OUT FAT_DIRENT **PtrDirEnt
+ )
+/*++
+
+Routine Description:
+
+ Load from disk the next directory entry at current end of directory position
+
+Arguments:
+
+ OFile - The parent OFile.
+ PtrDirEnt - The directory entry that is loaded.
+
+Returns:
+
+ EFI_SUCCESS - Load the directory entry successfully.
+ EFI_OUT_OF_RESOURCES - Out of resource.
+ other - An error occurred when reading the directory entries.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_DIRENT *DirEnt;
+ FAT_ODIR *ODir;
+ FAT_DIRECTORY_ENTRY Entry;
+
+ ODir = OFile->ODir;
+ //
+ // Make sure the parent's directory has been opened
+ //
+ ASSERT (ODir != NULL);
+ //
+ // Assert we have not reached the end of directory
+ //
+ ASSERT (!ODir->EndOfDir);
+ DirEnt = NULL;
+
+ for (;;) {
+ //
+ // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
+ //
+ Status = FatAccessEntry (OFile, READ_DATA, ODir->CurrentEndPos, &Entry);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (((UINT8) Entry.FileName[0] != DELETE_ENTRY_MARK) && (Entry.Attributes & FAT_ATTRIBUTE_VOLUME_ID) == 0) {
+ //
+ // We get a valid directory entry, then handle it
+ //
+ break;
+ }
+
+ ODir->CurrentEndPos++;
+ }
+
+ if (Entry.FileName[0] != EMPTY_ENTRY_MARK) {
+ //
+ // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications
+ // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.
+ //
+ if (OFile->Volume->FatType != FAT32) {
+ Entry.FileClusterHigh = 0;
+ }
+
+ //
+ // This is a valid directory entry
+ //
+ DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
+ if (DirEnt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DirEnt->Signature = FAT_DIRENT_SIGNATURE;
+ //
+ // Remember the directory's entry position on disk
+ //
+ DirEnt->EntryPos = (UINT16) ODir->CurrentEndPos;
+ CopyMem (&DirEnt->Entry, &Entry, sizeof (FAT_DIRECTORY_ENTRY));
+ FatLoadLongNameEntry (OFile, DirEnt);
+ if (DirEnt->FileString == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Add this directory entry to directory
+ //
+ FatAddDirEnt (ODir, DirEnt);
+ //
+ // Point to next directory entry
+ //
+ ODir->CurrentEndPos++;
+ } else {
+ ODir->EndOfDir = TRUE;
+ }
+
+ *PtrDirEnt = DirEnt;
+ return EFI_SUCCESS;
+
+Done:
+ FatFreeDirEnt (DirEnt);
+ return Status;
+}
+
+EFI_STATUS
+FatGetDirEntInfo (
+ IN FAT_VOLUME *Volume,
+ IN FAT_DIRENT *DirEnt,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the directory entry's info into Buffer.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ DirEnt - The corresponding directory entry.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing file info.
+
+Returns:
+
+ EFI_SUCCESS - Get the file info successfully.
+ EFI_BUFFER_TOO_SMALL - The buffer is too small.
+
+--*/
+{
+ UINTN Size;
+ UINTN NameSize;
+ UINTN ResultSize;
+ UINTN Cluster;
+ EFI_STATUS Status;
+ EFI_FILE_INFO *Info;
+ FAT_DIRECTORY_ENTRY *Entry;
+ FAT_DATE_TIME FatLastAccess;
+
+ ASSERT_VOLUME_LOCKED (Volume);
+
+ Size = SIZE_OF_EFI_FILE_INFO;
+ NameSize = StrSize (DirEnt->FileString);
+ ResultSize = Size + NameSize;
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*BufferSize >= ResultSize) {
+ Status = EFI_SUCCESS;
+ Entry = &DirEnt->Entry;
+ Info = Buffer;
+ Info->Size = ResultSize;
+ if ((Entry->Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
+ Cluster = (Entry->FileClusterHigh << 16) | Entry->FileCluster;
+ Info->PhysicalSize = FatPhysicalDirSize (Volume, Cluster);
+ Info->FileSize = Info->PhysicalSize;
+ } else {
+ Info->FileSize = Entry->FileSize;
+ Info->PhysicalSize = FatPhysicalFileSize (Volume, Entry->FileSize);
+ }
+
+ ZeroMem (&FatLastAccess.Time, sizeof (FatLastAccess.Time));
+ CopyMem (&FatLastAccess.Date, &Entry->FileLastAccess, sizeof (FatLastAccess.Date));
+ FatFatTimeToEfiTime (&FatLastAccess, &Info->LastAccessTime);
+ FatFatTimeToEfiTime (&Entry->FileCreateTime, &Info->CreateTime);
+ FatFatTimeToEfiTime (&Entry->FileModificationTime, &Info->ModificationTime);
+ Info->Attribute = Entry->Attributes & EFI_FILE_VALID_ATTR;
+ CopyMem ((CHAR8 *) Buffer + Size, DirEnt->FileString, NameSize);
+ }
+
+ *BufferSize = ResultSize;
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+FatSearchODir (
+ IN FAT_OFILE *OFile,
+ IN CHAR16 *FileNameString,
+ OUT FAT_DIRENT **PtrDirEnt
+ )
+/*++
+
+Routine Description:
+
+ Search the directory for the directory entry whose filename is FileNameString.
+
+Arguments:
+
+ OFile - The parent OFile whose directory is to be searched.
+ FileNameString - The filename to be searched.
+ PtrDirEnt - pointer to the directory entry if found.
+
+Returns:
+
+ EFI_SUCCESS - Find the directory entry or not found.
+ other - An error occurred when reading the directory entries.
+
+--*/
+{
+ BOOLEAN PossibleShortName;
+ CHAR8 File8Dot3Name[FAT_NAME_LEN];
+ FAT_ODIR *ODir;
+ FAT_DIRENT *DirEnt;
+ EFI_STATUS Status;
+
+ ODir = OFile->ODir;
+ ASSERT (ODir != NULL);
+ //
+ // Check if the file name is a valid short name
+ //
+ PossibleShortName = FatCheckIs8Dot3Name (FileNameString, File8Dot3Name);
+ //
+ // Search the hash table first
+ //
+ DirEnt = *FatLongNameHashSearch (ODir, FileNameString);
+ if (DirEnt == NULL && PossibleShortName) {
+ DirEnt = *FatShortNameHashSearch (ODir, File8Dot3Name);
+ }
+ if (DirEnt == NULL) {
+ //
+ // We fail to get the directory entry from hash table; we then
+ // search the rest directory
+ //
+ while (!ODir->EndOfDir) {
+ Status = FatLoadNextDirEnt (OFile, &DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (DirEnt != NULL) {
+ if (FatStriCmp (FileNameString, DirEnt->FileString) == 0) {
+ break;
+ }
+
+ if (PossibleShortName && CompareMem (File8Dot3Name, DirEnt->Entry.FileName, FAT_NAME_LEN) == 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ *PtrDirEnt = DirEnt;
+ return EFI_SUCCESS;
+}
+
+VOID
+FatResetODirCursor (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Set the OFile's current directory cursor to the list head.
+
+Arguments:
+
+ OFile - The directory OFile whose directory cursor is reset.
+
+Returns:
+
+ None.
+
+--*/
+{
+ FAT_ODIR *ODir;
+
+ ODir = OFile->ODir;
+ ASSERT (ODir != NULL);
+ ODir->CurrentCursor = &(ODir->ChildList);
+ ODir->CurrentPos = 0;
+}
+
+EFI_STATUS
+FatGetNextDirEnt (
+ IN FAT_OFILE *OFile,
+ OUT FAT_DIRENT **PtrDirEnt
+ )
+/*++
+
+Routine Description:
+
+ Set the directory’s cursor to the next and get the next directory entry.
+
+Arguments:
+
+ OFile - The parent OFile.
+ PtrDirEnt - The next directory entry.
+
+Returns:
+
+ EFI_SUCCESS - We get the next directory entry successfully.
+ other - An error occurred when get next directory entry.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_DIRENT *DirEnt;
+ FAT_ODIR *ODir;
+
+ ODir = OFile->ODir;
+ ASSERT (ODir != NULL);
+ if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
+ //
+ // End of directory, we will try one more time
+ //
+ if (!ODir->EndOfDir) {
+ //
+ // Read directory from disk
+ //
+ Status = FatLoadNextDirEnt (OFile, &DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
+ //
+ // End of directory, return NULL
+ //
+ DirEnt = NULL;
+ ODir->CurrentPos = ODir->CurrentEndPos;
+ } else {
+ ODir->CurrentCursor = ODir->CurrentCursor->ForwardLink;
+ DirEnt = DIRENT_FROM_LINK (ODir->CurrentCursor);
+ ODir->CurrentPos = DirEnt->EntryPos + 1;
+ }
+
+ *PtrDirEnt = DirEnt;
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+FatSetEntryCount (
+ IN FAT_OFILE *OFile,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Set the directory entry count according to the filename.
+
+Arguments:
+
+ OFile - The corresponding OFile.
+ DirEnt - The directory entry to be set.
+
+Returns:
+
+ None.
+
+--*/
+{
+ CHAR16 *FileString;
+ CHAR8 *File8Dot3Name;
+
+ //
+ // Get new entry count and set the 8.3 name
+ //
+ DirEnt->EntryCount = 1;
+ FileString = DirEnt->FileString;
+ File8Dot3Name = DirEnt->Entry.FileName;
+ SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');
+ if (StrCmp (FileString, L".") == 0) {
+ //
+ // "." entry
+ //
+ File8Dot3Name[0] = '.';
+ FatCloneDirEnt (DirEnt, OFile->DirEnt);
+ } else if (StrCmp (FileString, L"..") == 0) {
+ //
+ // ".." entry
+ //
+ File8Dot3Name[0] = '.';
+ File8Dot3Name[1] = '.';
+ FatCloneDirEnt (DirEnt, OFile->Parent->DirEnt);
+ } else {
+ //
+ // Normal name
+ //
+ if (FatCheckIs8Dot3Name (FileString, File8Dot3Name)) {
+ //
+ // This file name is a valid 8.3 file name, we need to further check its case flag
+ //
+ FatSetCaseFlag (DirEnt);
+ } else {
+ //
+ // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
+ //
+ FatCreate8Dot3Name (OFile, DirEnt);
+ DirEnt->EntryCount = (UINT8)(LFN_ENTRY_NUMBER (StrLen (FileString)) + DirEnt->EntryCount);
+ }
+ }
+}
+
+STATIC
+EFI_STATUS
+FatExpandODir (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Append a zero cluster to the current OFile.
+
+Arguments:
+
+ OFile - The directory OFile which needs to be updated.
+
+Returns:
+
+ EFI_SUCCESS - Append a zero cluster to the OFile successfully.
+ other - An error occurred when appending the zero cluster.
+
+--*/
+{
+ return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);
+}
+
+STATIC
+EFI_STATUS
+FatSeekVolumeId (
+ IN FAT_OFILE *Root,
+ OUT FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Search the Root OFile for the possible volume label.
+
+Arguments:
+
+ Root - The Root OFile.
+ DirEnt - The returned directory entry of volume label.
+
+Returns:
+
+ EFI_SUCCESS - The search process is completed successfully.
+ other - An error occurred when searching volume label.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN EntryPos;
+ FAT_DIRECTORY_ENTRY *Entry;
+
+ EntryPos = 0;
+ Entry = &DirEnt->Entry;
+ DirEnt->Invalid = TRUE;
+ do {
+ Status = FatAccessEntry (Root, READ_DATA, EntryPos, Entry);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (((UINT8) Entry->FileName[0] != DELETE_ENTRY_MARK) && (((Entry->Attributes) & (~FAT_ATTRIBUTE_ARCHIVE)) == FAT_ATTRIBUTE_VOLUME_ID)) {
+ DirEnt->EntryPos = (UINT16) EntryPos;
+ DirEnt->EntryCount = 1;
+ DirEnt->Invalid = FALSE;
+ break;
+ }
+
+ EntryPos++;
+ } while (Entry->FileName[0] != EMPTY_ENTRY_MARK);
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FatFirstFitInsertDirEnt (
+ IN FAT_OFILE *OFile,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Use First Fit Algorithm to insert directory entry.
+ Only this function will erase "E5" entries in a directory.
+ In view of safest recovery, this function will only be triggered
+ when maximum directory entry number has reached.
+
+Arguments:
+
+ OFile - The corresponding OFile.
+ DirEnt - The directory entry to be inserted.
+
+Returns:
+
+ EFI_SUCCESS - The directory entry has been successfully inserted.
+ EFI_VOLUME_FULL - The directory can not hold more directory entries.
+ Others - Some error occurred when inserting new directory entries.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_ODIR *ODir;
+ LIST_ENTRY *CurrentEntry;
+ FAT_DIRENT *CurrentDirEnt;
+ UINT32 CurrentPos;
+ UINT32 LabelPos;
+ UINT32 NewEntryPos;
+ UINT16 EntryCount;
+ FAT_DIRENT LabelDirEnt;
+
+ LabelPos = 0;
+ if (OFile->Parent == NULL) {
+ Status = FatSeekVolumeId (OFile, &LabelDirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!LabelDirEnt.Invalid) {
+ LabelPos = LabelDirEnt.EntryPos;
+ }
+ }
+
+ EntryCount = DirEnt->EntryCount;
+ NewEntryPos = EntryCount;
+ CurrentPos = 0;
+ ODir = OFile->ODir;
+ for (CurrentEntry = ODir->ChildList.ForwardLink;
+ CurrentEntry != &ODir->ChildList;
+ CurrentEntry = CurrentEntry->ForwardLink
+ ) {
+ CurrentDirEnt = DIRENT_FROM_LINK (CurrentEntry);
+ if (NewEntryPos + CurrentDirEnt->EntryCount <= CurrentDirEnt->EntryPos) {
+ if (LabelPos > NewEntryPos || LabelPos <= CurrentPos) {
+ //
+ // first fit succeeded
+ //
+ goto Done;
+ }
+ }
+
+ CurrentPos = CurrentDirEnt->EntryPos;
+ NewEntryPos = CurrentPos + EntryCount;
+ }
+
+ if (NewEntryPos >= ODir->CurrentEndPos) {
+ return EFI_VOLUME_FULL;
+ }
+
+Done:
+ DirEnt->EntryPos = (UINT16) NewEntryPos;
+ DirEnt->Link.BackLink = CurrentEntry;
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FatNewEntryPos (
+ IN FAT_OFILE *OFile,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Find the new directory entry position for the directory entry.
+
+Arguments:
+
+ OFile - The corresponding OFile.
+ DirEnt - The directory entry whose new position is to be set.
+
+Returns:
+
+ EFI_SUCCESS - The new directory entry position is successfully found.
+ EFI_VOLUME_FULL - The directory has reach its maximum capacity.
+ other - An error occurred when reading the directory entry.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_ODIR *ODir;
+ FAT_DIRENT *TempDirEnt;
+ UINT32 NewEndPos;
+
+ ODir = OFile->ODir;
+ ASSERT (ODir != NULL);
+ //
+ // Make sure the whole directory has been loaded
+ //
+ while (!ODir->EndOfDir) {
+ Status = FatLoadNextDirEnt (OFile, &TempDirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // We will append this entry to the end of directory
+ //
+ FatGetCurrentFatTime (&DirEnt->Entry.FileCreateTime);
+ FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime);
+ NewEndPos = ODir->CurrentEndPos + DirEnt->EntryCount;
+ if (NewEndPos * sizeof (FAT_DIRECTORY_ENTRY) > OFile->FileSize) {
+ if (NewEndPos >= (OFile->IsFixedRootDir ? OFile->Volume->RootEntries : FAT_MAX_DIRENTRY_COUNT)) {
+ //
+ // We try to use fist fit algorithm to insert this directory entry
+ //
+ return FatFirstFitInsertDirEnt (OFile, DirEnt);
+ }
+ //
+ // We should allocate a new cluster for this directory
+ //
+ Status = FatExpandODir (OFile);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // We append our directory entry at the end of directory file
+ //
+ ODir->CurrentEndPos = NewEndPos;
+ DirEnt->EntryPos = (UINT16) (ODir->CurrentEndPos - 1);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatGetVolumeEntry (
+ IN FAT_VOLUME *Volume,
+ IN CHAR16 *Name
+ )
+/*++
+
+Routine Description:
+
+ Get the directory entry for the volume.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ Name - The file name of the volume.
+
+Returns:
+
+ EFI_SUCCESS - Update the volume with the directory entry sucessfully.
+ others - An error occurred when getting volume label.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_DIRENT LabelDirEnt;
+
+ *Name = 0;
+ Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
+ if (!EFI_ERROR (Status)) {
+ if (!LabelDirEnt.Invalid) {
+ FatNameToStr (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, FALSE, Name);
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+FatSetVolumeEntry (
+ IN FAT_VOLUME *Volume,
+ IN CHAR16 *Name
+ )
+/*++
+
+Routine Description:
+
+ Set the relevant directory entry into disk for the volume.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ Name - The new file name of the volume.
+
+Returns:
+
+ EFI_SUCCESS - Update the Volume sucessfully.
+ EFI_UNSUPPORTED - The input label is not a valid volume label.
+ other - An error occurred when setting volume label.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_DIRENT LabelDirEnt;
+ FAT_OFILE *Root;
+
+ Root = Volume->Root;
+ Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (LabelDirEnt.Invalid) {
+ //
+ // If there is not the relevant directory entry, create a new one
+ //
+ ZeroMem (&LabelDirEnt, sizeof (FAT_DIRENT));
+ LabelDirEnt.EntryCount = 1;
+ Status = FatNewEntryPos (Root, &LabelDirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LabelDirEnt.Entry.Attributes = FAT_ATTRIBUTE_VOLUME_ID;
+ }
+
+ SetMem (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, ' ');
+ if (FatStrToFat (Name, FAT_NAME_LEN, LabelDirEnt.Entry.FileName)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FatGetCurrentFatTime (&LabelDirEnt.Entry.FileModificationTime);
+ return FatStoreDirEnt (Root, &LabelDirEnt);
+}
+
+EFI_STATUS
+FatCreateDotDirEnts (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Create "." and ".." directory entries in the newly-created parent OFile.
+
+Arguments:
+
+ OFile - The parent OFile.
+
+Returns:
+
+ EFI_SUCCESS - The dot directory entries are successfully created.
+ other - An error occurred when creating the directory entry.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_DIRENT *DirEnt;
+
+ Status = FatExpandODir (OFile);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FatSetDirEntCluster (OFile);
+ //
+ // Create "."
+ //
+ Status = FatCreateDirEnt (OFile, L".", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Create ".."
+ //
+ Status = FatCreateDirEnt (OFile, L"..", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
+ return Status;
+}
+
+EFI_STATUS
+FatCreateDirEnt (
+ IN FAT_OFILE *OFile,
+ IN CHAR16 *FileName,
+ IN UINT8 Attributes,
+ OUT FAT_DIRENT **PtrDirEnt
+ )
+/*++
+
+Routine Description:
+
+ Create a directory entry in the parent OFile.
+
+Arguments:
+
+ OFile - The parent OFile.
+ FileName - The filename of the newly-created directory entry.
+ Attributes - The attribute of the newly-created directory entry.
+ PtrDirEnt - The pointer to the newly-created directory entry.
+
+Returns:
+
+ EFI_SUCCESS - The directory entry is successfully created.
+ EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry.
+ other - An error occurred when creating the directory entry.
+
+--*/
+{
+ FAT_DIRENT *DirEnt;
+ FAT_ODIR *ODir;
+ EFI_STATUS Status;
+
+ ODir = OFile->ODir;
+ ASSERT (ODir != NULL);
+ DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
+ if (DirEnt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DirEnt->Signature = FAT_DIRENT_SIGNATURE;
+ DirEnt->FileString = AllocateCopyPool (StrSize (FileName), FileName);
+ if (DirEnt->FileString == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Determine how many directory entries we need
+ //
+ FatSetEntryCount (OFile, DirEnt);
+ //
+ // Determine the file's directory entry position
+ //
+ Status = FatNewEntryPos (OFile, DirEnt);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ FatAddDirEnt (ODir, DirEnt);
+ DirEnt->Entry.Attributes = Attributes;
+ *PtrDirEnt = DirEnt;
+ DEBUG ((EFI_D_INFO, "FSOpen: Created new directory entry '%S'\n", DirEnt->FileString));
+ return FatStoreDirEnt (OFile, DirEnt);
+
+Done:
+ FatFreeDirEnt (DirEnt);
+ return Status;
+}
+
+EFI_STATUS
+FatRemoveDirEnt (
+ IN FAT_OFILE *OFile,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Remove this directory entry node from the list of directory entries and hash table.
+
+Arguments:
+
+ OFile - The parent OFile.
+ DirEnt - The directory entry to be removed.
+
+Returns:
+
+ EFI_SUCCESS - The directory entry is successfully removed.
+ other - An error occurred when removing the directory entry.
+
+--*/
+{
+ FAT_ODIR *ODir;
+
+ ODir = OFile->ODir;
+ if (ODir->CurrentCursor == &DirEnt->Link) {
+ //
+ // Move the directory cursor to its previous directory entry
+ //
+ ODir->CurrentCursor = ODir->CurrentCursor->BackLink;
+ }
+ //
+ // Remove from directory entry list
+ //
+ RemoveEntryList (&DirEnt->Link);
+ //
+ // Remove from hash table
+ //
+ FatDeleteFromHashTable (ODir, DirEnt);
+ DirEnt->Entry.FileName[0] = DELETE_ENTRY_MARK;
+ DirEnt->Invalid = TRUE;
+ return FatStoreDirEnt (OFile, DirEnt);
+}
+
+EFI_STATUS
+FatOpenDirEnt (
+ IN FAT_OFILE *Parent,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Open the directory entry to get the OFile.
+
+Arguments:
+
+ OFile - The parent OFile.
+ DirEnt - The directory entry to be opened.
+
+Returns:
+
+ EFI_SUCCESS - The directory entry is successfully opened.
+ EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile.
+ other - An error occurred when opening the directory entry.
+
+--*/
+{
+ FAT_OFILE *OFile;
+ FAT_VOLUME *Volume;
+
+ if (DirEnt->OFile == NULL) {
+ //
+ // Open the directory entry
+ //
+ OFile = AllocateZeroPool (sizeof (FAT_OFILE));
+ if (OFile == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OFile->Signature = FAT_OFILE_SIGNATURE;
+ InitializeListHead (&OFile->Opens);
+ InitializeListHead (&OFile->ChildHead);
+ OFile->Parent = Parent;
+ OFile->DirEnt = DirEnt;
+ if (Parent != NULL) {
+ //
+ // The newly created OFile is not root
+ //
+ Volume = Parent->Volume;
+ OFile->FullPathLen = Parent->FullPathLen + 1 + StrLen (DirEnt->FileString);
+ OFile->FileCluster = ((DirEnt->Entry.FileClusterHigh) << 16) | (DirEnt->Entry.FileCluster);
+ InsertTailList (&Parent->ChildHead, &OFile->ChildLink);
+ } else {
+ //
+ // The newly created OFile is root
+ //
+ Volume = VOLUME_FROM_ROOT_DIRENT (DirEnt);
+ Volume->Root = OFile;
+ OFile->FileCluster = Volume->RootCluster;
+ if (Volume->FatType != FAT32) {
+ OFile->IsFixedRootDir = TRUE;
+ }
+ }
+
+ OFile->FileCurrentCluster = OFile->FileCluster;
+ OFile->Volume = Volume;
+ InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);
+
+ OFile->FileSize = DirEnt->Entry.FileSize;
+ if ((DirEnt->Entry.Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
+ if (OFile->IsFixedRootDir) {
+ OFile->FileSize = Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY);
+ } else {
+ OFile->FileSize = FatPhysicalDirSize (Volume, OFile->FileCluster);
+ }
+
+ FatRequestODir (OFile);
+ if (OFile->ODir == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ DirEnt->OFile = OFile;
+ }
+
+ return EFI_SUCCESS;
+}
+
+VOID
+FatCloseDirEnt (
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Close the directory entry and free the OFile.
+
+Arguments:
+
+ DirEnt - The directory entry to be closed.
+
+Returns:
+
+ EFI_SUCCESS - The directory entry is successfully opened.
+ Other - An error occurred when opening the directory entry.
+
+--*/
+{
+ FAT_OFILE *OFile;
+ FAT_VOLUME *Volume;
+
+ OFile = DirEnt->OFile;
+ Volume = OFile->Volume;
+ ASSERT (OFile != NULL);
+
+ if (OFile->ODir != NULL) {
+ FatDiscardODir (OFile);
+ }
+
+ if (OFile->Parent == NULL) {
+ Volume->Root = NULL;
+ } else {
+ RemoveEntryList (&OFile->ChildLink);
+ }
+
+ FreePool (OFile);
+ DirEnt->OFile = NULL;
+ if (DirEnt->Invalid == TRUE) {
+ //
+ // Free directory entry itself
+ //
+ FatFreeDirEnt (DirEnt);
+ }
+}
+
+EFI_STATUS
+FatLocateOFile (
+ IN OUT FAT_OFILE **PtrOFile,
+ IN CHAR16 *FileName,
+ IN UINT8 Attributes,
+ OUT CHAR16 *NewFileName
+ )
+/*++
+
+Routine Description:
+
+ Traverse filename and open all OFiles that can be opened.
+ Update filename pointer to the component that can't be opened.
+ If more than one name component remains, returns an error;
+ otherwise, return the remaining name component so that the caller might choose to create it.
+
+Arguments:
+ PtrOFile - As input, the reference OFile; as output, the located OFile.
+ FileName - The file name relevant to the OFile.
+ Attributes - The attribute of the destination OFile.
+ NewFileName - The remaining file name.
+
+Returns:
+
+ EFI_NOT_FOUND - The file name can't be opened and there is more than one
+ components within the name left (this means the name can
+ not be created either).
+ EFI_INVALID_PARAMETER - The parameter is not valid.
+ EFI_SUCCESS - Open the file successfully.
+ other - An error occured when locating the OFile.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_VOLUME *Volume;
+ CHAR16 ComponentName[EFI_PATH_STRING_LENGTH];
+ UINTN FileNameLen;
+ BOOLEAN DirIntended;
+ CHAR16 *Next;
+ FAT_OFILE *OFile;
+ FAT_DIRENT *DirEnt;
+
+ FileNameLen = StrLen (FileName);
+ if (FileNameLen == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OFile = *PtrOFile;
+ Volume = OFile->Volume;
+
+ DirIntended = FALSE;
+ if (FileName[FileNameLen - 1] == PATH_NAME_SEPARATOR) {
+ DirIntended = TRUE;
+ }
+ //
+ // If name starts with path name separator, then move to root OFile
+ //
+ if (*FileName == PATH_NAME_SEPARATOR) {
+ OFile = Volume->Root;
+ FileName++;
+ FileNameLen--;
+ }
+ //
+ // Per FAT Spec the file name should meet the following criteria:
+ // C1. Length (FileLongName) <= 255
+ // C2. Length (X:FileFullPath<NUL>) <= 260
+ // Here we check C2 first.
+ //
+ if (2 + OFile->FullPathLen + 1 + FileNameLen + 1 > EFI_PATH_STRING_LENGTH) {
+ //
+ // Full path length can not surpass 256
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Start at current location
+ //
+ Next = FileName;
+ for (;;) {
+ //
+ // Get the next component name
+ //
+ FileName = Next;
+ Next = FatGetNextNameComponent (FileName, ComponentName);
+
+ //
+ // If end of the file name, we're done
+ //
+ if (ComponentName[0] == 0) {
+ if (DirIntended && OFile->ODir == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewFileName[0] = 0;
+ break;
+ }
+ //
+ // If "dot", then current
+ //
+ if (StrCmp (ComponentName, L".") == 0) {
+ continue;
+ }
+ //
+ // If "dot dot", then parent
+ //
+ if (StrCmp (ComponentName, L"..") == 0) {
+ if (OFile->Parent == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ OFile = OFile->Parent;
+ continue;
+ }
+
+ if (!FatFileNameIsValid (ComponentName, NewFileName)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // We have a component name, try to open it
+ //
+ if (OFile->ODir == NULL) {
+ //
+ // This file isn't a directory, can't open it
+ //
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Search the compName in the directory
+ //
+ Status = FatSearchODir (OFile, NewFileName, &DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (DirEnt == NULL) {
+ //
+ // component name is not found in the directory
+ //
+ if (*Next != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (DirIntended && (Attributes & FAT_ATTRIBUTE_DIRECTORY) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // It's the last component name - return with the open
+ // path and the remaining name
+ //
+ break;
+ }
+
+ Status = FatOpenDirEnt (OFile, DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OFile = DirEnt->OFile;
+ }
+
+ *PtrOFile = OFile;
+ return EFI_SUCCESS;
+}
+
diff --git a/FatPkg/EnhancedFatDxe/DiskCache.c b/FatPkg/EnhancedFatDxe/DiskCache.c
new file mode 100644
index 0000000000..ef27a53eab
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/DiskCache.c
@@ -0,0 +1,541 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ DiskCache.c
+
+Abstract:
+
+ Cache implementation for EFI FAT File system driver
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+STATIC
+VOID
+FatFlushDataCacheRange (
+ IN FAT_VOLUME *Volume,
+ IN IO_MODE IoMode,
+ IN UINTN StartPageNo,
+ IN UINTN EndPageNo,
+ OUT UINT8 *Buffer
+ )
+/*++
+
+Routine Description:
+
+ This function is used by the Data Cache.
+
+ When this function is called by write command, all entries in this range
+ are older than the contents in disk, so they are invalid; just mark them invalid.
+
+ When this function is called by read command, if any entry in this range
+ is dirty, it means that the relative info directly readed from media is older than
+ than the info in the cache; So need to update the relative info in the Buffer.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ IoMode - This function is called by read command or write command
+ StartPageNo - First PageNo to be checked in the cache.
+ EndPageNo - Last PageNo to be checked in the cache.
+ Buffer - The user buffer need to update. Only when doing the read command
+ and there is dirty cache in the cache range, this parameter will be used.
+
+Returns:
+
+ None.
+
+--*/
+{
+ UINTN PageNo;
+ UINTN GroupNo;
+ UINTN GroupMask;
+ UINTN PageSize;
+ UINT8 PageAlignment;
+ DISK_CACHE *DiskCache;
+ CACHE_TAG *CacheTag;
+ UINT8 *BaseAddress;
+
+ DiskCache = &Volume->DiskCache[CACHE_DATA];
+ BaseAddress = DiskCache->CacheBase;
+ GroupMask = DiskCache->GroupMask;
+ PageAlignment = DiskCache->PageAlignment;
+ PageSize = (UINTN)1 << PageAlignment;
+
+ for (PageNo = StartPageNo; PageNo < EndPageNo; PageNo++) {
+ GroupNo = PageNo & GroupMask;
+ CacheTag = &DiskCache->CacheTag[GroupNo];
+ if (CacheTag->RealSize > 0 && CacheTag->PageNo == PageNo) {
+ //
+ // When reading data form disk directly, if some dirty data
+ // in cache is in this rang, this data in the Buffer need to
+ // be updated with the cache's dirty data.
+ //
+ if (IoMode == READ_DISK) {
+ if (CacheTag->Dirty) {
+ CopyMem (
+ Buffer + ((PageNo - StartPageNo) << PageAlignment),
+ BaseAddress + (GroupNo << PageAlignment),
+ PageSize
+ );
+ }
+ } else {
+ //
+ // Make all valid entries in this range invalid.
+ //
+ CacheTag->RealSize = 0;
+ }
+ }
+ }
+}
+
+STATIC
+EFI_STATUS
+FatExchangeCachePage (
+ IN FAT_VOLUME *Volume,
+ IN CACHE_DATA_TYPE DataType,
+ IN IO_MODE IoMode,
+ IN CACHE_TAG *CacheTag
+ )
+/*++
+
+Routine Description:
+
+ Exchange the cache page with the image on the disk
+
+Arguments:
+
+ Volume - FAT file system volume.
+ DataType - Indicate the cache type.
+ IoMode - Indicate whether to load this page from disk or store this page to disk.
+ CacheTag - The Cache Tag for the current cache page.
+
+Returns:
+
+ EFI_SUCCESS - Cache page exchanged successfully.
+ Others - An error occurred when exchanging cache page.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN GroupNo;
+ UINTN PageNo;
+ UINTN WriteCount;
+ UINTN RealSize;
+ UINT64 EntryPos;
+ UINT64 MaxSize;
+ DISK_CACHE *DiskCache;
+ VOID *PageAddress;
+ UINT8 PageAlignment;
+
+ DiskCache = &Volume->DiskCache[DataType];
+ PageNo = CacheTag->PageNo;
+ GroupNo = PageNo & DiskCache->GroupMask;
+ PageAlignment = DiskCache->PageAlignment;
+ PageAddress = DiskCache->CacheBase + (GroupNo << PageAlignment);
+ EntryPos = DiskCache->BaseAddress + LShiftU64 (PageNo, PageAlignment);
+ RealSize = CacheTag->RealSize;
+ if (IoMode == READ_DISK) {
+ RealSize = (UINTN)1 << PageAlignment;
+ MaxSize = DiskCache->LimitAddress - EntryPos;
+ if (MaxSize < RealSize) {
+ DEBUG ((EFI_D_INFO, "FatDiskIo: Cache Page OutBound occurred! \n"));
+ RealSize = (UINTN) MaxSize;
+ }
+ }
+
+ WriteCount = 1;
+ if (DataType == CACHE_FAT && IoMode == WRITE_DISK) {
+ WriteCount = Volume->NumFats;
+ }
+
+ do {
+ //
+ // Only fat table writing will execute more than once
+ //
+ Status = FatDiskIo (Volume, IoMode, EntryPos, RealSize, PageAddress);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ EntryPos += Volume->FatSize;
+ } while (--WriteCount > 0);
+
+ CacheTag->Dirty = FALSE;
+ CacheTag->RealSize = RealSize;
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FatGetCachePage (
+ IN FAT_VOLUME *Volume,
+ IN CACHE_DATA_TYPE CacheDataType,
+ IN UINTN PageNo,
+ IN CACHE_TAG *CacheTag
+ )
+/*++
+
+Routine Description:
+
+ Get one cache page by specified PageNo.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ CacheDataType - The cache type: CACHE_FAT or CACHE_DATA.
+ PageNo - PageNo to match with the cache.
+ CacheTag - The Cache Tag for the current cache page.
+
+Returns:
+
+ EFI_SUCCESS - Get the cache page successfully.
+ other - An error occurred when accessing data.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN OldPageNo;
+
+ OldPageNo = CacheTag->PageNo;
+ if (CacheTag->RealSize > 0 && OldPageNo == PageNo) {
+ //
+ // Cache Hit occurred
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Write dirty cache page back to disk
+ //
+ if (CacheTag->RealSize > 0 && CacheTag->Dirty) {
+ Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // Load new data from disk;
+ //
+ CacheTag->PageNo = PageNo;
+ Status = FatExchangeCachePage (Volume, CacheDataType, READ_DISK, CacheTag);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+FatAccessUnalignedCachePage (
+ IN FAT_VOLUME *Volume,
+ IN CACHE_DATA_TYPE CacheDataType,
+ IN IO_MODE IoMode,
+ IN UINTN PageNo,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN OUT VOID *Buffer
+ )
+/*++
+Routine Description:
+
+ Read Length bytes from the position of Offset into Buffer, or
+ write Length bytes from Buffer into the position of Offset.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
+ IoMode - Indicate the type of disk access.
+ PageNo - The number of unaligned cache page.
+ Offset - The starting byte of cache page.
+ Length - The number of bytes that is read or written
+ Buffer - Buffer containing cache data.
+
+Returns:
+
+ EFI_SUCCESS - The data was accessed correctly.
+ Others - An error occurred when accessing unaligned cache page.
+
+--*/
+{
+ EFI_STATUS Status;
+ VOID *Source;
+ VOID *Destination;
+ DISK_CACHE *DiskCache;
+ CACHE_TAG *CacheTag;
+ UINTN GroupNo;
+
+ DiskCache = &Volume->DiskCache[CacheDataType];
+ GroupNo = PageNo & DiskCache->GroupMask;
+ CacheTag = &DiskCache->CacheTag[GroupNo];
+ Status = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag);
+ if (!EFI_ERROR (Status)) {
+ Source = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset;
+ Destination = Buffer;
+ if (IoMode != READ_DISK) {
+ CacheTag->Dirty = TRUE;
+ DiskCache->Dirty = TRUE;
+ Destination = Source;
+ Source = Buffer;
+ }
+
+ CopyMem (Destination, Source, Length);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+FatAccessCache (
+ IN FAT_VOLUME *Volume,
+ IN CACHE_DATA_TYPE CacheDataType,
+ IN IO_MODE IoMode,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN OUT UINT8 *Buffer
+ )
+/*++
+Routine Description:
+
+ Read BufferSize bytes from the position of Offset into Buffer,
+ or write BufferSize bytes from Buffer into the position of Offset.
+
+ Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into
+ the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):
+
+ 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache
+ page hit, just return the cache page; else update the related cache page and return
+ the right cache page.
+ 2. Access of Data cache (CACHE_DATA):
+ The access data will be divided into UnderRun data, Aligned data and OverRun data;
+ The UnderRun data and OverRun data will be accessed by the Data cache,
+ but the Aligned data will be accessed with disk directly.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
+ IoMode - Indicate the type of disk access.
+ Offset - The starting byte offset to read from.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing cache data.
+
+Returns:
+
+ EFI_SUCCESS - The data was accessed correctly.
+ EFI_MEDIA_CHANGED - The MediaId does not match the current device.
+ Others - An error occurred when accessing cache.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN PageSize;
+ UINTN UnderRun;
+ UINTN OverRun;
+ UINTN AlignedSize;
+ UINTN Length;
+ UINTN PageNo;
+ UINTN AlignedPageCount;
+ UINTN OverRunPageNo;
+ DISK_CACHE *DiskCache;
+ UINT64 EntryPos;
+ UINT8 PageAlignment;
+
+ ASSERT (Volume->CacheBuffer != NULL);
+
+ Status = EFI_SUCCESS;
+ DiskCache = &Volume->DiskCache[CacheDataType];
+ EntryPos = Offset - DiskCache->BaseAddress;
+ PageAlignment = DiskCache->PageAlignment;
+ PageSize = (UINTN)1 << PageAlignment;
+ PageNo = (UINTN) RShiftU64 (EntryPos, PageAlignment);
+ UnderRun = ((UINTN) EntryPos) & (PageSize - 1);
+
+ if (UnderRun > 0) {
+ Length = PageSize - UnderRun;
+ if (Length > BufferSize) {
+ Length = BufferSize;
+ }
+
+ Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Buffer += Length;
+ BufferSize -= Length;
+ PageNo++;
+ }
+
+ AlignedPageCount = BufferSize >> PageAlignment;
+ OverRunPageNo = PageNo + AlignedPageCount;
+ //
+ // The access of the Aligned data
+ //
+ if (AlignedPageCount > 0) {
+ //
+ // Accessing fat table cannot have alignment data
+ //
+ ASSERT (CacheDataType == CACHE_DATA);
+
+ EntryPos = Volume->RootPos + LShiftU64 (PageNo, PageAlignment);
+ AlignedSize = AlignedPageCount << PageAlignment;
+ Status = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // If these access data over laps the relative cache range, these cache pages need
+ // to be updated.
+ //
+ FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer);
+ Buffer += AlignedSize;
+ BufferSize -= AlignedSize;
+ }
+ //
+ // The access of the OverRun data
+ //
+ OverRun = BufferSize;
+ if (OverRun > 0) {
+ //
+ // Last read is not a complete page
+ //
+ Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+FatVolumeFlushCache (
+ IN FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Flush all the dirty cache back, include the FAT cache and the Data cache.
+
+Arguments:
+
+ Volume - FAT file system volume.
+
+Returns:
+
+ EFI_SUCCESS - Flush all the dirty cache back successfully
+ other - An error occurred when writing the data into the disk
+
+--*/
+{
+ EFI_STATUS Status;
+ CACHE_DATA_TYPE CacheDataType;
+ UINTN GroupIndex;
+ UINTN GroupMask;
+ DISK_CACHE *DiskCache;
+ CACHE_TAG *CacheTag;
+
+ for (CacheDataType = (CACHE_DATA_TYPE) 0; CacheDataType < CACHE_MAX_TYPE; CacheDataType++) {
+ DiskCache = &Volume->DiskCache[CacheDataType];
+ if (DiskCache->Dirty) {
+ //
+ // Data cache or fat cache is dirty, write the dirty data back
+ //
+ GroupMask = DiskCache->GroupMask;
+ for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) {
+ CacheTag = &DiskCache->CacheTag[GroupIndex];
+ if (CacheTag->RealSize > 0 && CacheTag->Dirty) {
+ //
+ // Write back all Dirty Data Cache Page to disk
+ //
+ Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ DiskCache->Dirty = FALSE;
+ }
+ }
+ //
+ // Flush the block device.
+ //
+ Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo);
+ return Status;
+}
+
+EFI_STATUS
+FatInitializeDiskCache (
+ IN FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Initialize the disk cache according to Volume's FatType.
+
+Arguments:
+
+ Volume - FAT file system volume.
+
+Returns:
+
+ EFI_SUCCESS - The disk cache is successfully initialized.
+ EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.
+
+--*/
+{
+ DISK_CACHE *DiskCache;
+ UINTN FatCacheGroupCount;
+ UINTN DataCacheSize;
+ UINTN FatCacheSize;
+ UINT8 *CacheBuffer;
+
+ DiskCache = Volume->DiskCache;
+ //
+ // Configure the parameters of disk cache
+ //
+ if (Volume->FatType == FAT12) {
+ FatCacheGroupCount = FAT_FATCACHE_GROUP_MIN_COUNT;
+ DiskCache[CACHE_FAT].PageAlignment = FAT_FATCACHE_PAGE_MIN_ALIGNMENT;
+ DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT;
+ } else {
+ FatCacheGroupCount = FAT_FATCACHE_GROUP_MAX_COUNT;
+ DiskCache[CACHE_FAT].PageAlignment = FAT_FATCACHE_PAGE_MAX_ALIGNMENT;
+ DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT;
+ }
+
+ DiskCache[CACHE_DATA].GroupMask = FAT_DATACACHE_GROUP_COUNT - 1;
+ DiskCache[CACHE_DATA].BaseAddress = Volume->RootPos;
+ DiskCache[CACHE_DATA].LimitAddress = Volume->VolumeSize;
+ DiskCache[CACHE_FAT].GroupMask = FatCacheGroupCount - 1;
+ DiskCache[CACHE_FAT].BaseAddress = Volume->FatPos;
+ DiskCache[CACHE_FAT].LimitAddress = Volume->FatPos + Volume->FatSize;
+ FatCacheSize = FatCacheGroupCount << DiskCache[CACHE_FAT].PageAlignment;
+ DataCacheSize = FAT_DATACACHE_GROUP_COUNT << DiskCache[CACHE_DATA].PageAlignment;
+ //
+ // Allocate the Fat Cache buffer
+ //
+ CacheBuffer = AllocatePool (FatCacheSize + DataCacheSize);
+ if (CacheBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Volume->CacheBuffer = CacheBuffer;
+ DiskCache[CACHE_FAT].CacheBase = CacheBuffer;
+ DiskCache[CACHE_DATA].CacheBase = CacheBuffer + FatCacheSize;
+ return EFI_SUCCESS;
+}
diff --git a/FatPkg/EnhancedFatDxe/Fat.c b/FatPkg/EnhancedFatDxe/Fat.c
new file mode 100644
index 0000000000..e52b8c1d56
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Fat.c
@@ -0,0 +1,393 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Fat.c
+
+Abstract:
+
+ Fat File System driver routines that support EFI driver model
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+EFI_STATUS
+EFIAPI
+FatUnload (
+ IN EFI_HANDLE ImageHandle
+ );
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// DriverBinding protocol instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gFatDriverBinding = {
+ FatDriverBindingSupported,
+ FatDriverBindingStart,
+ FatDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_STATUS
+EFIAPI
+FatEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ Register Driver Binding protocol for this driver.
+
+Arguments:
+
+ ImageHandle - Handle for the image of this driver.
+ SystemTable - Pointer to the EFI System Table.
+
+Returns:
+
+ EFI_SUCCESS - Driver loaded.
+ other - Driver not loaded.
+
+--*/
+{
+ EFI_STATUS Status;
+
+ //
+ // Initialize the EFI Driver Library
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gFatDriverBinding,
+ ImageHandle,
+ &gFatComponentName,
+ &gFatComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+/*++
+
+Routine Description:
+
+ Unload function for this image. Uninstall DriverBinding protocol.
+
+Arguments:
+
+ ImageHandle - Handle for the image of this driver.
+
+Returns:
+
+ EFI_SUCCESS - Driver unloaded successfully.
+ other - Driver can not unloaded.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *DeviceHandleBuffer;
+ UINTN DeviceHandleCount;
+ UINTN Index;
+
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &DeviceHandleCount,
+ &DeviceHandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < DeviceHandleCount; Index++) {
+ Status = gBS->DisconnectController (
+ DeviceHandleBuffer[Index],
+ ImageHandle,
+ NULL
+ );
+ }
+
+ if (DeviceHandleBuffer != NULL) {
+ FreePool (DeviceHandleBuffer);
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+
+ Test to see if this driver can add a file system to ControllerHandle.
+ ControllerHandle must support both Disk IO and Block IO protocols.
+
+Arguments:
+
+ This - Protocol instance pointer.
+ ControllerHandle - Handle of device to test.
+ RemainingDevicePath - Not used.
+
+Returns:
+
+ EFI_SUCCESS - This driver supports this device.
+ EFI_ALREADY_STARTED - This driver is already running on this device.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+
+ Start this driver on ControllerHandle by opening a Block IO and Disk IO
+ protocol, reading Device Path. Add a Simple File System protocol to
+ ControllerHandle if the media contains a valid file system.
+
+Arguments:
+
+ This - Protocol instance pointer.
+ ControllerHandle - Handle of device to bind driver to.
+ RemainingDevicePath - Not used.
+
+Returns:
+
+ EFI_SUCCESS - This driver is added to DeviceHandle.
+ EFI_ALREADY_STARTED - This driver is already running on DeviceHandle.
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+
+ Status = InitializeUnicodeCollationSupport (This->DriverBindingHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open our required BlockIo and DiskIo
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Allocate Volume structure. In FatAllocateVolume(), Resources
+ // are allocated with protocol installed and cached initialized
+ //
+ Status = FatAllocateVolume (ControllerHandle, DiskIo, BlockIo);
+
+ //
+ // When the media changes on a device it will Reinstall the BlockIo interaface.
+ // This will cause a call to our Stop(), and a subsequent reentrant call to our
+ // Start() successfully. We should leave the device open when this happen.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+Routine Description:
+ Stop this driver on ControllerHandle.
+
+Arguments:
+ This - Protocol instance pointer.
+ ControllerHandle - Handle of device to stop driver on.
+ NumberOfChildren - Not used.
+ ChildHandleBuffer - Not used.
+
+Returns:
+ EFI_SUCCESS - This driver is removed DeviceHandle.
+ other - This driver was not removed from this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
+ FAT_VOLUME *Volume;
+
+ //
+ // Get our context back
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **) &FileSystem,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Volume = VOLUME_FROM_VOL_INTERFACE (FileSystem);
+ Status = FatAbandonVolume (Volume);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return Status;
+}
diff --git a/FatPkg/EnhancedFatDxe/Fat.h b/FatPkg/EnhancedFatDxe/Fat.h
new file mode 100644
index 0000000000..6328a52d15
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Fat.h
@@ -0,0 +1,1119 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Fat.h
+
+Abstract:
+
+ Main header file for EFI FAT file system driver
+
+Revision History
+
+--*/
+
+#ifndef _FAT_H_
+#define _FAT_H_
+
+#include <Uefi.h>
+
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/GlobalVariable.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/UnicodeCollation.h>
+
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include "FatFileSystem.h"
+
+//
+// The FAT signature
+//
+#define FAT_VOLUME_SIGNATURE EFI_SIGNATURE_32 ('f', 'a', 't', 'v')
+#define FAT_IFILE_SIGNATURE EFI_SIGNATURE_32 ('f', 'a', 't', 'i')
+#define FAT_ODIR_SIGNATURE EFI_SIGNATURE_32 ('f', 'a', 't', 'd')
+#define FAT_DIRENT_SIGNATURE EFI_SIGNATURE_32 ('f', 'a', 't', 'e')
+#define FAT_OFILE_SIGNATURE EFI_SIGNATURE_32 ('f', 'a', 't', 'o')
+
+#define ASSERT_VOLUME_LOCKED(a) ASSERT_LOCKED (&FatFsLock)
+
+#define IFILE_FROM_FHAND(a) CR (a, FAT_IFILE, Handle, FAT_IFILE_SIGNATURE)
+
+#define DIRENT_FROM_LINK(a) CR (a, FAT_DIRENT, Link, FAT_DIRENT_SIGNATURE)
+
+#define VOLUME_FROM_ROOT_DIRENT(a) CR (a, FAT_VOLUME, RootDirEnt, FAT_VOLUME_SIGNATURE)
+
+#define VOLUME_FROM_VOL_INTERFACE(a) CR (a, FAT_VOLUME, VolumeInterface, FAT_VOLUME_SIGNATURE);
+
+#define ODIR_FROM_DIRCACHELINK(a) CR (a, FAT_ODIR, DirCacheLink, FAT_ODIR_SIGNATURE)
+
+#define OFILE_FROM_CHECKLINK(a) CR (a, FAT_OFILE, CheckLink, FAT_OFILE_SIGNATURE)
+
+#define OFILE_FROM_CHILDLINK(a) CR (a, FAT_OFILE, ChildLink, FAT_OFILE_SIGNATURE)
+
+//
+// Minimum sector size is 512B, Maximum sector size is 4096B
+// Max sectors per cluster is 128
+//
+#define MAX_BLOCK_ALIGNMENT 12
+#define MIN_BLOCK_ALIGNMENT 9
+#define MAX_SECTORS_PER_CLUSTER_ALIGNMENT 7
+
+//
+// Efi Time Definition
+//
+#define IS_LEAP_YEAR(a) (((a) % 4 == 0) && (((a) % 100 != 0) || ((a) % 400 == 0)))
+
+//
+// Minimum fat page size is 8K, maximum fat page alignment is 32K
+// Minimum data page size is 8K, maximum fat page alignment is 64K
+//
+#define FAT_FATCACHE_PAGE_MIN_ALIGNMENT 13
+#define FAT_FATCACHE_PAGE_MAX_ALIGNMENT 15
+#define FAT_DATACACHE_PAGE_MIN_ALIGNMENT 13
+#define FAT_DATACACHE_PAGE_MAX_ALIGNMENT 16
+#define FAT_DATACACHE_GROUP_COUNT 64
+#define FAT_FATCACHE_GROUP_MIN_COUNT 1
+#define FAT_FATCACHE_GROUP_MAX_COUNT 16
+
+//
+// Used in 8.3 generation algorithm
+//
+#define MAX_SPEC_RETRY 4
+#define SPEC_BASE_TAG_LEN 6
+#define HASH_BASE_TAG_LEN 2
+#define HASH_VALUE_TAG_LEN (SPEC_BASE_TAG_LEN - HASH_BASE_TAG_LEN)
+
+//
+// Path name separator is back slash
+//
+#define PATH_NAME_SEPARATOR L'\\'
+
+
+#define EFI_PATH_STRING_LENGTH 260
+#define EFI_FILE_STRING_LENGTH 255
+#define FAT_MAX_ALLOCATE_SIZE 0xA00000
+#define LC_ISO_639_2_ENTRY_SIZE 3
+#define MAX_LANG_CODE_SIZE 100
+
+#define FAT_MAX_DIR_CACHE_COUNT 8
+#define FAT_MAX_DIRENTRY_COUNT 0xFFFF
+typedef CHAR8 LC_ISO_639_2;
+
+//
+// The fat types we support
+//
+typedef enum {
+ FAT12,
+ FAT16,
+ FAT32,
+ FatUndefined
+} FAT_VOLUME_TYPE;
+
+typedef enum {
+ CACHE_FAT,
+ CACHE_DATA,
+ CACHE_MAX_TYPE
+} CACHE_DATA_TYPE;
+
+//
+// Used in FatDiskIo
+//
+typedef enum {
+ READ_DISK = 0, // raw disk read
+ WRITE_DISK = 1, // raw disk write
+ READ_FAT = 2, // read fat cache
+ WRITE_FAT = 3, // write fat cache
+ READ_DATA = 6, // read data cache
+ WRITE_DATA = 7 // write data cache
+} IO_MODE;
+
+#define CACHE_ENABLED(a) ((a) >= 2)
+#define RAW_ACCESS(a) ((IO_MODE)((a) & 0x1))
+#define CACHE_TYPE(a) ((CACHE_DATA_TYPE)((a) >> 2))
+
+//
+// Disk cache tag
+//
+typedef struct {
+ UINTN PageNo;
+ UINTN RealSize;
+ BOOLEAN Dirty;
+} CACHE_TAG;
+
+typedef struct {
+ UINT64 BaseAddress;
+ UINT64 LimitAddress;
+ UINT8 *CacheBase;
+ BOOLEAN Dirty;
+ UINT8 PageAlignment;
+ UINTN GroupMask;
+ CACHE_TAG CacheTag[FAT_DATACACHE_GROUP_COUNT];
+} DISK_CACHE;
+
+//
+// Hash table size
+//
+#define HASH_TABLE_SIZE 0x400
+#define HASH_TABLE_MASK (HASH_TABLE_SIZE - 1)
+
+//
+// The directory entry for opened directory
+//
+typedef struct _FAT_DIRENT {
+ UINTN Signature;
+ UINT16 EntryPos; // The position of this directory entry in the parent directory file
+ UINT8 EntryCount; // The count of the directory entry in the parent directory file
+ BOOLEAN Invalid; // Indicate whether this directory entry is valid
+ CHAR16 *FileString; // The unicode long file name for this directory entry
+ struct _FAT_OFILE *OFile; // The OFile of the corresponding directory entry
+ struct _FAT_DIRENT *ShortNameForwardLink; // Hash successor link for short filename
+ struct _FAT_DIRENT *LongNameForwardLink; // Hash successor link for long filename
+ LIST_ENTRY Link; // Connection of every directory entry
+ FAT_DIRECTORY_ENTRY Entry; // The physical directory entry stored in disk
+} FAT_DIRENT;
+
+typedef struct _FAT_ODIR {
+ UINTN Signature;
+ UINT32 CurrentEndPos; // Current end position of the directory
+ UINT32 CurrentPos; // Current position of the directory
+ LIST_ENTRY *CurrentCursor; // Current directory entry pointer
+ LIST_ENTRY ChildList; // List of all directory entries
+ BOOLEAN EndOfDir; // Indicate whether we have reached the end of the directory
+ LIST_ENTRY DirCacheLink; // Linked in Volume->DirCacheList when discarded
+ UINTN DirCacheTag; // The identification of the directory when in directory cache
+ FAT_DIRENT *LongNameHashTable[HASH_TABLE_SIZE];
+ FAT_DIRENT *ShortNameHashTable[HASH_TABLE_SIZE];
+} FAT_ODIR;
+
+typedef struct {
+ UINTN Signature;
+ EFI_FILE Handle;
+ UINT64 Position;
+ BOOLEAN ReadOnly;
+ struct _FAT_OFILE *OFile;
+ LIST_ENTRY Link;
+} FAT_IFILE;
+
+//
+// FAT_OFILE - Each opened file
+//
+typedef struct _FAT_OFILE {
+ UINTN Signature;
+ struct _FAT_VOLUME *Volume;
+ //
+ // A permanant error code to return to all accesses to
+ // this opened file
+ //
+ EFI_STATUS Error;
+ //
+ // A list of the IFILE instances for this OFile
+ //
+ LIST_ENTRY Opens;
+
+ //
+ // The dynamic infomation
+ //
+ UINTN FileSize;
+ UINTN FileCluster;
+ UINTN FileCurrentCluster;
+ UINTN FileLastCluster;
+
+ //
+ // Dirty is set if there have been any updates to the
+ // file
+ // Archive is set if the archive attribute in the file’s
+ // directory entry needs to be set when performing flush
+ // PreserveLastMod is set if the last modification of the
+ // file is specified by SetInfo API
+ //
+ BOOLEAN Dirty;
+ BOOLEAN IsFixedRootDir;
+ BOOLEAN PreserveLastModification;
+ BOOLEAN Archive;
+ //
+ // Set by an OFile SetPosition
+ //
+ UINTN Position; // within file
+ UINT64 PosDisk; // on the disk
+ UINTN PosRem; // remaining in this disk run
+ //
+ // The opened parent, full path length and currently opened child files
+ //
+ struct _FAT_OFILE *Parent;
+ UINTN FullPathLen;
+ LIST_ENTRY ChildHead;
+ LIST_ENTRY ChildLink;
+
+ //
+ // The opened directory structure for a directory; if this
+ // OFile represents a file, then ODir = NULL
+ //
+ FAT_ODIR *ODir;
+ //
+ // The directory entry for the Ofile
+ //
+ FAT_DIRENT *DirEnt;
+
+ //
+ // Link in Volume's reference list
+ //
+ LIST_ENTRY CheckLink;
+} FAT_OFILE;
+
+typedef struct _FAT_VOLUME {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ BOOLEAN Valid;
+ BOOLEAN DiskError;
+
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL VolumeInterface;
+
+ //
+ // If opened, the parent handle and BlockIo interface
+ //
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ UINT32 MediaId;
+ BOOLEAN ReadOnly;
+
+ //
+ // Computed values from fat bpb info
+ //
+ UINT64 VolumeSize;
+ UINT64 FatPos; // Disk pos of fat tables
+ UINT64 RootPos; // Disk pos of root directory
+ UINT64 FirstClusterPos; // Disk pos of first cluster
+ UINTN FatSize; // Number of bytes in each fat
+ UINTN MaxCluster; // Max cluster number
+ UINTN ClusterSize; // Cluster size of fat partition
+ UINT8 ClusterAlignment; // Equal to log_2 (clustersize);
+ FAT_VOLUME_TYPE FatType;
+
+ //
+ // Current part of fat table that's present
+ //
+ UINT64 FatEntryPos; // Location of buffer
+ UINTN FatEntrySize; // Size of buffer
+ UINT32 FatEntryBuffer; // The buffer
+ FAT_INFO_SECTOR FatInfoSector; // Free cluster info
+ UINTN FreeInfoPos; // Pos with the free cluster info
+ BOOLEAN FreeInfoValid; // If free cluster info is valid
+ //
+ // Unpacked Fat BPB info
+ //
+ UINTN NumFats;
+ UINTN RootEntries; // < FAT32, root dir is fixed size
+ UINTN RootCluster; // >= FAT32, root cluster chain head
+ //
+ // info for marking the volume dirty or not
+ //
+ BOOLEAN FatDirty; // If fat-entries have been updated
+ UINT32 DirtyValue;
+ UINT32 NotDirtyValue;
+
+ //
+ // The root directory entry and opened root file
+ //
+ FAT_DIRENT RootDirEnt;
+ //
+ // File Name of root OFile, it is empty string
+ //
+ CHAR16 RootFileString[1];
+ struct _FAT_OFILE *Root;
+
+ //
+ // New OFiles are added to this list so they
+ // can be cleaned up if they aren't referenced.
+ //
+ LIST_ENTRY CheckRef;
+
+ //
+ // Directory cache List
+ //
+ LIST_ENTRY DirCacheList;
+ UINTN DirCacheCount;
+
+ //
+ // Disk Cache for this volume
+ //
+ VOID *CacheBuffer;
+ DISK_CACHE DiskCache[CACHE_MAX_TYPE];
+} FAT_VOLUME;
+
+//
+// Function Prototypes
+//
+EFI_STATUS
+EFIAPI
+FatOpen (
+ IN EFI_FILE *FHand,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+/*++
+Routine Description:
+
+ Implements Open() of Simple File System Protocol.
+
+Arguments:
+
+ FHand - File handle of the file serves as a starting reference point.
+ NewHandle - Handle of the file that is newly opened.
+ FileName - File name relative to FHand.
+ OpenMode - Open mode.
+ Attributes - Attributes to set if the file is created.
+
+Returns:
+
+ EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.
+ The OpenMode is not supported.
+ The Attributes is not the valid attributes.
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string.
+ EFI_SUCCESS - Open the file successfully.
+ Others - The status of open file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatGetPosition (
+ IN EFI_FILE *FHand,
+ OUT UINT64 *Position
+ )
+/*++
+
+Routine Description:
+
+ Get the file's position of the file
+
+Arguments:
+
+ FHand - The handle of file.
+ Position - The file's position of the file.
+
+Returns:
+
+ EFI_SUCCESS - Get the info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+ EFI_UNSUPPORTED - The open file is not a file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatGetInfo (
+ IN EFI_FILE *FHand,
+ IN EFI_GUID *Type,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the some types info of the file into Buffer
+
+Arguments:
+
+ FHand - The handle of file.
+ Type - The type of the info.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing volume info.
+
+Returns:
+
+ EFI_SUCCESS - Get the info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatSetInfo (
+ IN EFI_FILE *FHand,
+ IN EFI_GUID *Type,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Set the some types info of the file into Buffer
+
+Arguments:
+
+ FHand - The handle of file.
+ Type - The type of the info.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing volume info.
+
+Returns:
+
+ EFI_SUCCESS - Set the info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatFlush (
+ IN EFI_FILE *FHand
+ )
+/*++
+
+Routine Description:
+
+ Flushes all data associated with the file handle
+
+Arguments:
+
+ FHand - Handle to file to flush
+
+Returns:
+
+ EFI_SUCCESS - Flushed the file successfully
+ EFI_WRITE_PROTECTED - The volume is read only
+ EFI_ACCESS_DENIED - The volume is not read only
+ but the file is read only
+ Others - Flushing of the file is failed
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatClose (
+ IN EFI_FILE *FHand
+ )
+/*++
+
+Routine Description:
+
+ Flushes & Closes the file handle.
+
+Arguments:
+
+ FHand - Handle to the file to delete.
+
+Returns:
+
+ EFI_SUCCESS - Closed the file successfully.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatDelete (
+ IN EFI_FILE *FHand
+ )
+/*++
+
+Routine Description:
+
+ Deletes the file & Closes the file handle.
+
+Arguments:
+
+ FHand - Handle to the file to delete.
+
+Returns:
+
+ EFI_SUCCESS - Delete the file successfully.
+ EFI_WARN_DELETE_FAILURE - Fail to delete the file.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatSetPosition (
+ IN EFI_FILE *FHand,
+ IN UINT64 Position
+ )
+/*++
+
+Routine Description:
+
+ Set the file's position of the file
+
+Arguments:
+
+ FHand - The handle of file
+ Position - The file's position of the file
+
+Returns:
+
+ EFI_SUCCESS - Set the info successfully
+ EFI_DEVICE_ERROR - Can not find the OFile for the file
+ EFI_UNSUPPORTED - Set a directory with a not-zero position
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatRead (
+ IN EFI_FILE *FHand,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the file info.
+
+Arguments:
+
+ FHand - The handle of the file.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing read data.
+
+Returns:
+
+ EFI_SUCCESS - Get the file info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.
+ other - An error occurred when operation the disk.
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+FatWrite (
+ IN EFI_FILE *FHand,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Set the file info.
+
+Arguments:
+
+ FHand - The handle of the file.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing write data.
+
+Returns:
+
+ EFI_SUCCESS - Set the file info successfully.
+ EFI_WRITE_PROTECTED - The disk is write protected.
+ EFI_ACCESS_DENIED - The file is read-only.
+ EFI_DEVICE_ERROR - The OFile is not valid.
+ EFI_UNSUPPORTED - The open file is not a file.
+ - The writing file size is larger than 4GB.
+ other - An error occurred when operation the disk.
+
+--*/
+;
+
+//
+// DiskCache.c
+//
+EFI_STATUS
+FatInitializeDiskCache (
+ IN FAT_VOLUME *Volume
+ );
+
+EFI_STATUS
+FatAccessCache (
+ IN FAT_VOLUME *Volume,
+ IN CACHE_DATA_TYPE CacheDataType,
+ IN IO_MODE IoMode,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN OUT UINT8 *Buffer
+ );
+
+EFI_STATUS
+FatVolumeFlushCache (
+ IN FAT_VOLUME *Volume
+ );
+
+//
+// Flush.c
+//
+EFI_STATUS
+FatOFileFlush (
+ IN FAT_OFILE *OFile
+ );
+
+BOOLEAN
+FatCheckOFileRef (
+ IN FAT_OFILE *OFile
+ );
+
+VOID
+FatSetVolumeError (
+ IN FAT_OFILE *OFile,
+ IN EFI_STATUS Status
+ );
+
+EFI_STATUS
+FatIFileClose (
+ FAT_IFILE *IFile
+ );
+
+EFI_STATUS
+FatCleanupVolume (
+ IN FAT_VOLUME *Volume,
+ IN FAT_OFILE *OFile,
+ IN EFI_STATUS EfiStatus
+ );
+
+//
+// FileSpace.c
+//
+EFI_STATUS
+FatShrinkEof (
+ IN FAT_OFILE *OFile
+ );
+
+EFI_STATUS
+FatGrowEof (
+ IN FAT_OFILE *OFile,
+ IN UINT64 NewSizeInBytes
+ );
+
+UINTN
+FatPhysicalDirSize (
+ IN FAT_VOLUME *Volume,
+ IN UINTN Cluster
+ );
+
+UINT64
+FatPhysicalFileSize (
+ IN FAT_VOLUME *Volume,
+ IN UINTN RealSize
+ );
+
+EFI_STATUS
+FatOFilePosition (
+ IN FAT_OFILE *OFile,
+ IN UINTN Position,
+ IN UINTN PosLimit
+ );
+
+VOID
+FatComputeFreeInfo (
+ IN FAT_VOLUME *Volume
+ );
+
+//
+// Init.c
+//
+EFI_STATUS
+FatAllocateVolume (
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo
+ );
+
+EFI_STATUS
+FatOpenDevice (
+ IN OUT FAT_VOLUME *Volume
+ );
+
+EFI_STATUS
+FatAbandonVolume (
+ IN FAT_VOLUME *Volume
+ );
+
+//
+// Misc.c
+//
+EFI_STATUS
+FatAccessVolumeDirty (
+ IN FAT_VOLUME *Volume,
+ IN IO_MODE IoMode,
+ IN VOID *DirtyValue
+ );
+
+EFI_STATUS
+FatDiskIo (
+ IN FAT_VOLUME *Volume,
+ IN IO_MODE IoMode,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ );
+
+VOID
+FatAcquireLock (
+ VOID
+ );
+
+VOID
+FatReleaseLock (
+ VOID
+ );
+
+BOOLEAN
+FatIsLocked (
+ VOID
+ );
+
+VOID
+FatFreeDirEnt (
+ IN FAT_DIRENT *DirEnt
+ );
+
+VOID
+FatFreeVolume (
+ IN FAT_VOLUME *Volume
+ );
+
+VOID
+FatEfiTimeToFatTime (
+ IN EFI_TIME *ETime,
+ OUT FAT_DATE_TIME *FTime
+ );
+
+VOID
+FatFatTimeToEfiTime (
+ IN FAT_DATE_TIME *FTime,
+ OUT EFI_TIME *ETime
+ );
+
+VOID
+FatGetCurrentFatTime (
+ OUT FAT_DATE_TIME *FatTime
+ );
+
+BOOLEAN
+FatIsValidTime (
+ IN EFI_TIME *Time
+ );
+
+//
+// UnicodeCollation.c
+//
+EFI_STATUS
+InitializeUnicodeCollationSupport (
+ IN EFI_HANDLE AgentHandle
+ );
+
+VOID
+FatFatToStr (
+ IN UINTN FatSize,
+ IN CHAR8 *Fat,
+ OUT CHAR16 *String
+ );
+
+BOOLEAN
+FatStrToFat (
+ IN CHAR16 *String,
+ IN UINTN FatSize,
+ OUT CHAR8 *Fat
+ );
+
+VOID
+FatStrLwr (
+ IN CHAR16 *Str
+ );
+
+VOID
+FatStrUpr (
+ IN CHAR16 *Str
+ );
+
+INTN
+FatStriCmp (
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ );
+
+//
+// Open.c
+//
+EFI_STATUS
+FatOFileOpen (
+ IN FAT_OFILE *OFile,
+ OUT FAT_IFILE **NewIFile,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT8 Attributes
+ );
+
+EFI_STATUS
+FatAllocateIFile (
+ IN FAT_OFILE *OFile,
+ OUT FAT_IFILE **PtrIFile
+ );
+
+//
+// OpenVolume.c
+//
+EFI_STATUS
+EFIAPI
+FatOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE **File
+ );
+
+//
+// ReadWrite.c
+//
+EFI_STATUS
+FatAccessOFile (
+ IN FAT_OFILE *OFile,
+ IN IO_MODE IoMode,
+ IN UINTN Position,
+ IN UINTN *DataBufferSize,
+ IN UINT8 *UserBuffer
+ );
+
+EFI_STATUS
+FatExpandOFile (
+ IN FAT_OFILE *OFile,
+ IN UINT64 ExpandedSize
+ );
+
+EFI_STATUS
+FatWriteZeroPool (
+ IN FAT_OFILE *OFile,
+ IN UINTN WritePos
+ );
+
+EFI_STATUS
+FatTruncateOFile (
+ IN FAT_OFILE *OFile,
+ IN UINTN TruncatedSize
+ );
+
+//
+// DirectoryManage.c
+//
+VOID
+FatResetODirCursor (
+ IN FAT_OFILE *OFile
+ );
+
+EFI_STATUS
+FatGetNextDirEnt (
+ IN FAT_OFILE *OFILE,
+ OUT FAT_DIRENT **PtrDirEnt
+ );
+
+EFI_STATUS
+FatRemoveDirEnt (
+ IN FAT_OFILE *OFile,
+ IN FAT_DIRENT *DirEnt
+ );
+
+EFI_STATUS
+FatStoreDirEnt (
+ IN FAT_OFILE *OFile,
+ IN FAT_DIRENT *DirEnt
+ );
+
+EFI_STATUS
+FatCreateDirEnt (
+ IN FAT_OFILE *OFile,
+ IN CHAR16 *FileName,
+ IN UINT8 Attributes,
+ OUT FAT_DIRENT **PtrDirEnt
+ );
+
+BOOLEAN
+FatIsDotDirEnt (
+ IN FAT_DIRENT *DirEnt
+ );
+
+VOID
+FatUpdateDirEntClusterSizeInfo (
+ IN FAT_OFILE *OFile
+ );
+
+VOID
+FatCloneDirEnt (
+ IN FAT_DIRENT *DirEnt1,
+ IN FAT_DIRENT *DirEnt2
+ );
+
+EFI_STATUS
+FatGetDirEntInfo (
+ IN FAT_VOLUME *Volume,
+ IN FAT_DIRENT *DirEnt,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+EFI_STATUS
+FatOpenDirEnt (
+ IN FAT_OFILE *OFile,
+ IN FAT_DIRENT *DirEnt
+ );
+
+EFI_STATUS
+FatCreateDotDirEnts (
+ IN FAT_OFILE *OFile
+ );
+
+VOID
+FatCloseDirEnt (
+ IN FAT_DIRENT *DirEnt
+ );
+
+EFI_STATUS
+FatLocateOFile (
+ IN OUT FAT_OFILE **PtrOFile,
+ IN CHAR16 *FileName,
+ IN UINT8 Attributes,
+ OUT CHAR16 *NewFileName
+ );
+
+EFI_STATUS
+FatGetVolumeEntry (
+ IN FAT_VOLUME *Volume,
+ IN CHAR16 *Name
+ );
+
+EFI_STATUS
+FatSetVolumeEntry (
+ IN FAT_VOLUME *Volume,
+ IN CHAR16 *Name
+ );
+
+//
+// Hash.c
+//
+FAT_DIRENT **
+FatLongNameHashSearch (
+ IN FAT_ODIR *ODir,
+ IN CHAR16 *LongNameString
+ );
+
+FAT_DIRENT **
+FatShortNameHashSearch (
+ IN FAT_ODIR *ODir,
+ IN CHAR8 *ShortNameString
+ );
+
+VOID
+FatInsertToHashTable (
+ IN FAT_ODIR *ODir,
+ IN FAT_DIRENT *DirEnt
+ );
+
+VOID
+FatDeleteFromHashTable (
+ IN FAT_ODIR *ODir,
+ IN FAT_DIRENT *DirEnt
+ );
+
+//
+// FileName.c
+//
+BOOLEAN
+FatCheckIs8Dot3Name (
+ IN CHAR16 *FileName,
+ OUT CHAR8 *File8Dot3Name
+ );
+
+VOID
+FatCreate8Dot3Name (
+ IN FAT_OFILE *Parent,
+ IN FAT_DIRENT *DirEnt
+ );
+
+VOID
+FatNameToStr (
+ IN CHAR8 *FatName,
+ IN UINTN Len,
+ IN UINTN LowerCase,
+ IN CHAR16 *Str
+ );
+
+VOID
+FatSetCaseFlag (
+ IN FAT_DIRENT *DirEnt
+ );
+
+VOID
+FatGetFileNameViaCaseFlag (
+ IN FAT_DIRENT *DirEnt,
+ OUT CHAR16 *FileString
+ );
+
+UINT8
+FatCheckSum (
+ IN CHAR8 *ShortNameString
+ );
+
+CHAR16*
+FatGetNextNameComponent (
+ IN CHAR16 *Path,
+ OUT CHAR16 *Name
+ );
+
+BOOLEAN
+FatFileNameIsValid (
+ IN CHAR16 *InputFileName,
+ OUT CHAR16 *OutputFileName
+ );
+
+//
+// DirectoryCache.c
+//
+VOID
+FatDiscardODir (
+ IN FAT_OFILE *OFile
+ );
+
+VOID
+FatRequestODir (
+ IN FAT_OFILE *OFile
+ );
+
+VOID
+FatCleanupODirCache (
+ IN FAT_VOLUME *Volume
+ );
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gFatDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gFatComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gFatComponentName2;
+extern EFI_LOCK FatFsLock;
+extern EFI_FILE FatFileInterface;
+
+#endif
diff --git a/FatPkg/EnhancedFatDxe/Fat.inf b/FatPkg/EnhancedFatDxe/Fat.inf
new file mode 100644
index 0000000000..56f37cb667
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Fat.inf
@@ -0,0 +1,98 @@
+#/** @file
+# Component description file for FAT module.
+#
+# This UEFI driver detects the FAT file system in the disk.
+# It also produces the Simple File System protocol for the consumer to
+# perform file and directory operations on the disk.
+# Copyright (c) 2007, Intel Corporation
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Fat
+ FILE_GUID = 961578FE-B6B7-44c3-AF35-6BC705CD2B1F
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = FatEntryPoint
+ UNLOAD_IMAGE = FatUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gFatDriverBinding
+# COMPONENT_NAME = gFatComponentName
+# COMPONENT_NAME2 = gFatComponentName2
+#
+
+[Sources.common]
+ DirectoryCache.c
+ DiskCache.c
+ FileName.c
+ Hash.c
+ DirectoryManage.c
+ ComponentName.c
+ FatFileSystem.h
+ Fat.h
+ ReadWrite.c
+ OpenVolume.c
+ Open.c
+ Misc.c
+ Init.c
+ Info.c
+ FileSpace.c
+ Flush.c
+ Fat.c
+ Delete.c
+ Data.c
+ UnicodeCollation.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ FatPkg/FatPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[Guids]
+ gEfiFileInfoGuid
+ gEfiFileSystemInfoGuid
+ gEfiFileSystemVolumeLabelInfoIdGuid
+ gEfiGlobalVariableGuid
+
+[Protocols]
+ gEfiDiskIoProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiUnicodeCollationProtocolGuid
+ gEfiUnicodeCollation2ProtocolGuid
+
+[FeaturePcd]
+ gEfiFatPkgTokenSpaceGuid.PcdUnicodeCollationSupport
+ gEfiFatPkgTokenSpaceGuid.PcdUnicodeCollation2Support
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang
diff --git a/FatPkg/EnhancedFatDxe/FatFileSystem.h b/FatPkg/EnhancedFatDxe/FatFileSystem.h
new file mode 100644
index 0000000000..d6fd8e46b3
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/FatFileSystem.h
@@ -0,0 +1,221 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ FatFileSystem.h
+
+Abstract:
+
+ Definitions for on-disk FAT structures
+
+Revision History
+
+--*/
+
+#ifndef _FATFILESYSTEM_H_
+#define _FATFILESYSTEM_H_
+
+#pragma pack(1)
+//
+// FAT info signature
+//
+#define FAT_INFO_SIGNATURE 0x41615252
+#define FAT_INFO_BEGIN_SIGNATURE 0x61417272
+#define FAT_INFO_END_SIGNATURE 0xAA550000
+//
+// FAT entry values
+//
+#define FAT_CLUSTER_SPECIAL_EXT (-1 & (~0xF))
+#define FAT_CLUSTER_SPECIAL ((FAT_CLUSTER_SPECIAL_EXT) | 0x07)
+#define FAT_CLUSTER_FREE 0
+#define FAT_CLUSTER_RESERVED (FAT_CLUSTER_SPECIAL)
+#define FAT_CLUSTER_BAD (FAT_CLUSTER_SPECIAL)
+#define FAT_CLUSTER_LAST (-1)
+#define FAT_END_OF_FAT_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL))
+#define FAT_MIN_CLUSTER 2
+#define FAT_MAX_FAT12_CLUSTER 0xFF5
+#define FAT_MAX_FAT16_CLUSTER 0xFFF5
+#define FAT_CLUSTER_SPECIAL_FAT12 0xFF7
+#define FAT_CLUSTER_SPECIAL_FAT16 0xFFF7
+#define FAT_CLUSTER_SPECIAL_FAT32 0x0FFFFFF7
+#define FAT_CLUSTER_MASK_FAT12 0xFFF
+#define FAT_CLUSTER_UNMASK_FAT12 0xF000
+#define FAT_CLUSTER_MASK_FAT32 0x0FFFFFFF
+#define FAT_CLUSTER_UNMASK_FAT32 0xF0000000
+#define FAT_POS_FAT12(a) ((a) * 3 / 2)
+#define FAT_POS_FAT16(a) ((a) * 2)
+#define FAT_POS_FAT32(a) ((a) * 4)
+#define FAT_ODD_CLUSTER_FAT12(a) (((a) & 1) != 0)
+
+
+//
+// FAT attribute define
+//
+#define FAT_ATTRIBUTE_READ_ONLY 0x01
+#define FAT_ATTRIBUTE_HIDDEN 0x02
+#define FAT_ATTRIBUTE_SYSTEM 0x04
+#define FAT_ATTRIBUTE_VOLUME_ID 0x08
+#define FAT_ATTRIBUTE_DIRECTORY 0x10
+#define FAT_ATTRIBUTE_ARCHIVE 0x20
+#define FAT_ATTRIBUTE_DEVICE 0x40
+#define FAT_ATTRIBUTE_LFN 0x0F
+//
+// Some Long File Name definitions
+//
+#define FAT_LFN_LAST 0x40 // Ordinal field
+#define MAX_LFN_ENTRIES 20
+#define LFN_CHAR1_LEN 5
+#define LFN_CHAR2_LEN 6
+#define LFN_CHAR3_LEN 2
+#define LFN_CHAR_TOTAL (LFN_CHAR1_LEN + LFN_CHAR2_LEN + LFN_CHAR3_LEN)
+#define LFN_ENTRY_NUMBER(a) (((a) + LFN_CHAR_TOTAL - 1) / LFN_CHAR_TOTAL)
+//
+// Some 8.3 File Name definitions
+//
+#define FAT_MAIN_NAME_LEN 8
+#define FAT_EXTEND_NAME_LEN 3
+#define FAT_NAME_LEN (FAT_MAIN_NAME_LEN + FAT_EXTEND_NAME_LEN)
+//
+// Some directory entry information
+//
+#define FAT_ENTRY_INFO_OFFSET 13
+#define DELETE_ENTRY_MARK 0xE5
+#define EMPTY_ENTRY_MARK 0x00
+
+//
+// Volume dirty Mask
+//
+#define FAT16_DIRTY_MASK 0x7fff
+#define FAT32_DIRTY_MASK 0xf7ffffff
+//
+// internal flag
+//
+#define FAT_CASE_MIXED 0x01
+#define FAT_CASE_NAME_LOWER 0x08
+#define FAT_CASE_EXT_LOWER 0x10
+
+typedef struct {
+ UINT8 Ia32Jump[3];
+ CHAR8 OemId[8];
+ UINT16 SectorSize;
+ UINT8 SectorsPerCluster;
+ UINT16 ReservedSectors;
+ UINT8 NumFats;
+ UINT16 RootEntries; // < FAT32, root dir is fixed size
+ UINT16 Sectors;
+ UINT8 Media;
+ UINT16 SectorsPerFat; // < FAT32
+ UINT16 SectorsPerTrack; // (ignored)
+ UINT16 Heads; // (ignored)
+ UINT32 HiddenSectors; // (ignored)
+ UINT32 LargeSectors; // Used if Sectors==0
+} FAT_BOOT_SECTOR_BASIC;
+
+typedef struct {
+ UINT8 PhysicalDriveNumber; // (ignored)
+ UINT8 CurrentHead; // holds boot_sector_dirty bit
+ UINT8 Signature; // (ignored)
+ CHAR8 Id[4];
+ CHAR8 FatLabel[11];
+ CHAR8 SystemId[8];
+} FAT_BOOT_SECTOR_EXT;
+
+typedef struct {
+ UINT32 LargeSectorsPerFat; // FAT32
+ UINT16 ExtendedFlags; // FAT32 (ignored)
+ UINT16 FsVersion; // FAT32 (ignored)
+ UINT32 RootDirFirstCluster; // FAT32
+ UINT16 FsInfoSector; // FAT32
+ UINT16 BackupBootSector; // FAT32
+ UINT8 Reserved[12]; // FAT32 (ignored)
+ UINT8 PhysicalDriveNumber; // (ignored)
+ UINT8 CurrentHead; // holds boot_sector_dirty bit
+ UINT8 Signature; // (ignored)
+ CHAR8 Id[4];
+ CHAR8 FatLabel[11];
+ CHAR8 SystemId[8];
+} FAT32_BOOT_SECTOR_EXT;
+
+typedef struct {
+ FAT_BOOT_SECTOR_BASIC FatBsb;
+ union {
+ FAT_BOOT_SECTOR_EXT FatBse;
+ FAT32_BOOT_SECTOR_EXT Fat32Bse;
+ } FatBse;
+} FAT_BOOT_SECTOR;
+
+//
+// FAT Info Structure
+//
+typedef struct {
+ UINT32 ClusterCount;
+ UINT32 NextCluster;
+} FAT_FREE_INFO;
+
+typedef struct {
+ UINT32 Signature;
+ UINT8 ExtraBootCode[480];
+ UINT32 InfoBeginSignature;
+ FAT_FREE_INFO FreeInfo;
+ UINT8 Reserved[12];
+ UINT32 InfoEndSignature;
+} FAT_INFO_SECTOR;
+
+//
+// Directory Entry
+//
+#define FAT_MAX_YEAR_FROM_1980 0x7f
+typedef struct {
+ UINT16 Day : 5;
+ UINT16 Month : 4;
+ UINT16 Year : 7; // From 1980
+} FAT_DATE;
+
+typedef struct {
+ UINT16 DoubleSecond : 5;
+ UINT16 Minute : 6;
+ UINT16 Hour : 5;
+} FAT_TIME;
+
+typedef struct {
+ FAT_TIME Time;
+ FAT_DATE Date;
+} FAT_DATE_TIME;
+
+typedef struct {
+ CHAR8 FileName[11]; // 8.3 filename
+ UINT8 Attributes;
+ UINT8 CaseFlag;
+ UINT8 CreateMillisecond; // (creation milliseconds - ignored)
+ FAT_DATE_TIME FileCreateTime;
+ FAT_DATE FileLastAccess;
+ UINT16 FileClusterHigh; // >= FAT32
+ FAT_DATE_TIME FileModificationTime;
+ UINT16 FileCluster;
+ UINT32 FileSize;
+} FAT_DIRECTORY_ENTRY;
+
+typedef struct {
+ UINT8 Ordinal;
+ CHAR8 Name1[10]; // (Really 5 chars, but not WCHAR aligned)
+ UINT8 Attributes;
+ UINT8 Type;
+ UINT8 Checksum;
+ CHAR16 Name2[6];
+ UINT16 MustBeZero;
+ CHAR16 Name3[2];
+} FAT_DIRECTORY_LFN;
+
+#pragma pack()
+
+#endif
diff --git a/FatPkg/EnhancedFatDxe/FileName.c b/FatPkg/EnhancedFatDxe/FileName.c
new file mode 100644
index 0000000000..8ad298a2d7
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/FileName.c
@@ -0,0 +1,583 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ FileName.c
+
+Abstract:
+
+ Functions for manipulating file names
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+BOOLEAN
+FatCheckIs8Dot3Name (
+ IN CHAR16 *FileName,
+ OUT CHAR8 *File8Dot3Name
+ )
+/*++
+
+Routine Description:
+
+ This function checks whether the input FileName is a valid 8.3 short name.
+ If the input FileName is a valid 8.3, the output is the 8.3 short name;
+ otherwise, the output is the base tag of 8.3 short name.
+
+Arguments:
+
+ FileName - The input unicode filename.
+ File8Dot3Name - The output ascii 8.3 short name or base tag of 8.3 short name.
+
+Returns:
+
+ TRUE - The input unicode filename is a valid 8.3 short name.
+ FALSE - The input unicode filename is not a valid 8.3 short name.
+
+--*/
+{
+ BOOLEAN PossibleShortName;
+ CHAR16 *TempName;
+ CHAR16 *ExtendName;
+ CHAR16 *SeparateDot;
+ UINTN MainNameLen;
+ UINTN ExtendNameLen;
+
+ PossibleShortName = TRUE;
+ SeparateDot = NULL;
+ SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');
+ for (TempName = FileName; *TempName; TempName++) {
+ if (*TempName == L'.') {
+ SeparateDot = TempName;
+ }
+ }
+
+ if (SeparateDot == NULL) {
+ //
+ // Extended filename is not detected
+ //
+ MainNameLen = TempName - FileName;
+ ExtendName = TempName;
+ ExtendNameLen = 0;
+ } else {
+ //
+ // Extended filename is detected
+ //
+ MainNameLen = SeparateDot - FileName;
+ ExtendName = SeparateDot + 1;
+ ExtendNameLen = TempName - ExtendName;
+ }
+ //
+ // We scan the filename for the second time
+ // to check if there exists any extra blanks and dots
+ //
+ while (--TempName >= FileName) {
+ if ((*TempName == L'.' || *TempName == L' ') && (TempName != SeparateDot)) {
+ //
+ // There exist extra blanks and dots
+ //
+ PossibleShortName = FALSE;
+ }
+ }
+
+ if (MainNameLen == 0) {
+ PossibleShortName = FALSE;
+ }
+
+ if (MainNameLen > FAT_MAIN_NAME_LEN) {
+ PossibleShortName = FALSE;
+ MainNameLen = FAT_MAIN_NAME_LEN;
+ }
+
+ if (ExtendNameLen > FAT_EXTEND_NAME_LEN) {
+ PossibleShortName = FALSE;
+ ExtendNameLen = FAT_EXTEND_NAME_LEN;
+ }
+
+ if (FatStrToFat (FileName, MainNameLen, File8Dot3Name)) {
+ PossibleShortName = FALSE;
+ }
+
+ if (FatStrToFat (ExtendName, ExtendNameLen, File8Dot3Name + FAT_MAIN_NAME_LEN)) {
+ PossibleShortName = FALSE;
+ }
+
+ return PossibleShortName;
+}
+
+STATIC
+UINTN
+FatTrimAsciiTrailingBlanks (
+ IN CHAR8 *Name,
+ IN UINTN Len
+ )
+/*++
+
+Routine Description:
+
+ Trim the trailing blanks of fat name.
+
+Arguments:
+
+ Name - The Char8 string needs to be trimed.
+ Len - The length of the fat name.
+
+Returns:
+
+ The real length of the fat name after the trailing blanks are trimmed.
+
+--*/
+{
+ while (Len > 0 && Name[Len - 1] == ' ') {
+ Len--;
+ }
+
+ return Len;
+}
+
+VOID
+FatNameToStr (
+ IN CHAR8 *FatName,
+ IN UINTN Len,
+ IN UINTN LowerCase,
+ OUT CHAR16 *Str
+ )
+/*++
+
+Routine Description:
+
+ Convert the ascii fat name to the unicode string and strip trailing spaces,
+ and if necessary, convert the unicode string to lower case.
+
+Arguments:
+
+ FatName - The Char8 string needs to be converted.
+ Len - The length of the fat name.
+ LowerCase - Indicate whether to convert the string to lower case.
+ Str - The result of the convertion.
+
+Returns:
+
+ None.
+
+--*/
+{
+ //
+ // First, trim the trailing blanks
+ //
+ Len = FatTrimAsciiTrailingBlanks (FatName, Len);
+ //
+ // Convert fat string to unicode string
+ //
+ FatFatToStr (Len, FatName, Str);
+
+ //
+ // If the name is to be lower cased, do it now
+ //
+ if (LowerCase != 0) {
+ FatStrLwr (Str);
+ }
+}
+
+VOID
+FatCreate8Dot3Name (
+ IN FAT_OFILE *Parent,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ This function generates 8Dot3 name from user specified name for a newly created file.
+
+Arguments:
+
+ Parent - The parent directory.
+ DirEnt - The directory entry whose 8Dot3Name needs to be generated.
+
+Returns:
+
+ None.
+
+--*/
+{
+ CHAR8 *ShortName;
+ CHAR8 *ShortNameChar;
+ UINTN BaseTagLen;
+ UINTN Index;
+ UINTN Retry;
+ UINT8 Segment;
+ union {
+ UINT32 Crc;
+ struct HEX_DATA {
+ UINT8 Segment : HASH_VALUE_TAG_LEN;
+ } Hex[HASH_VALUE_TAG_LEN];
+ } HashValue;
+ //
+ // Make sure the whole directory has been loaded
+ //
+ ASSERT (Parent->ODir->EndOfDir);
+ ShortName = DirEnt->Entry.FileName;
+
+ //
+ // Trim trailing blanks of 8.3 name
+ //
+ BaseTagLen = FatTrimAsciiTrailingBlanks (ShortName, FAT_MAIN_NAME_LEN);
+ if (BaseTagLen > SPEC_BASE_TAG_LEN) {
+ BaseTagLen = SPEC_BASE_TAG_LEN;
+ }
+ //
+ // We first use the algorithm described by spec.
+ //
+ ShortNameChar = ShortName + BaseTagLen;
+ *ShortNameChar++ = '~';
+ *ShortNameChar = '1';
+ Retry = 0;
+ while (*FatShortNameHashSearch (Parent->ODir, ShortName) != NULL) {
+ *ShortNameChar = (CHAR8)(*ShortNameChar + 1);
+ if (++Retry == MAX_SPEC_RETRY) {
+ //
+ // We use new algorithm to generate 8.3 name
+ //
+ ASSERT (DirEnt->FileString != NULL);
+ gBS->CalculateCrc32 (DirEnt->FileString, StrSize (DirEnt->FileString), &HashValue.Crc);
+
+ if (BaseTagLen > HASH_BASE_TAG_LEN) {
+ BaseTagLen = HASH_BASE_TAG_LEN;
+ }
+
+ ShortNameChar = ShortName + BaseTagLen;
+ for (Index = 0; Index < HASH_VALUE_TAG_LEN; Index++) {
+ Segment = HashValue.Hex[Index].Segment;
+ if (Segment > 9) {
+ *ShortNameChar++ = (CHAR8)(Segment - 10 + 'A');
+ } else {
+ *ShortNameChar++ = (CHAR8)(Segment + '0');
+ }
+ }
+
+ *ShortNameChar++ = '~';
+ *ShortNameChar = '1';
+ }
+ }
+}
+
+STATIC
+UINT8
+FatCheckNameCase (
+ IN CHAR16 *Str,
+ IN UINT8 InCaseFlag
+ )
+/*++
+
+Routine Description:
+
+ Check the string is lower case or upper case
+ and it is used by fatname to dir entry count
+
+Arguments:
+
+ Str - The string which needs to be checked.
+ InCaseFlag - The input case flag which is returned when the string is lower case.
+
+Returns:
+
+ OutCaseFlag - The output case flag.
+
+--*/
+{
+ CHAR16 Buffer[FAT_MAIN_NAME_LEN + 1];
+ UINT8 OutCaseFlag;
+
+ ASSERT (StrSize (Str) <= sizeof (Buffer));
+ //
+ // Assume the case of input string is mixed
+ //
+ OutCaseFlag = FAT_CASE_MIXED;
+ //
+ // Lower case a copy of the string, if it matches the
+ // original then the string is lower case
+ //
+ StrCpy (Buffer, Str);
+ FatStrLwr (Buffer);
+ if (StrCmp (Str, Buffer) == 0) {
+ OutCaseFlag = InCaseFlag;
+ }
+ //
+ // Upper case a copy of the string, if it matches the
+ // original then the string is upper case
+ //
+ StrCpy (Buffer, Str);
+ FatStrUpr (Buffer);
+ if (StrCmp (Str, Buffer) == 0) {
+ OutCaseFlag = 0;
+ }
+
+ return OutCaseFlag;
+}
+
+VOID
+FatSetCaseFlag (
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Set the caseflag value for the directory entry.
+
+Arguments:
+
+ DirEnt - The logical directory entry whose caseflag value is to be set.
+
+Returns:
+
+ None.
+
+--*/
+{
+ CHAR16 LfnBuffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1];
+ CHAR16 *TempCharPtr;
+ CHAR16 *ExtendName;
+ CHAR16 *FileNameCharPtr;
+ UINT8 CaseFlag;
+
+ ExtendName = NULL;
+ TempCharPtr = LfnBuffer;
+ FileNameCharPtr = DirEnt->FileString;
+ ASSERT (StrSize (DirEnt->FileString) <= sizeof (LfnBuffer));
+ while ((*TempCharPtr = *FileNameCharPtr) != 0) {
+ if (*TempCharPtr == L'.') {
+ ExtendName = TempCharPtr;
+ }
+
+ TempCharPtr++;
+ FileNameCharPtr++;
+ }
+
+ CaseFlag = 0;
+ if (ExtendName != NULL) {
+ *ExtendName = 0;
+ ExtendName++;
+ CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (ExtendName, FAT_CASE_EXT_LOWER));
+ }
+
+ CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (LfnBuffer, FAT_CASE_NAME_LOWER));
+ if ((CaseFlag & FAT_CASE_MIXED) == 0) {
+ //
+ // We just need one directory entry to store this file name entry
+ //
+ DirEnt->Entry.CaseFlag = CaseFlag;
+ } else {
+ //
+ // We need one extra directory entry to store the mixed case entry
+ //
+ DirEnt->Entry.CaseFlag = 0;
+ DirEnt->EntryCount++;
+ }
+}
+
+VOID
+FatGetFileNameViaCaseFlag (
+ IN FAT_DIRENT *DirEnt,
+ OUT CHAR16 *FileString
+ )
+/*++
+
+Routine Description:
+
+ Convert the 8.3 ASCII fat name to cased Unicode string according to case flag.
+
+Arguments:
+
+ DirEnt - The corresponding directory entry.
+ FileString - The output Unicode file name.
+
+Returns:
+
+ None.
+
+--*/
+{
+ UINT8 CaseFlag;
+ CHAR8 *File8Dot3Name;
+ CHAR16 TempExt[1 + FAT_EXTEND_NAME_LEN + 1];
+ //
+ // Store file extension like ".txt"
+ //
+ CaseFlag = DirEnt->Entry.CaseFlag;
+ File8Dot3Name = DirEnt->Entry.FileName;
+
+ FatNameToStr (File8Dot3Name, FAT_MAIN_NAME_LEN, CaseFlag & FAT_CASE_NAME_LOWER, FileString);
+ FatNameToStr (File8Dot3Name + FAT_MAIN_NAME_LEN, FAT_EXTEND_NAME_LEN, CaseFlag & FAT_CASE_EXT_LOWER, &TempExt[1]);
+ if (TempExt[1] != 0) {
+ TempExt[0] = L'.';
+ StrCat (FileString, TempExt);
+ }
+}
+
+UINT8
+FatCheckSum (
+ IN CHAR8 *ShortNameString
+ )
+/*++
+
+Routine Description:
+
+ Get the Check sum for a short name.
+
+Arguments:
+
+ ShortNameString - The short name for a file.
+
+Returns:
+
+ Sum - UINT8 checksum.
+
+--*/
+{
+ UINTN ShortNameLen;
+ UINT8 Sum;
+ Sum = 0;
+ for (ShortNameLen = FAT_NAME_LEN; ShortNameLen != 0; ShortNameLen--) {
+ Sum = (UINT8)(((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *ShortNameString++);
+ }
+
+ return Sum;
+}
+
+CHAR16 *
+FatGetNextNameComponent (
+ IN CHAR16 *Path,
+ OUT CHAR16 *Name
+ )
+/*++
+
+Routine Description:
+
+ Takes Path as input, returns the next name component
+ in Name, and returns the position after Name (e.g., the
+ start of the next name component)
+
+Arguments:
+
+ Path - The path of one file.
+ Name - The next name component in Path.
+
+Returns:
+
+ The position after Name in the Path
+
+--*/
+{
+ while (*Path != 0 && *Path != PATH_NAME_SEPARATOR) {
+ *Name++ = *Path++;
+ }
+ *Name = 0;
+ //
+ // Get off of trailing path name separator
+ //
+ while (*Path == PATH_NAME_SEPARATOR) {
+ Path++;
+ }
+
+ return Path;
+}
+
+BOOLEAN
+FatFileNameIsValid (
+ IN CHAR16 *InputFileName,
+ OUT CHAR16 *OutputFileName
+ )
+/*++
+
+Routine Description:
+
+ Check whether the IFileName is valid long file name. If the IFileName is a valid
+ long file name, then we trim the possible leading blanks and leading/trailing dots.
+ the trimmed filename is stored in OutputFileName
+
+Arguments:
+
+ InputFileName - The input file name.
+ OutputFileName - The output file name.
+
+
+Returns:
+
+ TRUE - The InputFileName is a valid long file name.
+ FALSE - The InputFileName is not a valid long file name.
+
+--*/
+{
+ CHAR16 *TempNamePointer;
+ CHAR16 TempChar;
+ //
+ // Trim Leading blanks
+ //
+ while (*InputFileName == L' ') {
+ InputFileName++;
+ }
+
+ TempNamePointer = OutputFileName;
+ while (*InputFileName != 0) {
+ *TempNamePointer++ = *InputFileName++;
+ }
+ //
+ // Trim Trailing blanks and dots
+ //
+ while (TempNamePointer > OutputFileName) {
+ TempChar = *(TempNamePointer - 1);
+ if (TempChar != L' ' && TempChar != L'.') {
+ break;
+ }
+
+ TempNamePointer--;
+ }
+
+ *TempNamePointer = 0;
+
+ //
+ // Per FAT Spec the file name should meet the following criteria:
+ // C1. Length (FileLongName) <= 255
+ // C2. Length (X:FileFullPath<NUL>) <= 260
+ // Here we check C1.
+ //
+ if (TempNamePointer - OutputFileName > EFI_FILE_STRING_LENGTH) {
+ return FALSE;
+ }
+ //
+ // See if there is any illegal characters within the name
+ //
+ do {
+ if (*OutputFileName < 0x20 ||
+ *OutputFileName == '\"' ||
+ *OutputFileName == '*' ||
+ *OutputFileName == '/' ||
+ *OutputFileName == ':' ||
+ *OutputFileName == '<' ||
+ *OutputFileName == '>' ||
+ *OutputFileName == '?' ||
+ *OutputFileName == '\\' ||
+ *OutputFileName == '|'
+ ) {
+ return FALSE;
+ }
+
+ OutputFileName++;
+ } while (*OutputFileName != 0);
+ return TRUE;
+}
diff --git a/FatPkg/EnhancedFatDxe/FileSpace.c b/FatPkg/EnhancedFatDxe/FileSpace.c
new file mode 100644
index 0000000000..24f84d2a64
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/FileSpace.c
@@ -0,0 +1,816 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ FileSpace.c
+
+Abstract:
+
+ Routines dealing with disk spaces and FAT table entries
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+
+STATIC
+VOID *
+FatLoadFatEntry (
+ IN FAT_VOLUME *Volume,
+ IN UINTN Index
+ )
+/*++
+
+Routine Description:
+
+ Get the FAT entry of the volume, which is identified with the Index.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ Index - The index of the FAT entry of the volume.
+
+Returns:
+
+ The buffer of the FAT entry
+
+--*/
+{
+ UINTN Pos;
+ EFI_STATUS Status;
+
+ if (Index > (Volume->MaxCluster + 1)) {
+ Volume->FatEntryBuffer = (UINT32) -1;
+ return &Volume->FatEntryBuffer;
+ }
+ //
+ // Compute buffer position needed
+ //
+ switch (Volume->FatType) {
+ case FAT12:
+ Pos = FAT_POS_FAT12 (Index);
+ break;
+
+ case FAT16:
+ Pos = FAT_POS_FAT16 (Index);
+ break;
+
+ default:
+ Pos = FAT_POS_FAT32 (Index);
+ }
+ //
+ // Set the position and read the buffer
+ //
+ Volume->FatEntryPos = Volume->FatPos + Pos;
+ Status = FatDiskIo (
+ Volume,
+ READ_FAT,
+ Volume->FatEntryPos,
+ Volume->FatEntrySize,
+ &Volume->FatEntryBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ Volume->FatEntryBuffer = (UINT32) -1;
+ }
+
+ return &Volume->FatEntryBuffer;
+}
+
+STATIC
+UINTN
+FatGetFatEntry (
+ IN FAT_VOLUME *Volume,
+ IN UINTN Index
+ )
+/*++
+
+Routine Description:
+
+ Get the FAT entry value of the volume, which is identified with the Index.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ Index - The index of the FAT entry of the volume.
+
+Returns:
+
+ The value of the FAT entry.
+
+--*/
+{
+ VOID *Pos;
+ UINT8 *E12;
+ UINT16 *E16;
+ UINT32 *E32;
+ UINTN Accum;
+
+ Pos = FatLoadFatEntry (Volume, Index);
+
+ if (Index > (Volume->MaxCluster + 1)) {
+ return (UINTN) -1;
+ }
+
+ switch (Volume->FatType) {
+ case FAT12:
+ E12 = Pos;
+ Accum = E12[0] | (E12[1] << 8);
+ Accum = FAT_ODD_CLUSTER_FAT12 (Index) ? (Accum >> 4) : (Accum & FAT_CLUSTER_MASK_FAT12);
+ Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT12) ? FAT_CLUSTER_SPECIAL_EXT : 0);
+ break;
+
+ case FAT16:
+ E16 = Pos;
+ Accum = *E16;
+ Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT16) ? FAT_CLUSTER_SPECIAL_EXT : 0);
+ break;
+
+ default:
+ E32 = Pos;
+ Accum = *E32 & FAT_CLUSTER_MASK_FAT32;
+ Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT32) ? FAT_CLUSTER_SPECIAL_EXT : 0);
+ }
+
+ return Accum;
+}
+
+STATIC
+EFI_STATUS
+FatSetFatEntry (
+ IN FAT_VOLUME *Volume,
+ IN UINTN Index,
+ IN UINTN Value
+ )
+/*++
+
+Routine Description:
+
+ Set the FAT entry value of the volume, which is identified with the Index.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ Index - The index of the FAT entry of the volume.
+ Value - The new value of the FAT entry.
+
+Returns:
+
+ EFI_SUCCESS - Set the new FAT entry value sucessfully.
+ EFI_VOLUME_CORRUPTED - The FAT type of the volume is error.
+ other - An error occurred when operation the FAT entries.
+
+--*/
+{
+ VOID *Pos;
+ UINT8 *E12;
+ UINT16 *E16;
+ UINT32 *E32;
+ UINTN Accum;
+ EFI_STATUS Status;
+ UINTN OriginalVal;
+
+ if (Index < FAT_MIN_CLUSTER) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ OriginalVal = FatGetFatEntry (Volume, Index);
+ if (Value == FAT_CLUSTER_FREE && OriginalVal != FAT_CLUSTER_FREE) {
+ Volume->FatInfoSector.FreeInfo.ClusterCount += 1;
+ if (Index < Volume->FatInfoSector.FreeInfo.NextCluster) {
+ Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;
+ }
+ } else if (Value != FAT_CLUSTER_FREE && OriginalVal == FAT_CLUSTER_FREE) {
+ if (Volume->FatInfoSector.FreeInfo.ClusterCount != 0) {
+ Volume->FatInfoSector.FreeInfo.ClusterCount -= 1;
+ }
+ }
+ //
+ // Make sure the entry is in memory
+ //
+ Pos = FatLoadFatEntry (Volume, Index);
+
+ //
+ // Update the value
+ //
+ switch (Volume->FatType) {
+ case FAT12:
+ E12 = Pos;
+ Accum = E12[0] | (E12[1] << 8);
+ Value = Value & FAT_CLUSTER_MASK_FAT12;
+
+ if (FAT_ODD_CLUSTER_FAT12 (Index)) {
+ Accum = (Value << 4) | (Accum & 0xF);
+ } else {
+ Accum = Value | (Accum & FAT_CLUSTER_UNMASK_FAT12);
+ }
+
+ E12[0] = (UINT8) (Accum & 0xFF);
+ E12[1] = (UINT8) (Accum >> 8);
+ break;
+
+ case FAT16:
+ E16 = Pos;
+ *E16 = (UINT16) Value;
+ break;
+
+ default:
+ E32 = Pos;
+ *E32 = (*E32 & FAT_CLUSTER_UNMASK_FAT32) | (UINT32) (Value & FAT_CLUSTER_MASK_FAT32);
+ }
+ //
+ // If the volume's dirty bit is not set, set it now
+ //
+ if (!Volume->FatDirty && Volume->FatType != FAT12) {
+ Volume->FatDirty = TRUE;
+ FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->DirtyValue);
+ }
+ //
+ // Write the updated fat entry value to the volume
+ // The fat is the first fat, and other fat will be in sync
+ // when the FAT cache flush back.
+ //
+ Status = FatDiskIo (
+ Volume,
+ WRITE_FAT,
+ Volume->FatEntryPos,
+ Volume->FatEntrySize,
+ &Volume->FatEntryBuffer
+ );
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+FatFreeClusters (
+ IN FAT_VOLUME *Volume,
+ IN UINTN Cluster
+ )
+/*++
+
+Routine Description:
+
+ Free the cluster clain.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ Cluster - The first cluster of cluster chain.
+
+Returns:
+
+ EFI_SUCCESS - The cluster chain is freed successfully.
+ EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.
+
+--*/
+{
+ UINTN LastCluster;
+
+ while (!FAT_END_OF_FAT_CHAIN (Cluster)) {
+ if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
+
+ DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ LastCluster = Cluster;
+ Cluster = FatGetFatEntry (Volume, Cluster);
+ FatSetFatEntry (Volume, LastCluster, FAT_CLUSTER_FREE);
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+UINTN
+FatAllocateCluster (
+ IN FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Allocate a free cluster and return the cluster index.
+
+Arguments:
+
+ Volume - FAT file system volume.
+
+Returns:
+
+ The index of the free cluster
+
+--*/
+{
+ UINTN Cluster;
+
+ //
+ // Start looking at FatFreePos for the next unallocated cluster
+ //
+ if (Volume->DiskError) {
+ return (UINTN) FAT_CLUSTER_LAST;
+ }
+
+ for (;;) {
+ //
+ // If the end of the list, return no available cluster
+ //
+ if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {
+ if (Volume->FreeInfoValid && 0 < (INT32) (Volume->FatInfoSector.FreeInfo.ClusterCount)) {
+ Volume->FreeInfoValid = FALSE;
+ }
+
+ FatComputeFreeInfo (Volume);
+ if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {
+ return (UINTN) FAT_CLUSTER_LAST;
+ }
+ }
+
+ Cluster = FatGetFatEntry (Volume, Volume->FatInfoSector.FreeInfo.NextCluster);
+ if (Cluster == FAT_CLUSTER_FREE) {
+ break;
+ }
+ //
+ // Try the next cluster
+ //
+ Volume->FatInfoSector.FreeInfo.NextCluster += 1;
+ }
+
+ Cluster = Volume->FatInfoSector.FreeInfo.NextCluster;
+ Volume->FatInfoSector.FreeInfo.NextCluster += 1;
+ return Cluster;
+}
+
+STATIC
+UINTN
+FatSizeToClusters (
+ IN FAT_VOLUME *Volume,
+ IN UINTN Size
+ )
+/*++
+
+Routine Description:
+
+ Count the number of clusters given a size
+
+Arguments:
+
+ Volume - The file system volume.
+ Size - The size in bytes.
+
+Returns:
+
+ The number of the clusters.
+
+--*/
+{
+ UINTN Clusters;
+
+ Clusters = Size >> Volume->ClusterAlignment;
+ if ((Size & (Volume->ClusterSize - 1)) > 0) {
+ Clusters += 1;
+ }
+
+ return Clusters;
+}
+
+EFI_STATUS
+FatShrinkEof (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Shrink the end of the open file base on the file size.
+
+Arguments:
+
+ OFile - The open file.
+
+Returns:
+
+ EFI_SUCCESS - Shrinked sucessfully.
+ EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.
+
+--*/
+{
+ FAT_VOLUME *Volume;
+ UINTN NewSize;
+ UINTN CurSize;
+ UINTN Cluster;
+ UINTN LastCluster;
+
+ Volume = OFile->Volume;
+ ASSERT_VOLUME_LOCKED (Volume);
+
+ NewSize = FatSizeToClusters (Volume, OFile->FileSize);
+
+ //
+ // Find the address of the last cluster
+ //
+ Cluster = OFile->FileCluster;
+ LastCluster = FAT_CLUSTER_FREE;
+
+ if (NewSize != 0) {
+
+ for (CurSize = 0; CurSize < NewSize; CurSize++) {
+ if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
+
+ DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ LastCluster = Cluster;
+ Cluster = FatGetFatEntry (Volume, Cluster);
+ }
+
+ FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);
+
+ } else {
+ //
+ // Check to see if the file is already completely truncated
+ //
+ if (Cluster == FAT_CLUSTER_FREE) {
+ return EFI_SUCCESS;
+ }
+ //
+ // The file is being completely truncated.
+ //
+ OFile->FileCluster = FAT_CLUSTER_FREE;
+ }
+ //
+ // Set CurrentCluster == FileCluster
+ // to force a recalculation of Position related stuffs
+ //
+ OFile->FileCurrentCluster = OFile->FileCluster;
+ OFile->FileLastCluster = LastCluster;
+ OFile->Dirty = TRUE;
+ //
+ // Free the remaining cluster chain
+ //
+ return FatFreeClusters (Volume, Cluster);
+}
+
+EFI_STATUS
+FatGrowEof (
+ IN FAT_OFILE *OFile,
+ IN UINT64 NewSizeInBytes
+ )
+/*++
+
+Routine Description:
+
+ Grow the end of the open file base on the NewSizeInBytes.
+
+Arguments:
+
+ OFile - The open file.
+ NewSizeInBytes - The new size in bytes of the open file.
+
+Returns:
+
+ EFI_SUCCESS - The file is grown sucessfully.
+ EFI_UNSUPPORTED - The file size is larger than 4GB.
+ EFI_VOLUME_CORRUPTED - There are errors in the files' clusters.
+ EFI_VOLUME_FULL - The volume is full and can not grow the file.
+
+--*/
+{
+ FAT_VOLUME *Volume;
+ EFI_STATUS Status;
+ UINTN Cluster;
+ UINTN CurSize;
+ UINTN NewSize;
+ UINTN LastCluster;
+ UINTN NewCluster;
+ UINTN ClusterCount;
+
+ //
+ // For FAT file system, the max file is 4GB.
+ //
+ if (NewSizeInBytes > 0x0FFFFFFFFL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Volume = OFile->Volume;
+ ASSERT_VOLUME_LOCKED (Volume);
+ //
+ // If the file is already large enough, do nothing
+ //
+ CurSize = FatSizeToClusters (Volume, OFile->FileSize);
+ NewSize = FatSizeToClusters (Volume, (UINTN) NewSizeInBytes);
+
+ if (CurSize < NewSize) {
+ //
+ // If we haven't found the files last cluster do it now
+ //
+ if ((OFile->FileCluster != 0) && (OFile->FileLastCluster == 0)) {
+ Cluster = OFile->FileCluster;
+ ClusterCount = 0;
+
+ while (!FAT_END_OF_FAT_CHAIN (Cluster)) {
+ if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
+
+ DEBUG (
+ (EFI_D_INIT | EFI_D_ERROR,
+ "FatGrowEof: cluster chain corrupt\n")
+ );
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Done;
+ }
+
+ ClusterCount++;
+ OFile->FileLastCluster = Cluster;
+ Cluster = FatGetFatEntry (Volume, Cluster);
+ }
+
+ if (ClusterCount != CurSize) {
+ DEBUG (
+ (EFI_D_INIT | EFI_D_ERROR,
+ "FatGrowEof: cluster chain size does not match file size\n")
+ );
+ Status = EFI_VOLUME_CORRUPTED;
+ goto Done;
+ }
+
+ }
+ //
+ // Loop until we've allocated enough space
+ //
+ LastCluster = OFile->FileLastCluster;
+
+ while (CurSize < NewSize) {
+ NewCluster = FatAllocateCluster (Volume);
+ if (FAT_END_OF_FAT_CHAIN (NewCluster)) {
+ if (LastCluster != FAT_CLUSTER_FREE) {
+ FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);
+ OFile->FileLastCluster = LastCluster;
+ }
+
+ Status = EFI_VOLUME_FULL;
+ goto Done;
+ }
+
+ if (LastCluster != 0) {
+ FatSetFatEntry (Volume, LastCluster, NewCluster);
+ } else {
+ OFile->FileCluster = NewCluster;
+ OFile->FileCurrentCluster = NewCluster;
+ }
+
+ LastCluster = NewCluster;
+ CurSize += 1;
+ }
+ //
+ // Terminate the cluster list
+ //
+ FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);
+ OFile->FileLastCluster = LastCluster;
+ }
+
+ OFile->FileSize = (UINTN) NewSizeInBytes;
+ OFile->Dirty = TRUE;
+ return EFI_SUCCESS;
+
+Done:
+ FatShrinkEof (OFile);
+ return Status;
+}
+
+EFI_STATUS
+FatOFilePosition (
+ IN FAT_OFILE *OFile,
+ IN UINTN Position,
+ IN UINTN PosLimit
+ )
+/*++
+
+Routine Description:
+
+ Seek OFile to requested position, and calculate the number of
+ consecutive clusters from the position in the file
+
+Arguments:
+
+ OFile - The open file.
+ Position - The file's position which will be accessed.
+ PosLimit - The maximum length current reading/writing may access
+
+Returns:
+
+ EFI_SUCCESS - Set the info successfully.
+ EFI_VOLUME_CORRUPTED - Cluster chain corrupt.
+
+--*/
+{
+ FAT_VOLUME *Volume;
+ UINTN ClusterSize;
+ UINTN Cluster;
+ UINTN StartPos;
+ UINTN Run;
+
+ Volume = OFile->Volume;
+ ClusterSize = Volume->ClusterSize;
+
+ ASSERT_VOLUME_LOCKED (Volume);
+
+ //
+ // If this is the fixed root dir, then compute it's position
+ // from it's fixed info in the fat bpb
+ //
+ if (OFile->IsFixedRootDir) {
+ OFile->PosDisk = Volume->RootPos + Position;
+ Run = OFile->FileSize - Position;
+ } else {
+ //
+ // Run the file's cluster chain to find the current position
+ // If possible, run from the current cluster rather than
+ // start from beginning
+ // Assumption: OFile->Position is always consistent with
+ // OFile->FileCurrentCluster.
+ // OFile->Position is not modified outside this function;
+ // OFile->FileCurrentCluster is modified outside this function
+ // to be the same as OFile->FileCluster
+ // when OFile->FileCluster is updated, so make a check of this
+ // and invalidate the original OFile->Position in this case
+ //
+ Cluster = OFile->FileCurrentCluster;
+ StartPos = OFile->Position;
+ if (Position < StartPos || OFile->FileCluster == Cluster) {
+ StartPos = 0;
+ Cluster = OFile->FileCluster;
+ }
+
+ while (StartPos + ClusterSize <= Position) {
+ StartPos += ClusterSize;
+ if (Cluster == FAT_CLUSTER_FREE || (Cluster >= FAT_CLUSTER_SPECIAL)) {
+ DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatOFilePosition:"" cluster chain corrupt\n"));
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ Cluster = FatGetFatEntry (Volume, Cluster);
+ }
+
+ if (Cluster < FAT_MIN_CLUSTER) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ OFile->PosDisk = Volume->FirstClusterPos +
+ LShiftU64 (Cluster - FAT_MIN_CLUSTER, Volume->ClusterAlignment) +
+ Position - StartPos;
+ OFile->FileCurrentCluster = Cluster;
+ OFile->Position = StartPos;
+
+ //
+ // Compute the number of consecutive clusters in the file
+ //
+ Run = StartPos + ClusterSize - Position;
+ if (!FAT_END_OF_FAT_CHAIN (Cluster)) {
+ while ((FatGetFatEntry (Volume, Cluster) == Cluster + 1) && Run < PosLimit) {
+ Run += ClusterSize;
+ Cluster += 1;
+ }
+ }
+ }
+
+ OFile->PosRem = Run;
+ return EFI_SUCCESS;
+}
+
+UINTN
+FatPhysicalDirSize (
+ IN FAT_VOLUME *Volume,
+ IN UINTN Cluster
+ )
+/*++
+
+Routine Description:
+
+ Get the size of directory of the open file
+
+Arguments:
+
+ Volume - The File System Volume.
+ Cluster - The Starting cluster.
+
+Returns:
+
+ The physical size of the file starting at the input cluster, if there is error in the
+ cluster chain, the return value is 0.
+
+--*/
+{
+ UINTN Size;
+ ASSERT_VOLUME_LOCKED (Volume);
+ //
+ // Run the cluster chain for the OFile
+ //
+ Size = 0;
+ //
+ // N.B. ".." directories on some media do not contain a starting
+ // cluster. In the case of "." or ".." we don't need the size anyway.
+ //
+ if (Cluster != 0) {
+ while (!FAT_END_OF_FAT_CHAIN (Cluster)) {
+ if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
+ DEBUG (
+ (EFI_D_INIT | EFI_D_ERROR,
+ "FATDirSize: cluster chain corrupt\n")
+ );
+ return 0;
+ }
+
+ Size += Volume->ClusterSize;
+ Cluster = FatGetFatEntry (Volume, Cluster);
+ }
+ }
+
+ return Size;
+}
+
+UINT64
+FatPhysicalFileSize (
+ IN FAT_VOLUME *Volume,
+ IN UINTN RealSize
+ )
+/*++
+
+Routine Description:
+
+ Get the physical size of a file on the disk.
+
+Arguments:
+
+ Volume - The file system volume.
+ RealSize - The real size of a file.
+
+Returns:
+
+ The physical size of a file on the disk.
+
+--*/
+{
+ UINTN ClusterSizeMask;
+ UINT64 PhysicalSize;
+ ClusterSizeMask = Volume->ClusterSize - 1;
+ PhysicalSize = (RealSize + ClusterSizeMask) & (~((UINT64) ClusterSizeMask));
+ return PhysicalSize;
+}
+
+VOID
+FatComputeFreeInfo (
+ IN FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Update the free cluster info of FatInfoSector of the volume.
+
+Arguments:
+
+ Volume - FAT file system volume.
+
+Returns:
+
+ None.
+
+--*/
+{
+ UINTN Index;
+
+ //
+ // If we don't have valid info, compute it now
+ //
+ if (!Volume->FreeInfoValid) {
+
+ Volume->FreeInfoValid = TRUE;
+ Volume->FatInfoSector.FreeInfo.ClusterCount = 0;
+ for (Index = Volume->MaxCluster + 1; Index >= FAT_MIN_CLUSTER; Index--) {
+ if (Volume->DiskError) {
+ break;
+ }
+
+ if (FatGetFatEntry (Volume, Index) == FAT_CLUSTER_FREE) {
+ Volume->FatInfoSector.FreeInfo.ClusterCount += 1;
+ Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;
+ }
+ }
+
+ Volume->FatInfoSector.Signature = FAT_INFO_SIGNATURE;
+ Volume->FatInfoSector.InfoBeginSignature = FAT_INFO_BEGIN_SIGNATURE;
+ Volume->FatInfoSector.InfoEndSignature = FAT_INFO_END_SIGNATURE;
+ }
+}
diff --git a/FatPkg/EnhancedFatDxe/Flush.c b/FatPkg/EnhancedFatDxe/Flush.c
new file mode 100644
index 0000000000..e058fa4cf8
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Flush.c
@@ -0,0 +1,480 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ flush.c
+
+Abstract:
+
+ Routines that check references and flush OFiles
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatFlush (
+ IN EFI_FILE *FHand
+ )
+/*++
+
+Routine Description:
+
+ Flushes all data associated with the file handle.
+
+Arguments:
+
+ FHand - Handle to file to flush.
+
+Returns:
+
+ EFI_SUCCESS - Flushed the file successfully.
+ EFI_WRITE_PROTECTED - The volume is read only.
+ EFI_ACCESS_DENIED - The file is read only.
+ Others - Flushing of the file failed.
+
+--*/
+{
+ FAT_IFILE *IFile;
+ FAT_OFILE *OFile;
+ FAT_VOLUME *Volume;
+ EFI_STATUS Status;
+
+ IFile = IFILE_FROM_FHAND (FHand);
+ OFile = IFile->OFile;
+ Volume = OFile->Volume;
+
+ //
+ // If the file has a permanent error, return it
+ //
+ if (EFI_ERROR (OFile->Error)) {
+ return OFile->Error;
+ }
+
+ if (Volume->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+ //
+ // If read only, return error
+ //
+ if (IFile->ReadOnly) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Flush the OFile
+ //
+ FatAcquireLock ();
+ Status = FatOFileFlush (OFile);
+ Status = FatCleanupVolume (OFile->Volume, OFile, Status);
+ FatReleaseLock ();
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatClose (
+ IN EFI_FILE *FHand
+ )
+/*++
+
+Routine Description:
+
+ Flushes & Closes the file handle.
+
+Arguments:
+
+ FHand - Handle to the file to delete.
+
+Returns:
+
+ EFI_SUCCESS - Closed the file successfully.
+
+--*/
+{
+ FAT_IFILE *IFile;
+ FAT_OFILE *OFile;
+ FAT_VOLUME *Volume;
+
+ IFile = IFILE_FROM_FHAND (FHand);
+ OFile = IFile->OFile;
+ Volume = OFile->Volume;
+
+ //
+ // Lock the volume
+ //
+ FatAcquireLock ();
+
+ //
+ // Close the file instance handle
+ //
+ FatIFileClose (IFile);
+
+ //
+ // Done. Unlock the volume
+ //
+ FatCleanupVolume (Volume, OFile, EFI_SUCCESS);
+ FatReleaseLock ();
+
+ //
+ // Close always succeed
+ //
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatIFileClose (
+ FAT_IFILE *IFile
+ )
+/*++
+
+Routine Description:
+
+ Close the open file instance.
+
+Arguments:
+
+ IFile - Open file instance.
+
+Returns:
+
+ EFI_SUCCESS - Closed the file successfully.
+
+--*/
+{
+ FAT_OFILE *OFile;
+ FAT_VOLUME *Volume;
+
+ OFile = IFile->OFile;
+ Volume = OFile->Volume;
+
+ ASSERT_VOLUME_LOCKED (Volume);
+
+ //
+ // Remove the IFile struct
+ //
+ RemoveEntryList (&IFile->Link);
+
+ //
+ // Add the OFile to the check reference list
+ //
+ if (OFile->CheckLink.ForwardLink == NULL) {
+ InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);
+ }
+ //
+ // Done. Free the open instance structure
+ //
+ FreePool (IFile);
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatOFileFlush (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Flush the data associated with an open file.
+ In this implementation, only last Mod/Access time is updated.
+
+Arguments:
+
+ OFile - The open file.
+
+Returns:
+
+ EFI_SUCCESS - The OFile is flushed successfully.
+ Others - An error occurred when flushing this OFile.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_OFILE *Parent;
+ FAT_DIRENT *DirEnt;
+ FAT_DATE_TIME FatNow;
+
+ //
+ // Flush each entry up the tree while dirty
+ //
+ do {
+ //
+ // If the file has a permanant error, then don't write any
+ // of its data to the device (may be from different media)
+ //
+ if (EFI_ERROR (OFile->Error)) {
+ return OFile->Error;
+ }
+
+ Parent = OFile->Parent;
+ DirEnt = OFile->DirEnt;
+ if (OFile->Dirty) {
+ //
+ // Update the last modification time
+ //
+ FatGetCurrentFatTime (&FatNow);
+ CopyMem (&DirEnt->Entry.FileLastAccess, &FatNow.Date, sizeof (FAT_DATE));
+ if (!OFile->PreserveLastModification) {
+ FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime);
+ }
+
+ OFile->PreserveLastModification = FALSE;
+ if (OFile->Archive) {
+ DirEnt->Entry.Attributes |= FAT_ATTRIBUTE_ARCHIVE;
+ OFile->Archive = FALSE;
+ }
+ //
+ // Write the directory entry
+ //
+ if (Parent != NULL && !DirEnt->Invalid) {
+ //
+ // Write the OFile's directory entry
+ //
+ Status = FatStoreDirEnt (Parent, DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ OFile->Dirty = FALSE;
+ }
+ //
+ // Check the parent
+ //
+ OFile = Parent;
+ } while (OFile != NULL);
+ return EFI_SUCCESS;
+}
+
+BOOLEAN
+FatCheckOFileRef (
+ IN FAT_OFILE *OFile
+ )
+/*++
+
+Routine Description:
+
+ Check the references of the OFile.
+ If the OFile (that is checked) is no longer
+ referenced, then it is freed.
+
+Arguments:
+
+ OFile - The OFile to be checked.
+
+Returns:
+
+ TRUE - The OFile is not referenced and freed.
+ FALSE - The OFile is kept.
+
+--*/
+{
+ //
+ // If the OFile is on the check ref list, remove it
+ //
+ if (OFile->CheckLink.ForwardLink != NULL) {
+ RemoveEntryList (&OFile->CheckLink);
+ OFile->CheckLink.ForwardLink = NULL;
+ }
+
+ FatOFileFlush (OFile);
+ //
+ // Are there any references to this OFile?
+ //
+ if (!IsListEmpty (&OFile->Opens) || !IsListEmpty (&OFile->ChildHead)) {
+ //
+ // The OFile cannot be freed
+ //
+ return FALSE;
+ }
+ //
+ // Free the Ofile
+ //
+ FatCloseDirEnt (OFile->DirEnt);
+ return TRUE;
+}
+
+STATIC
+VOID
+FatCheckVolumeRef (
+ IN FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Check the references of all open files on the volume.
+ Any open file (that is checked) that is no longer
+ referenced, is freed - and it's parent open file
+ is then referenced checked.
+
+Arguments:
+
+ Volume - The volume to check the pending open file list.
+
+Returns:
+
+ None
+
+--*/
+{
+ FAT_OFILE *OFile;
+ FAT_OFILE *Parent;
+
+ //
+ // Check all files on the pending check list
+ //
+ while (!IsListEmpty (&Volume->CheckRef)) {
+ //
+ // Start with the first file listed
+ //
+ Parent = OFILE_FROM_CHECKLINK (Volume->CheckRef.ForwardLink);
+ //
+ // Go up the tree cleaning up any un-referenced OFiles
+ //
+ while (Parent != NULL) {
+ OFile = Parent;
+ Parent = OFile->Parent;
+ if (!FatCheckOFileRef (OFile)) {
+ break;
+ }
+ }
+ }
+}
+
+EFI_STATUS
+FatCleanupVolume (
+ IN FAT_VOLUME *Volume,
+ IN FAT_OFILE *OFile,
+ IN EFI_STATUS EfiStatus
+ )
+/*++
+
+Routine Description:
+
+ Set error status for a specific OFile, reference checking the volume.
+ If volume is already marked as invalid, and all resources are freed
+ after reference checking, the file system protocol is uninstalled and
+ the volume structure is freed.
+
+Arguments:
+
+ Volume - the Volume that is to be reference checked and unlocked.
+ OFile - the OFile whose permanent error code is to be set.
+ EfiStatus - error code to be set.
+
+Returns:
+
+ EFI_SUCCESS - Clean up the volume successfully.
+ Others - Cleaning up of the volume is failed.
+
+--*/
+{
+ EFI_STATUS Status;
+ //
+ // Flag the OFile
+ //
+ if (OFile != NULL) {
+ FatSetVolumeError (OFile, EfiStatus);
+ }
+ //
+ // Clean up any dangling OFiles that don't have IFiles
+ // we don't check return status here because we want the
+ // volume be cleaned up even the volume is invalid.
+ //
+ FatCheckVolumeRef (Volume);
+ if (Volume->Valid) {
+ //
+ // Update the free hint info. Volume->FreeInfoPos != 0
+ // indicates this a FAT32 volume
+ //
+ if (Volume->FreeInfoValid && Volume->FatDirty && Volume->FreeInfoPos) {
+ Status = FatDiskIo (Volume, WRITE_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // Update that the volume is not dirty
+ //
+ if (Volume->FatDirty && Volume->FatType != FAT12) {
+ Volume->FatDirty = FALSE;
+ Status = FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->NotDirtyValue);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // Flush all dirty cache entries to disk
+ //
+ Status = FatVolumeFlushCache (Volume);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // If the volume is cleared , remove it.
+ // The only time volume be invalidated is in DriverBindingStop.
+ //
+ if (Volume->Root == NULL && !Volume->Valid) {
+ //
+ // Free the volume structure
+ //
+ FatFreeVolume (Volume);
+ }
+
+ return EfiStatus;
+}
+
+VOID
+FatSetVolumeError (
+ IN FAT_OFILE *OFile,
+ IN EFI_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Set the OFile and its child OFile with the error Status
+
+Arguments:
+
+ OFile - The OFile whose permanent error code is to be set.
+ Status - Error code to be set.
+
+Returns:
+
+ None
+
+--*/
+{
+ LIST_ENTRY *Link;
+ FAT_OFILE *ChildOFile;
+
+ //
+ // If this OFile doesn't already have an error, set one
+ //
+ if (!EFI_ERROR (OFile->Error)) {
+ OFile->Error = Status;
+ }
+ //
+ // Set the error on each child OFile
+ //
+ for (Link = OFile->ChildHead.ForwardLink; Link != &OFile->ChildHead; Link = Link->ForwardLink) {
+ ChildOFile = OFILE_FROM_CHILDLINK (Link);
+ FatSetVolumeError (ChildOFile, Status);
+ }
+}
diff --git a/FatPkg/EnhancedFatDxe/Hash.c b/FatPkg/EnhancedFatDxe/Hash.c
new file mode 100644
index 0000000000..c0fbab2f1e
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Hash.c
@@ -0,0 +1,217 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Hash.c
+
+Abstract:
+
+ Hash table operations
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+STATIC
+UINT32
+FatHashLongName (
+ IN CHAR16 *LongNameString
+ )
+/*++
+
+Routine Description:
+
+ Get hash value for long name.
+
+Arguments:
+
+ LongNameString - The long name string to be hashed.
+
+Returns:
+
+ HashValue.
+
+--*/
+{
+ UINT32 HashValue;
+ CHAR16 UpCasedLongFileName[EFI_PATH_STRING_LENGTH];
+ StrCpy (UpCasedLongFileName, LongNameString);
+ FatStrUpr (UpCasedLongFileName);
+ gBS->CalculateCrc32 (UpCasedLongFileName, StrSize (UpCasedLongFileName), &HashValue);
+ return (HashValue & HASH_TABLE_MASK);
+}
+
+STATIC
+UINT32
+FatHashShortName (
+ IN CHAR8 *ShortNameString
+ )
+/*++
+
+Routine Description:
+
+ Get hash value for short name.
+
+Arguments:
+
+ ShortNameString - The short name string to be hashed.
+
+Returns:
+
+ HashValue
+
+--*/
+{
+ UINT32 HashValue;
+ gBS->CalculateCrc32 (ShortNameString, FAT_NAME_LEN, &HashValue);
+ return (HashValue & HASH_TABLE_MASK);
+}
+
+FAT_DIRENT **
+FatLongNameHashSearch (
+ IN FAT_ODIR *ODir,
+ IN CHAR16 *LongNameString
+ )
+/*++
+
+Routine Description:
+
+ Search the long name hash table for the directory entry.
+
+Arguments:
+
+ ODir - The directory to be searched.
+ LongNameString - The long name string to search.
+
+Returns:
+
+ The previous long name hash node of the directory entry.
+
+--*/
+{
+ FAT_DIRENT **PreviousHashNode;
+ for (PreviousHashNode = &ODir->LongNameHashTable[FatHashLongName (LongNameString)];
+ *PreviousHashNode != NULL;
+ PreviousHashNode = &(*PreviousHashNode)->LongNameForwardLink
+ ) {
+ if (FatStriCmp (LongNameString, (*PreviousHashNode)->FileString) == 0) {
+ break;
+ }
+ }
+
+ return PreviousHashNode;
+}
+
+FAT_DIRENT **
+FatShortNameHashSearch (
+ IN FAT_ODIR *ODir,
+ IN CHAR8 *ShortNameString
+ )
+/*++
+
+Routine Description:
+
+ Search the short name hash table for the directory entry.
+
+Arguments:
+
+ ODir - The directory to be searched.
+ ShortNameString - The short name string to search.
+
+Returns:
+
+ The previous short name hash node of the directory entry.
+
+--*/
+{
+ FAT_DIRENT **PreviousHashNode;
+ for (PreviousHashNode = &ODir->ShortNameHashTable[FatHashShortName (ShortNameString)];
+ *PreviousHashNode != NULL;
+ PreviousHashNode = &(*PreviousHashNode)->ShortNameForwardLink
+ ) {
+ if (CompareMem (ShortNameString, (*PreviousHashNode)->Entry.FileName, FAT_NAME_LEN) == 0) {
+ break;
+ }
+ }
+
+ return PreviousHashNode;
+}
+
+VOID
+FatInsertToHashTable (
+ IN FAT_ODIR *ODir,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Insert directory entry to hash table.
+
+Arguments:
+
+ ODir - The parent directory.
+ DirEnt - The directory entry node.
+
+Returns:
+
+ None.
+
+--*/
+{
+ FAT_DIRENT **HashTable;
+ UINT32 HashTableIndex;
+
+ //
+ // Insert hash table index for short name
+ //
+ HashTableIndex = FatHashShortName (DirEnt->Entry.FileName);
+ HashTable = ODir->ShortNameHashTable;
+ DirEnt->ShortNameForwardLink = HashTable[HashTableIndex];
+ HashTable[HashTableIndex] = DirEnt;
+ //
+ // Insert hash table index for long name
+ //
+ HashTableIndex = FatHashLongName (DirEnt->FileString);
+ HashTable = ODir->LongNameHashTable;
+ DirEnt->LongNameForwardLink = HashTable[HashTableIndex];
+ HashTable[HashTableIndex] = DirEnt;
+}
+
+VOID
+FatDeleteFromHashTable (
+ IN FAT_ODIR *ODir,
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Delete directory entry from hash table.
+
+Arguments:
+
+ ODir - The parent directory.
+ DirEnt - The directory entry node.
+
+Returns:
+
+ None.
+
+--*/
+{
+ *FatShortNameHashSearch (ODir, DirEnt->Entry.FileName) = DirEnt->ShortNameForwardLink;
+ *FatLongNameHashSearch (ODir, DirEnt->FileString) = DirEnt->LongNameForwardLink;
+}
diff --git a/FatPkg/EnhancedFatDxe/Info.c b/FatPkg/EnhancedFatDxe/Info.c
new file mode 100644
index 0000000000..2ef4e9c809
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Info.c
@@ -0,0 +1,625 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Info.c
+
+Abstract:
+
+ Routines dealing with setting/getting file/volume info
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+FatGetVolumeInfo (
+ IN FAT_VOLUME *Volume,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+EFI_STATUS
+FatSetVolumeInfo (
+ IN FAT_VOLUME *Volume,
+ IN OUT UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+EFI_STATUS
+FatSetOrGetInfo (
+ IN BOOLEAN IsSet,
+ IN EFI_FILE *FHand,
+ IN EFI_GUID *Type,
+ IN OUT UINTN *BufferSize,
+ IN OUT VOID *Buffer
+ );
+
+EFI_STATUS
+FatGetFileInfo (
+ IN FAT_OFILE *OFile,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the open file's info into Buffer.
+
+Arguments:
+
+ OFile - The open file.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing file info.
+
+Returns:
+
+ EFI_SUCCESS - Get the file info successfully.
+ EFI_BUFFER_TOO_SMALL - The buffer is too small.
+
+--*/
+{
+ return FatGetDirEntInfo (OFile->Volume, OFile->DirEnt, BufferSize, Buffer);
+}
+
+EFI_STATUS
+FatGetVolumeInfo (
+ IN FAT_VOLUME *Volume,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the volume's info into Buffer.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing volume info.
+
+Returns:
+
+ EFI_SUCCESS - Get the volume info successfully.
+ EFI_BUFFER_TOO_SMALL - The buffer is too small.
+
+--*/
+{
+ UINTN Size;
+ UINTN NameSize;
+ UINTN ResultSize;
+ CHAR16 Name[FAT_NAME_LEN + 1];
+ EFI_STATUS Status;
+ EFI_FILE_SYSTEM_INFO *Info;
+ UINT8 ClusterAlignment;
+
+ Size = SIZE_OF_EFI_FILE_SYSTEM_INFO;
+ Status = FatGetVolumeEntry (Volume, Name);
+ NameSize = StrSize (Name);
+ ResultSize = Size + NameSize;
+ ClusterAlignment = Volume->ClusterAlignment;
+
+ //
+ // If we don't have valid info, compute it now
+ //
+ FatComputeFreeInfo (Volume);
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*BufferSize >= ResultSize) {
+ Status = EFI_SUCCESS;
+
+ Info = Buffer;
+ ZeroMem (Info, SIZE_OF_EFI_FILE_SYSTEM_INFO);
+
+ Info->Size = ResultSize;
+ Info->ReadOnly = Volume->ReadOnly;
+ Info->BlockSize = (UINT32) Volume->ClusterSize;
+ Info->VolumeSize = LShiftU64 (Volume->MaxCluster, ClusterAlignment);
+ Info->FreeSpace = LShiftU64 (
+ Volume->FatInfoSector.FreeInfo.ClusterCount,
+ ClusterAlignment
+ );
+ CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);
+ }
+
+ *BufferSize = ResultSize;
+ return Status;
+}
+
+EFI_STATUS
+FatGetVolumeLabelInfo (
+ IN FAT_VOLUME *Volume,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the volume's label info into Buffer.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing volume's label info.
+
+Returns:
+
+ EFI_SUCCESS - Get the volume's label info successfully.
+ EFI_BUFFER_TOO_SMALL - The buffer is too small.
+
+--*/
+{
+ UINTN Size;
+ UINTN NameSize;
+ UINTN ResultSize;
+ CHAR16 Name[FAT_NAME_LEN + 1];
+ EFI_STATUS Status;
+
+ Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO;
+ Status = FatGetVolumeEntry (Volume, Name);
+ NameSize = StrSize (Name);
+ ResultSize = Size + NameSize;
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*BufferSize >= ResultSize) {
+ Status = EFI_SUCCESS;
+ CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);
+ }
+
+ *BufferSize = ResultSize;
+ return Status;
+}
+
+EFI_STATUS
+FatSetVolumeInfo (
+ IN FAT_VOLUME *Volume,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Set the volume's info.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing the new volume info.
+
+Returns:
+
+ EFI_SUCCESS - Set the volume info successfully.
+ EFI_BAD_BUFFER_SIZE - The buffer size is error.
+ EFI_WRITE_PROTECTED - The volume is read only.
+ other - An error occurred when operation the disk.
+
+--*/
+{
+ EFI_FILE_SYSTEM_INFO *Info;
+
+ Info = (EFI_FILE_SYSTEM_INFO *) Buffer;
+
+ if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + 2 || Info->Size > BufferSize) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ return FatSetVolumeEntry (Volume, Info->VolumeLabel);
+}
+
+EFI_STATUS
+FatSetVolumeLabelInfo (
+ IN FAT_VOLUME *Volume,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Set the volume's label info
+
+Arguments:
+
+ Volume - FAT file system volume.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing the new volume label info.
+
+Returns:
+
+ EFI_SUCCESS - Set the volume label info successfully.
+ EFI_WRITE_PROTECTED - The disk is write protected.
+ EFI_BAD_BUFFER_SIZE - The buffer size is error.
+ other - An error occurred when operation the disk.
+
+--*/
+{
+ EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *Info;
+
+ Info = (EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *) Buffer;
+
+ if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + 2) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ return FatSetVolumeEntry (Volume, Info->VolumeLabel);
+}
+
+EFI_STATUS
+FatSetFileInfo (
+ IN FAT_VOLUME *Volume,
+ IN FAT_IFILE *IFile,
+ IN FAT_OFILE *OFile,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Set the file info.
+
+Arguments:
+
+ Volume - FAT file system volume.
+ IFile - The instance of the open file.
+ OFile - The open file.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing the new file info.
+
+Returns:
+
+ EFI_SUCCESS - Set the file info successfully.
+ EFI_ACCESS_DENIED - It is the root directory
+ or the directory attribute bit can not change
+ or try to change a directory size
+ or something else.
+ EFI_UNSUPPORTED - The new file size is larger than 4GB.
+ EFI_WRITE_PROTECTED - The disk is write protected.
+ EFI_BAD_BUFFER_SIZE - The buffer size is error.
+ EFI_INVALID_PARAMETER - The time info or attributes info is error.
+ EFI_OUT_OF_RESOURCES - Can not allocate new memory.
+ EFI_VOLUME_CORRUPTED - The volume is corrupted.
+ other - An error occurred when operation the disk.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *NewInfo;
+ FAT_OFILE *DotOFile;
+ FAT_OFILE *Parent;
+ CHAR16 NewFileName[EFI_PATH_STRING_LENGTH];
+ EFI_TIME ZeroTime;
+ FAT_DIRENT *DirEnt;
+ FAT_DIRENT *TempDirEnt;
+ UINT8 NewAttribute;
+ BOOLEAN ReadOnly;
+
+ ZeroMem (&ZeroTime, sizeof (EFI_TIME));
+ Parent = OFile->Parent;
+ DirEnt = OFile->DirEnt;
+ //
+ // If this is the root directory, we can't make any updates
+ //
+ if (Parent == NULL) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Make sure there's a valid input buffer
+ //
+ NewInfo = Buffer;
+ if (BufferSize < SIZE_OF_EFI_FILE_INFO + 2 || NewInfo->Size > BufferSize) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ ReadOnly = (BOOLEAN)(IFile->ReadOnly || (DirEnt->Entry.Attributes & EFI_FILE_READ_ONLY));
+ //
+ // if a zero time is specified, then the original time is preserved
+ //
+ if (CompareMem (&ZeroTime, &NewInfo->CreateTime, sizeof (EFI_TIME)) != 0) {
+ if (!FatIsValidTime (&NewInfo->CreateTime)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!ReadOnly) {
+ FatEfiTimeToFatTime (&NewInfo->CreateTime, &DirEnt->Entry.FileCreateTime);
+ }
+ }
+
+ if (CompareMem (&ZeroTime, &NewInfo->ModificationTime, sizeof (EFI_TIME)) != 0) {
+ if (!FatIsValidTime (&NewInfo->ModificationTime)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!ReadOnly) {
+ FatEfiTimeToFatTime (&NewInfo->ModificationTime, &DirEnt->Entry.FileModificationTime);
+ }
+
+ OFile->PreserveLastModification = TRUE;
+ }
+
+ if (NewInfo->Attribute & (~EFI_FILE_VALID_ATTR)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NewAttribute = (UINT8) NewInfo->Attribute;
+ //
+ // Can not change the directory attribute bit
+ //
+ if ((NewAttribute ^ DirEnt->Entry.Attributes) & EFI_FILE_DIRECTORY) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Set the current attributes even if the IFile->ReadOnly is TRUE
+ //
+ DirEnt->Entry.Attributes = (UINT8) ((DirEnt->Entry.Attributes &~EFI_FILE_VALID_ATTR) | NewAttribute);
+ //
+ // Open the filename and see if it refers to an existing file
+ //
+ Status = FatLocateOFile (&Parent, NewInfo->FileName, DirEnt->Entry.Attributes, NewFileName);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (*NewFileName != 0) {
+ //
+ // File was not found. We do not allow rename of the current directory if
+ // there are open files below the current directory
+ //
+ if (!IsListEmpty (&OFile->ChildHead) || Parent == OFile) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (ReadOnly) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ Status = FatRemoveDirEnt (OFile->Parent, DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Create new dirent
+ //
+ Status = FatCreateDirEnt (Parent, NewFileName, DirEnt->Entry.Attributes, &TempDirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FatCloneDirEnt (TempDirEnt, DirEnt);
+ FatFreeDirEnt (DirEnt);
+ DirEnt = TempDirEnt;
+ DirEnt->OFile = OFile;
+ OFile->DirEnt = DirEnt;
+ OFile->Parent = Parent;
+ RemoveEntryList (&OFile->ChildLink);
+ InsertHeadList (&Parent->ChildHead, &OFile->ChildLink);
+ //
+ // If this is a directory, synchronize its dot directory entry
+ //
+ if (OFile->ODir != NULL) {
+ //
+ // Syncronize its dot entry
+ //
+ FatResetODirCursor (OFile);
+ ASSERT (OFile->Parent != NULL);
+ for (DotOFile = OFile; DotOFile != OFile->Parent->Parent; DotOFile = DotOFile->Parent) {
+ Status = FatGetNextDirEnt (OFile, &DirEnt);
+ if (EFI_ERROR (Status) || DirEnt == NULL || !FatIsDotDirEnt (DirEnt)) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ FatCloneDirEnt (DirEnt, DotOFile->DirEnt);
+ Status = FatStoreDirEnt (OFile, DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ //
+ // If the file is renamed, we should append the ARCHIVE attribute
+ //
+ OFile->Archive = TRUE;
+ } else if (Parent != OFile) {
+ //
+ // filename is to a different filename that already exists
+ //
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // If the file size has changed, apply it
+ //
+ if (NewInfo->FileSize != OFile->FileSize) {
+ if (OFile->ODir != NULL || ReadOnly) {
+ //
+ // If this is a directory or the file is read only, we can't change the file size
+ //
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (NewInfo->FileSize > OFile->FileSize) {
+ Status = FatExpandOFile (OFile, NewInfo->FileSize);
+ } else {
+ Status = FatTruncateOFile (OFile, (UINTN) NewInfo->FileSize);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FatUpdateDirEntClusterSizeInfo (OFile);
+ }
+
+ OFile->Dirty = TRUE;
+ return FatOFileFlush (OFile);
+}
+
+EFI_STATUS
+FatSetOrGetInfo (
+ IN BOOLEAN IsSet,
+ IN EFI_FILE *FHand,
+ IN EFI_GUID *Type,
+ IN OUT UINTN *BufferSize,
+ IN OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Set or Get the some types info of the file into Buffer
+
+Arguments:
+
+ IsSet - TRUE:The access is set, else is get
+ FHand - The handle of file
+ Type - The type of the info
+ BufferSize - Size of Buffer
+ Buffer - Buffer containing volume info
+
+Returns:
+
+ EFI_SUCCESS - Get the info successfully
+ EFI_DEVICE_ERROR - Can not find the OFile for the file
+
+--*/
+{
+ FAT_IFILE *IFile;
+ FAT_OFILE *OFile;
+ FAT_VOLUME *Volume;
+ EFI_STATUS Status;
+
+ IFile = IFILE_FROM_FHAND (FHand);
+ OFile = IFile->OFile;
+ Volume = OFile->Volume;
+
+ Status = OFile->Error;
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ FatAcquireLock ();
+
+ //
+ // Verify the file handle isn't in an error state
+ //
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the proper information based on the request
+ //
+ Status = EFI_UNSUPPORTED;
+ if (IsSet) {
+ if (Volume->ReadOnly) {
+ Status = EFI_WRITE_PROTECTED;
+ } else {
+ if (CompareGuid (Type, &gEfiFileInfoGuid)) {
+ Status = FatSetFileInfo (Volume, IFile, OFile, *BufferSize, Buffer);
+ }
+
+ if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {
+ Status = FatSetVolumeInfo (Volume, *BufferSize, Buffer);
+ }
+
+ if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ Status = FatSetVolumeLabelInfo (Volume, *BufferSize, Buffer);
+ }
+ }
+ } else {
+ if (CompareGuid (Type, &gEfiFileInfoGuid)) {
+ Status = FatGetFileInfo (OFile, BufferSize, Buffer);
+ }
+
+ if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {
+ Status = FatGetVolumeInfo (Volume, BufferSize, Buffer);
+ }
+
+ if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ Status = FatGetVolumeLabelInfo (Volume, BufferSize, Buffer);
+ }
+ }
+ }
+
+ Status = FatCleanupVolume (Volume, NULL, Status);
+
+ FatReleaseLock ();
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatGetInfo (
+ IN EFI_FILE *FHand,
+ IN EFI_GUID *Type,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the some types info of the file into Buffer.
+
+Arguments:
+
+ FHand - The handle of file.
+ Type - The type of the info.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing volume info.
+
+Returns:
+
+ EFI_SUCCESS - Get the info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+
+--*/
+{
+ return FatSetOrGetInfo (FALSE, FHand, Type, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+FatSetInfo (
+ IN EFI_FILE *FHand,
+ IN EFI_GUID *Type,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Set the some types info of the file into Buffer.
+
+Arguments:
+
+ FHand - The handle of file.
+ Type - The type of the info.
+ BufferSize - Size of Buffer
+ Buffer - Buffer containing volume info.
+
+Returns:
+
+ EFI_SUCCESS - Set the info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+
+--*/
+{
+ return FatSetOrGetInfo (TRUE, FHand, Type, &BufferSize, Buffer);
+}
diff --git a/FatPkg/EnhancedFatDxe/Init.c b/FatPkg/EnhancedFatDxe/Init.c
new file mode 100644
index 0000000000..a532b56b29
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Init.c
@@ -0,0 +1,431 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Init.c
+
+Abstract:
+
+ Initialization routines
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+FatAllocateVolume (
+ IN EFI_HANDLE Handle,
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo
+ )
+/*++
+
+Routine Description:
+
+ Allocates volume structure, detects FAT file system, installs protocol,
+ and initialize cache.
+
+Arguments:
+
+ Handle - The handle of parent device.
+ DiskIo - The DiskIo of parent device.
+ BlockIo - The BlockIo of parent devicel
+
+Returns:
+
+ EFI_SUCCESS - Allocate a new volume successfully.
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory.
+ Others - Allocating a new volume failed.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_VOLUME *Volume;
+ BOOLEAN LockedByMe;
+ LockedByMe = FALSE;
+ //
+ // Allocate a volume structure
+ //
+ Volume = AllocateZeroPool (sizeof (FAT_VOLUME));
+ if (Volume == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Acquire the lock.
+ // If caller has already acquired the lock, cannot lock it again.
+ //
+ if (!FatIsLocked ()) {
+ FatAcquireLock ();
+ LockedByMe = TRUE;
+ }
+ //
+ // Initialize the structure
+ //
+ Volume->Signature = FAT_VOLUME_SIGNATURE;
+ Volume->Handle = Handle;
+ Volume->DiskIo = DiskIo;
+ Volume->BlockIo = BlockIo;
+ Volume->MediaId = BlockIo->Media->MediaId;
+ Volume->ReadOnly = BlockIo->Media->ReadOnly;
+ Volume->VolumeInterface.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
+ Volume->VolumeInterface.OpenVolume = FatOpenVolume;
+ InitializeListHead (&Volume->CheckRef);
+ InitializeListHead (&Volume->DirCacheList);
+ //
+ // Initialize Root Directory entry
+ //
+ Volume->RootDirEnt.FileString = Volume->RootFileString;
+ Volume->RootDirEnt.Entry.Attributes = FAT_ATTRIBUTE_DIRECTORY;
+ //
+ // Check to see if there's a file system on the volume
+ //
+ Status = FatOpenDevice (Volume);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Initialize cache
+ //
+ Status = FatInitializeDiskCache (Volume);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Install our protocol interfaces on the device's handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Volume->Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ &Volume->VolumeInterface,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Volume installed
+ //
+ DEBUG ((EFI_D_INIT, "%HInstalled Fat filesystem on %x%N\n", Handle));
+ Volume->Valid = TRUE;
+
+Done:
+ //
+ // Unlock if locked by myself.
+ //
+ if (LockedByMe) {
+ FatReleaseLock ();
+ }
+
+ if (EFI_ERROR (Status)) {
+ FatFreeVolume (Volume);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+FatAbandonVolume (
+ IN FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Called by FatDriverBindingStop(), Abandon the volume.
+
+Arguments:
+
+ Volume - The volume to be abandoned.
+
+Returns:
+
+ EFI_SUCCESS - Abandoned the volume successfully.
+ Others - Can not uninstall the protocol interfaces.
+
+--*/
+{
+ EFI_STATUS Status;
+ BOOLEAN LockedByMe;
+
+ //
+ // Uninstall the protocol interface.
+ //
+ if (Volume->Handle != NULL) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Volume->Handle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ &Volume->VolumeInterface,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ LockedByMe = FALSE;
+
+ //
+ // Acquire the lock.
+ // If the caller has already acquired the lock (which
+ // means we are in the process of some Fat operation),
+ // we can not acquire again.
+ //
+ if (!FatIsLocked ()) {
+ LockedByMe = TRUE;
+ FatAcquireLock ();
+ }
+ //
+ // The volume is still being used. Hence, set error flag for all OFiles still in
+ // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is
+ // EFI_NO_MEDIA.
+ //
+ if (Volume->Root != NULL) {
+ FatSetVolumeError (
+ Volume->Root,
+ Volume->BlockIo->Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA
+ );
+ }
+
+ Volume->Valid = FALSE;
+
+ //
+ // Release the lock.
+ // If locked by me, this means DriverBindingStop is NOT
+ // called within an on-going Fat operation, so we should
+ // take responsibility to cleanup and free the volume.
+ // Otherwise, the DriverBindingStop is called within an on-going
+ // Fat operation, we shouldn't check reference, so just let outer
+ // FatCleanupVolume do the task.
+ //
+ if (LockedByMe) {
+ FatCleanupVolume (Volume, NULL, EFI_SUCCESS);
+ FatReleaseLock ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatOpenDevice (
+ IN OUT FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Detects FAT file system on Disk and set relevant fields of Volume
+
+Arguments:
+
+ Volume - The volume structure.
+
+Returns:
+
+ EFI_SUCCESS - The Fat File System is detected successfully
+ EFI_UNSUPPORTED - The volume is not FAT file system.
+ EFI_VOLUME_CORRUPTED - The volume is corrupted.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ UINT32 DirtyMask;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ FAT_BOOT_SECTOR FatBs;
+ FAT_VOLUME_TYPE FatType;
+ UINTN RootDirSectors;
+ UINTN FatLba;
+ UINTN RootLba;
+ UINTN FirstClusterLba;
+ UINTN Sectors;
+ UINTN SectorsPerFat;
+ UINT8 SectorsPerClusterAlignment;
+ UINT8 BlockAlignment;
+
+ //
+ // Read the FAT_BOOT_SECTOR BPB info
+ // This is the only part of FAT code that uses parent DiskIo,
+ // Others use FatDiskIo which utilizes a Cache.
+ //
+ DiskIo = Volume->DiskIo;
+ Status = DiskIo->ReadDisk (DiskIo, Volume->MediaId, 0, sizeof (FatBs), &FatBs);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INIT, "FatOpenDevice: read of part_lba failed %r\n", Status));
+ return Status;
+ }
+
+ FatType = FatUndefined;
+
+ //
+ // Use LargeSectors if Sectors is 0
+ //
+ Sectors = FatBs.FatBsb.Sectors;
+ if (Sectors == 0) {
+ Sectors = FatBs.FatBsb.LargeSectors;
+ }
+
+ SectorsPerFat = FatBs.FatBsb.SectorsPerFat;
+ if (SectorsPerFat == 0) {
+ SectorsPerFat = FatBs.FatBse.Fat32Bse.LargeSectorsPerFat;
+ FatType = FAT32;
+ }
+ //
+ // Is boot sector a fat sector?
+ // (Note that so far we only know if the sector is FAT32 or not, we don't
+ // know if the sector is Fat16 or Fat12 until later when we can compute
+ // the volume size)
+ //
+ if (FatBs.FatBsb.ReservedSectors == 0 || FatBs.FatBsb.NumFats == 0 || Sectors == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((FatBs.FatBsb.SectorSize & (FatBs.FatBsb.SectorSize - 1)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ BlockAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorSize);
+ if (BlockAlignment > MAX_BLOCK_ALIGNMENT || BlockAlignment < MIN_BLOCK_ALIGNMENT) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((FatBs.FatBsb.SectorsPerCluster & (FatBs.FatBsb.SectorsPerCluster - 1)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SectorsPerClusterAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorsPerCluster);
+ if (SectorsPerClusterAlignment > MAX_SECTORS_PER_CLUSTER_ALIGNMENT) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (FatBs.FatBsb.Media <= 0xf7 &&
+ FatBs.FatBsb.Media != 0xf0 &&
+ FatBs.FatBsb.Media != 0x00 &&
+ FatBs.FatBsb.Media != 0x01
+ ) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Initialize fields the volume information for this FatType
+ //
+ if (FatType != FAT32) {
+ if (FatBs.FatBsb.RootEntries == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Unpack fat12, fat16 info
+ //
+ Volume->RootEntries = FatBs.FatBsb.RootEntries;
+ } else {
+ //
+ // If this is fat32, refuse to mount mirror-disabled volumes
+ //
+ if ((SectorsPerFat == 0 || FatBs.FatBse.Fat32Bse.FsVersion != 0) || (FatBs.FatBse.Fat32Bse.ExtendedFlags & 0x80)) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Unpack fat32 info
+ //
+ Volume->RootCluster = FatBs.FatBse.Fat32Bse.RootDirFirstCluster;
+ }
+
+ Volume->NumFats = FatBs.FatBsb.NumFats;
+ //
+ // Compute some fat locations
+ //
+ BlockSize = FatBs.FatBsb.SectorSize;
+ RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (BlockSize - 1)) / BlockSize;
+
+ FatLba = FatBs.FatBsb.ReservedSectors;
+ RootLba = FatBs.FatBsb.NumFats * SectorsPerFat + FatLba;
+ FirstClusterLba = RootLba + RootDirSectors;
+
+ Volume->FatPos = FatLba * BlockSize;
+ Volume->FatSize = SectorsPerFat * BlockSize;
+
+ Volume->VolumeSize = LShiftU64 (Sectors, BlockAlignment);
+ Volume->RootPos = LShiftU64 (RootLba, BlockAlignment);
+ Volume->FirstClusterPos = LShiftU64 (FirstClusterLba, BlockAlignment);
+ Volume->MaxCluster = (Sectors - FirstClusterLba) >> SectorsPerClusterAlignment;
+ Volume->ClusterAlignment = (UINT8)(BlockAlignment + SectorsPerClusterAlignment);
+ Volume->ClusterSize = (UINTN)1 << (Volume->ClusterAlignment);
+
+ //
+ // If this is not a fat32, determine if it's a fat16 or fat12
+ //
+ if (FatType != FAT32) {
+ if (Volume->MaxCluster >= FAT_MAX_FAT16_CLUSTER) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ FatType = Volume->MaxCluster < FAT_MAX_FAT12_CLUSTER ? FAT12 : FAT16;
+ //
+ // fat12 & fat16 fat-entries are 2 bytes
+ //
+ Volume->FatEntrySize = sizeof (UINT16);
+ DirtyMask = FAT16_DIRTY_MASK;
+ } else {
+ if (Volume->MaxCluster < FAT_MAX_FAT16_CLUSTER) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+ //
+ // fat32 fat-entries are 4 bytes
+ //
+ Volume->FatEntrySize = sizeof (UINT32);
+ DirtyMask = FAT32_DIRTY_MASK;
+ }
+ //
+ // Get the DirtyValue and NotDirtyValue
+ // We should keep the initial value as the NotDirtyValue
+ // in case the volume is dirty already
+ //
+ if (FatType != FAT12) {
+ Status = FatAccessVolumeDirty (Volume, READ_DISK, &Volume->NotDirtyValue);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Volume->DirtyValue = Volume->NotDirtyValue & DirtyMask;
+ }
+ //
+ // If present, read the fat hint info
+ //
+ if (FatType == FAT32) {
+ Volume->FreeInfoPos = FatBs.FatBse.Fat32Bse.FsInfoSector * BlockSize;
+ if (FatBs.FatBse.Fat32Bse.FsInfoSector != 0) {
+ FatDiskIo (Volume, READ_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector);
+ if (Volume->FatInfoSector.Signature == FAT_INFO_SIGNATURE &&
+ Volume->FatInfoSector.InfoBeginSignature == FAT_INFO_BEGIN_SIGNATURE &&
+ Volume->FatInfoSector.InfoEndSignature == FAT_INFO_END_SIGNATURE &&
+ Volume->FatInfoSector.FreeInfo.ClusterCount <= Volume->MaxCluster
+ ) {
+ Volume->FreeInfoValid = TRUE;
+ }
+ }
+ }
+ //
+ // Just make up a FreeInfo.NextCluster for use by allocate cluster
+ //
+ if (FAT_MIN_CLUSTER > Volume->FatInfoSector.FreeInfo.NextCluster ||
+ Volume->FatInfoSector.FreeInfo.NextCluster > Volume->MaxCluster + 1
+ ) {
+ Volume->FatInfoSector.FreeInfo.NextCluster = FAT_MIN_CLUSTER;
+ }
+ //
+ // We are now defining FAT Type
+ //
+ Volume->FatType = FatType;
+ ASSERT (FatType != FatUndefined);
+
+ return EFI_SUCCESS;
+}
diff --git a/FatPkg/EnhancedFatDxe/Misc.c b/FatPkg/EnhancedFatDxe/Misc.c
new file mode 100644
index 0000000000..a06914fd19
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Misc.c
@@ -0,0 +1,409 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ Misc.c
+
+Abstract:
+
+ Miscellaneous functions
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+FatAccessVolumeDirty (
+ IN FAT_VOLUME *Volume,
+ IN IO_MODE IoMode,
+ IN VOID *DirtyValue
+ )
+/*++
+
+Routine Description:
+
+ Set the volume as dirty or not
+
+Arguments:
+
+ Volume - FAT file system volume.
+ IoMode - The access mode.
+ DirtyValue - Set the volume as dirty or not.
+
+Returns:
+
+ EFI_SUCCESS - Set the new FAT entry value sucessfully.
+ other - An error occurred when operation the FAT entries.
+
+--*/
+{
+ UINTN WriteCount;
+
+ WriteCount = Volume->FatEntrySize;
+ return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue);
+}
+
+EFI_STATUS
+FatDiskIo (
+ IN FAT_VOLUME *Volume,
+ IN IO_MODE IoMode,
+ IN UINT64 Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ General disk access function
+
+Arguments:
+
+ Volume - FAT file system volume.
+ IoMode - The access mode (disk read/write or cache access).
+ Offset - The starting byte offset to read from.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing read data.
+
+Returns:
+
+ EFI_SUCCESS - The operation is performed successfully.
+ EFI_VOLUME_CORRUPTED - The accesss is
+ Others - The status of read/write the disk
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_DISK_READ IoFunction;
+
+ //
+ // Verify the IO is in devices range
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ if (Offset + BufferSize <= Volume->VolumeSize) {
+ if (CACHE_ENABLED (IoMode)) {
+ //
+ // Access cache
+ //
+ Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer);
+ } else {
+ //
+ // Access disk directly
+ //
+ DiskIo = Volume->DiskIo;
+ IoFunction = (IoMode == READ_DISK) ? DiskIo->ReadDisk : DiskIo->WriteDisk;
+ Status = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ Volume->DiskError = TRUE;
+ DEBUG ((EFI_D_INFO, "FatDiskIo: error %r\n", Status));
+ }
+
+ return Status;
+}
+
+VOID
+FatAcquireLock (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Lock the volume.
+
+Arguments:
+
+ None.
+
+Returns:
+
+ None.
+
+--*/
+{
+ EfiAcquireLock (&FatFsLock);
+}
+
+BOOLEAN
+FatIsLocked (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Get the locking status of the volume.
+
+Arguments:
+
+ None.
+
+Returns:
+
+ TRUE - The volume is locked.
+ FALSE - The volume is not locked.
+
+--*/
+{
+ return (BOOLEAN) (FatFsLock.Lock);
+}
+
+VOID
+FatReleaseLock (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Unlock the volume.
+
+Arguments:
+
+ Null.
+
+Returns:
+
+ None.
+
+--*/
+{
+ EfiReleaseLock (&FatFsLock);
+}
+
+VOID
+FatFreeDirEnt (
+ IN FAT_DIRENT *DirEnt
+ )
+/*++
+
+Routine Description:
+
+ Free directory entry.
+
+Arguments:
+
+ DirEnt - The directory entry to be freed.
+
+Returns:
+
+ None.
+
+--*/
+{
+ if (DirEnt->FileString != NULL) {
+ FreePool (DirEnt->FileString);
+ }
+
+ FreePool (DirEnt);
+}
+
+VOID
+FatFreeVolume (
+ IN FAT_VOLUME *Volume
+ )
+/*++
+
+Routine Description:
+
+ Free volume structure (including the contents of directory cache and disk cache).
+
+Arguments:
+
+ Volume - The volume structure to be freed.
+
+Returns:
+
+ None.
+
+--*/
+{
+ //
+ // Free disk cache
+ //
+ if (Volume->CacheBuffer != NULL) {
+ FreePool (Volume->CacheBuffer);
+ }
+ //
+ // Free directory cache
+ //
+ FatCleanupODirCache (Volume);
+ FreePool (Volume);
+}
+
+VOID
+FatEfiTimeToFatTime (
+ IN EFI_TIME *ETime,
+ OUT FAT_DATE_TIME *FTime
+ )
+/*++
+
+Routine Description:
+
+ Translate EFI time to FAT time.
+
+Arguments:
+
+ ETime - The time of EFI_TIME.
+ FTime - The time of FAT_DATE_TIME.
+
+Returns:
+
+ None.
+
+--*/
+{
+ //
+ // ignores timezone info in source ETime
+ //
+ if (ETime->Year > 1980) {
+ FTime->Date.Year = (UINT16) (ETime->Year - 1980);
+ }
+
+ if (ETime->Year >= 1980 + FAT_MAX_YEAR_FROM_1980) {
+ FTime->Date.Year = FAT_MAX_YEAR_FROM_1980;
+ }
+
+ FTime->Date.Month = ETime->Month;
+ FTime->Date.Day = ETime->Day;
+ FTime->Time.Hour = ETime->Hour;
+ FTime->Time.Minute = ETime->Minute;
+ FTime->Time.DoubleSecond = (UINT16) (ETime->Second / 2);
+}
+
+VOID
+FatFatTimeToEfiTime (
+ IN FAT_DATE_TIME *FTime,
+ OUT EFI_TIME *ETime
+ )
+/*++
+
+Routine Description:
+
+ Translate Fat time to EFI time.
+
+Arguments:
+
+ FTime - The time of FAT_DATE_TIME.
+ ETime - The time of EFI_TIME.
+
+Returns:
+
+ None.
+
+--*/
+{
+ ETime->Year = (UINT16) (FTime->Date.Year + 1980);
+ ETime->Month = (UINT8) FTime->Date.Month;
+ ETime->Day = (UINT8) FTime->Date.Day;
+ ETime->Hour = (UINT8) FTime->Time.Hour;
+ ETime->Minute = (UINT8) FTime->Time.Minute;
+ ETime->Second = (UINT8) (FTime->Time.DoubleSecond * 2);
+ ETime->Nanosecond = 0;
+ ETime->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ ETime->Daylight = 0;
+}
+
+VOID
+FatGetCurrentFatTime (
+ OUT FAT_DATE_TIME *FatNow
+ )
+/*++
+
+Routine Description:
+
+ Get Current FAT time.
+
+Arguments:
+
+ FatNow - Current FAT time.
+
+Returns:
+
+ None.
+
+--*/
+{
+ EFI_TIME Now;
+ gRT->GetTime (&Now, NULL);
+ FatEfiTimeToFatTime (&Now, FatNow);
+}
+
+BOOLEAN
+FatIsValidTime (
+ IN EFI_TIME *Time
+ )
+/*++
+
+Routine Description:
+
+ Check whether a time is valid.
+
+Arguments:
+
+ Time - The time of EFI_TIME.
+
+Returns:
+
+ TRUE - The time is valid.
+ FALSE - The time is not valid.
+
+--*/
+{
+ static UINT8 MonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ UINTN Day;
+ BOOLEAN ValidTime;
+
+ ValidTime = TRUE;
+
+ //
+ // Check the fields for range problems
+ // Fat can only support from 1980
+ //
+ if (Time->Year < 1980 ||
+ Time->Month < 1 ||
+ Time->Month > 12 ||
+ Time->Day < 1 ||
+ Time->Day > 31 ||
+ Time->Hour > 23 ||
+ Time->Minute > 59 ||
+ Time->Second > 59 ||
+ Time->Nanosecond > 999999999
+ ) {
+
+ ValidTime = FALSE;
+
+ } else {
+ //
+ // Perform a more specific check of the day of the month
+ //
+ Day = MonthDays[Time->Month - 1];
+ if (Time->Month == 2 && IS_LEAP_YEAR (Time->Year)) {
+ Day += 1;
+ //
+ // 1 extra day this month
+ //
+ }
+ if (Time->Day > Day) {
+ ValidTime = FALSE;
+ }
+ }
+
+ return ValidTime;
+}
diff --git a/FatPkg/EnhancedFatDxe/Open.c b/FatPkg/EnhancedFatDxe/Open.c
new file mode 100644
index 0000000000..b6369cf0b3
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/Open.c
@@ -0,0 +1,285 @@
+/*++
+
+Copyright (c) 2005 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ open.c
+
+Abstract:
+
+ Routines dealing with file open
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+FatAllocateIFile (
+ IN FAT_OFILE *OFile,
+ OUT FAT_IFILE **PtrIFile
+ )
+/*++
+
+Routine Description:
+
+ Create an Open instance for the existing OFile.
+ The IFile of the newly opened file is passed out.
+
+Arguments:
+
+ OFile - The file that serves as a starting reference point.
+ PtrIFile - The newly generated IFile instance.
+
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory for the IFile
+ EFI_SUCCESS - Create the new IFile for the OFile successfully
+
+--*/
+{
+ FAT_IFILE *IFile;
+
+ ASSERT_VOLUME_LOCKED (OFile->Volume);
+
+ //
+ // Allocate a new open instance
+ //
+ IFile = AllocateZeroPool (sizeof (FAT_IFILE));
+ if (IFile == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IFile->Signature = FAT_IFILE_SIGNATURE;
+
+ CopyMem (&(IFile->Handle), &FatFileInterface, sizeof (EFI_FILE));
+
+ IFile->OFile = OFile;
+ InsertTailList (&OFile->Opens, &IFile->Link);
+
+ *PtrIFile = IFile;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatOFileOpen (
+ IN FAT_OFILE *OFile,
+ OUT FAT_IFILE **NewIFile,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT8 Attributes
+ )
+/*++
+
+Routine Description:
+
+ Open a file for a file name relative to an existing OFile.
+ The IFile of the newly opened file is passed out.
+
+Arguments:
+
+ OFile - The file that serves as a starting reference point.
+ NewIFile - The newly generated IFile instance.
+ FileName - The file name relative to the OFile.
+ OpenMode - Open mode.
+ Attributes - Attributes to set if the file is created.
+
+Returns:
+
+ EFI_SUCCESS - Open the file successfully.
+ EFI_INVALID_PARAMETER - The open mode is conflict with the attributes
+ or the file name is not valid.
+ EFI_NOT_FOUND - Conficts between dir intention and attribute.
+ EFI_WRITE_PROTECTED - Can't open for write if the volume is read only.
+ EFI_ACCESS_DENIED - If the file's attribute is read only, and the
+ open is for read-write fail it.
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory.
+
+--*/
+{
+ FAT_VOLUME *Volume;
+ EFI_STATUS Status;
+ CHAR16 NewFileName[EFI_PATH_STRING_LENGTH];
+ FAT_DIRENT *DirEnt;
+ UINT8 FileAttributes;
+ BOOLEAN WriteMode;
+
+ Volume = OFile->Volume;
+ ASSERT_VOLUME_LOCKED (Volume);
+ WriteMode = (BOOLEAN) (OpenMode & EFI_FILE_MODE_WRITE);
+ if (Volume->ReadOnly && WriteMode) {
+ return EFI_WRITE_PROTECTED;
+ }
+ //
+ // Verify the source file handle isn't in an error state
+ //
+ Status = OFile->Error;
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get new OFile for the file
+ //
+ Status = FatLocateOFile (&OFile, FileName, Attributes, NewFileName);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (*NewFileName != 0) {
+ //
+ // If there's a remaining part of the name, then we had
+ // better be creating the file in the directory
+ //
+ if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = FatCreateDirEnt (OFile, NewFileName, Attributes, &DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = FatOpenDirEnt (OFile, DirEnt);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OFile = DirEnt->OFile;
+ if (OFile->ODir != NULL) {
+ //
+ // If we just created a directory, we need to create "." and ".."
+ //
+ Status = FatCreateDotDirEnts (OFile);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ //
+ // If the file's attribute is read only, and the open is for
+ // read-write, then the access is denied.
+ //
+ FileAttributes = OFile->DirEnt->Entry.Attributes;
+ if ((FileAttributes & EFI_FILE_READ_ONLY) != 0 && (FileAttributes & FAT_ATTRIBUTE_DIRECTORY) == 0 && WriteMode) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Create an open instance of the OFile
+ //
+ Status = FatAllocateIFile (OFile, NewIFile);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ (*NewIFile)->ReadOnly = (BOOLEAN)!WriteMode;
+
+ DEBUG ((EFI_D_INFO, "FSOpen: Open '%S' %r\n", FileName, Status));
+ return FatOFileFlush (OFile);
+}
+
+EFI_STATUS
+EFIAPI
+FatOpen (
+ IN EFI_FILE *FHand,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+/*++
+Routine Description:
+
+ Implements Open() of Simple File System Protocol.
+
+Arguments:
+
+ FHand - File handle of the file serves as a starting reference point.
+ NewHandle - Handle of the file that is newly opened.
+ FileName - File name relative to FHand.
+ OpenMode - Open mode.
+ Attributes - Attributes to set if the file is created.
+
+Returns:
+
+ EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.
+ The OpenMode is not supported.
+ The Attributes is not the valid attributes.
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string.
+ EFI_SUCCESS - Open the file successfully.
+ Others - The status of open file.
+
+--*/
+{
+ FAT_IFILE *IFile;
+ FAT_IFILE *NewIFile;
+ FAT_OFILE *OFile;
+ EFI_STATUS Status;
+
+ //
+ // Perform some parameter checking
+ //
+ if (FileName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check for a valid mode
+ //
+ switch (OpenMode) {
+ case EFI_FILE_MODE_READ:
+ case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
+ case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check for valid attributes
+ //
+ if (Attributes & (~EFI_FILE_VALID_ATTR)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Can't open for create and apply the read only attribute
+ //
+ if ((OpenMode & EFI_FILE_MODE_CREATE) && (Attributes & EFI_FILE_READ_ONLY)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IFile = IFILE_FROM_FHAND (FHand);
+ OFile = IFile->OFile;
+
+ //
+ // Lock
+ //
+ FatAcquireLock ();
+
+ //
+ // Open the file
+ //
+ Status = FatOFileOpen (OFile, &NewIFile, FileName, OpenMode, (UINT8) Attributes);
+
+ //
+ // If the file was opened, return the handle to the caller
+ //
+ if (!EFI_ERROR (Status)) {
+ *NewHandle = &NewIFile->Handle;
+ }
+ //
+ // Unlock
+ //
+ Status = FatCleanupVolume (OFile->Volume, NULL, Status);
+ FatReleaseLock ();
+
+ return Status;
+}
diff --git a/FatPkg/EnhancedFatDxe/OpenVolume.c b/FatPkg/EnhancedFatDxe/OpenVolume.c
new file mode 100644
index 0000000000..723ee127cd
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/OpenVolume.c
@@ -0,0 +1,80 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ OpenVolume.c
+
+Abstract:
+
+ OpenVolume() function of Simple File System Protocol
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE **File
+ )
+/*++
+
+Routine Description:
+
+ Implements Simple File System Protocol interface function OpenVolume().
+
+Arguments:
+
+ This - Calling context.
+ File - the Root Directory of the volume.
+
+Returns:
+
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory.
+ EFI_VOLUME_CORRUPTED - The FAT type is error.
+ EFI_SUCCESS - Open the volume successfully.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_VOLUME *Volume;
+ FAT_IFILE *IFile;
+
+ Volume = VOLUME_FROM_VOL_INTERFACE (This);
+ FatAcquireLock ();
+
+ //
+ // Open Root file
+ //
+ Status = FatOpenDirEnt (NULL, &Volume->RootDirEnt);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Open a new instance to the root
+ //
+ Status = FatAllocateIFile (Volume->Root, &IFile);
+ if (!EFI_ERROR (Status)) {
+ *File = &IFile->Handle;
+ }
+
+Done:
+
+ Status = FatCleanupVolume (Volume, Volume->Root, Status);
+ FatReleaseLock ();
+
+ return Status;
+}
diff --git a/FatPkg/EnhancedFatDxe/ReadWrite.c b/FatPkg/EnhancedFatDxe/ReadWrite.c
new file mode 100644
index 0000000000..7ccf517bf1
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/ReadWrite.c
@@ -0,0 +1,612 @@
+/*++
+
+Copyright (c) 2005, Intel Corporation
+All rights reserved. This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+
+ ReadWrite.c
+
+Abstract:
+
+ Functions that perform file read/write
+
+Revision History
+
+--*/
+
+#include "Fat.h"
+
+EFI_STATUS
+EFIAPI
+FatGetPosition (
+ IN EFI_FILE *FHand,
+ OUT UINT64 *Position
+ )
+/*++
+
+Routine Description:
+
+ Get the file's position of the file.
+
+Arguments:
+
+ FHand - The handle of file.
+ Position - The file's position of the file.
+
+Returns:
+
+ EFI_SUCCESS - Get the info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+ EFI_UNSUPPORTED - The open file is not a file.
+
+--*/
+{
+ FAT_IFILE *IFile;
+ FAT_OFILE *OFile;
+
+ IFile = IFILE_FROM_FHAND (FHand);
+ OFile = IFile->OFile;
+
+ if (OFile->Error == EFI_NOT_FOUND) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (OFile->ODir != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *Position = IFile->Position;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FatSetPosition (
+ IN EFI_FILE *FHand,
+ IN UINT64 Position
+ )
+/*++
+
+Routine Description:
+
+ Set the file's position of the file.
+
+Arguments:
+
+ FHand - The handle of file.
+ Position - The file's position of the file.
+
+Returns:
+
+ EFI_SUCCESS - Set the info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+ EFI_UNSUPPORTED - Set a directory with a not-zero position.
+
+--*/
+{
+ FAT_IFILE *IFile;
+ FAT_OFILE *OFile;
+
+ IFile = IFILE_FROM_FHAND (FHand);
+ OFile = IFile->OFile;
+
+ if (OFile->Error == EFI_NOT_FOUND) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // If this is a directory, we can only set back to position 0
+ //
+ if (OFile->ODir != NULL) {
+ if (Position != 0) {
+ //
+ // Reset current directory cursor;
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ FatResetODirCursor (OFile);
+ }
+ //
+ // Set the position
+ //
+ if (Position == -1) {
+ Position = OFile->FileSize;
+ }
+ //
+ // Set the position
+ //
+ IFile->Position = Position;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+FatIFileReadDir (
+ IN FAT_IFILE *IFile,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the file info from the open file of the IFile into Buffer.
+
+Arguments:
+
+ IFile - The instance of the open file.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing read data.
+
+Returns:
+
+ EFI_SUCCESS - Get the file info successfully.
+ other - An error occurred when operation the disk.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_OFILE *OFile;
+ FAT_ODIR *ODir;
+ FAT_DIRENT *DirEnt;
+ UINT32 CurrentPos;
+
+ OFile = IFile->OFile;
+ ODir = OFile->ODir;
+ CurrentPos = ((UINT32) IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY);
+
+ //
+ // We need to relocate the directory
+ //
+ if (CurrentPos < ODir->CurrentPos) {
+ //
+ // The directory cursor has been modified by another IFile, we reset the cursor
+ //
+ FatResetODirCursor (OFile);
+ }
+ //
+ // We seek the next directory entry's position
+ //
+ do {
+ Status = FatGetNextDirEnt (OFile, &DirEnt);
+ if (EFI_ERROR (Status) || DirEnt == NULL) {
+ //
+ // Something error occurred or reach the end of directory,
+ // return 0 buffersize
+ //
+ *BufferSize = 0;
+ goto Done;
+ }
+ } while (ODir->CurrentPos <= CurrentPos);
+ Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer);
+
+Done:
+ //
+ // Update IFile's Position
+ //
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update IFile->Position, if everything is all right
+ //
+ CurrentPos = ODir->CurrentPos;
+ IFile->Position = (UINT64) (CurrentPos * sizeof (FAT_DIRECTORY_ENTRY));
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+FatIFileAccess (
+ IN EFI_FILE *FHand,
+ IN IO_MODE IoMode,
+ IN OUT UINTN *BufferSize,
+ IN OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the file info from the open file of the IFile into Buffer.
+
+Arguments:
+
+ FHand - The file handle to access.
+ IoMode - Indicate whether the access mode is reading or writing.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing read data.
+
+Returns:
+
+ EFI_SUCCESS - Get the file info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.
+ EFI_WRITE_PROTECTED - The disk is write protect.
+ EFI_ACCESS_DENIED - The file is read-only.
+ other - An error occurred when operating on the disk.
+
+--*/
+{
+ EFI_STATUS Status;
+ FAT_IFILE *IFile;
+ FAT_OFILE *OFile;
+ FAT_VOLUME *Volume;
+ UINT64 EndPosition;
+
+ IFile = IFILE_FROM_FHAND (FHand);
+ OFile = IFile->OFile;
+ Volume = OFile->Volume;
+
+ if (OFile->Error == EFI_NOT_FOUND) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (IoMode == READ_DATA) {
+ //
+ // If position is at EOF, then return device error
+ //
+ if (IFile->Position > OFile->FileSize) {
+ return EFI_DEVICE_ERROR;
+ }
+ } else {
+ //
+ // Check if the we can write data
+ //
+ if (Volume->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (IFile->ReadOnly) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+
+ FatAcquireLock ();
+
+ Status = OFile->Error;
+ if (!EFI_ERROR (Status)) {
+ if (OFile->ODir != NULL) {
+ //
+ // Access a directory
+ //
+ Status = EFI_UNSUPPORTED;
+ if (IoMode == READ_DATA) {
+ //
+ // Read a directory is supported
+ //
+ Status = FatIFileReadDir (IFile, BufferSize, Buffer);
+ }
+
+ OFile = NULL;
+ } else {
+ //
+ // Access a file
+ //
+ EndPosition = IFile->Position + *BufferSize;
+ if (EndPosition > OFile->FileSize) {
+ //
+ // The position goes beyond the end of file
+ //
+ if (IoMode == READ_DATA) {
+ //
+ // Adjust the actual size read
+ //
+ *BufferSize -= (UINTN) EndPosition - OFile->FileSize;
+ } else {
+ //
+ // We expand the file size of OFile
+ //
+ Status = FatGrowEof (OFile, EndPosition);
+ if (EFI_ERROR (Status)) {
+ //
+ // Must update the file's info into the file's Directory Entry
+ // and then flush the dirty cache info into disk.
+ //
+ *BufferSize = 0;
+ FatOFileFlush (OFile);
+ OFile = NULL;
+ goto Done;
+ }
+
+ FatUpdateDirEntClusterSizeInfo (OFile);
+ }
+ }
+
+ Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer);
+ IFile->Position += *BufferSize;
+ }
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ Status = FatCleanupVolume (Volume, OFile, Status);
+ }
+ //
+ // On EFI_SUCCESS case, not calling FatCleanupVolume():
+ // 1) The Cache flush operation is avoided to enhance
+ // performance. Caller is responsible to call Flush() when necessary.
+ // 2) The volume dirty bit is probably set already, and is expected to be
+ // cleaned in subsequent Flush() or other operations.
+ // 3) Write operation doesn't affect OFile/IFile structure, so
+ // Reference checking is not necessary.
+ //
+ FatReleaseLock ();
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+FatRead (
+ IN EFI_FILE *FHand,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Get the file info.
+
+Arguments:
+
+ FHand - The handle of the file.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing read data.
+
+Returns:
+
+ EFI_SUCCESS - Get the file info successfully.
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.
+ other - An error occurred when operation the disk.
+
+--*/
+{
+ return FatIFileAccess (FHand, READ_DATA, BufferSize, Buffer);
+}
+
+EFI_STATUS
+EFIAPI
+FatWrite (
+ IN EFI_FILE *FHand,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Write the content of buffer into files.
+
+Arguments:
+
+ FHand - The handle of the file.
+ BufferSize - Size of Buffer.
+ Buffer - Buffer containing write data.
+
+Returns:
+
+ EFI_SUCCESS - Set the file info successfully.
+ EFI_WRITE_PROTECTED - The disk is write protect.
+ EFI_ACCESS_DENIED - The file is read-only.
+ EFI_DEVICE_ERROR - The OFile is not valid.
+ EFI_UNSUPPORTED - The open file is not a file.
+ - The writing file size is larger than 4GB.
+ other - An error occurred when operation the disk.
+
+--*/
+{
+ return FatIFileAccess (FHand, WRITE_DATA, BufferSize, Buffer);
+}
+
+EFI_STATUS
+FatAccessOFile (
+ IN FAT_OFILE *OFile,
+ IN IO_MODE IoMode,
+ IN UINTN Position,
+ IN OUT UINTN *DataBufferSize,
+ IN OUT UINT8 *UserBuffer
+ )
+/*++
+
+Routine Description:
+
+ This function reads data from a file or writes data to a file.
+ It uses OFile->PosRem to determine how much data can be accessed in one time.
+
+Arguments:
+
+ OFile - The open file.
+ IoMode - Indicate whether the access mode is reading or writing.
+ Position - The position where data will be accessed.
+ DataBufferSize - Size of Buffer.
+ UserBuffer - Buffer containing data.
+
+Returns:
+
+ EFI_SUCCESS - Access the data successfully.
+ other - An error occurred when operating on the disk.
+
+--*/
+{
+ FAT_VOLUME *Volume;
+ UINTN Len;
+ EFI_STATUS Status;
+ UINTN BufferSize;
+
+ BufferSize = *DataBufferSize;
+ Volume = OFile->Volume;
+ ASSERT_VOLUME_LOCKED (Volume);
+
+ Status = EFI_SUCCESS;
+ while (BufferSize > 0) {
+ //
+ // Seek the OFile to the file position
+ //
+ Status = FatOFilePosition (OFile, Position, BufferSize);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Clip length to block run
+ //
+ Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize;
+
+ //
+ // Write the data
+ //
+ Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Data was successfully accessed
+ //
+ Position += Len;
+ UserBuffer += Len;
+ BufferSize -= Len;
+ if (IoMode == WRITE_DATA) {
+ OFile->Dirty = TRUE;
+ OFile->Archive = TRUE;
+ }
+ //
+ // Make sure no outbound occurred
+ //
+ ASSERT (Position <= OFile->FileSize);
+ }
+ //
+ // Update the number of bytes accessed
+ //
+ *DataBufferSize -= BufferSize;
+ return Status;
+}
+
+EFI_STATUS
+FatExpandOFile (
+ IN FAT_OFILE *OFile,
+ IN UINT64 ExpandedSize
+ )
+/*++
+
+Routine Description:
+
+ Expand OFile by appending zero bytes at the end of OFile.
+
+Arguments:
+
+ OFile - The open file.
+ ExpandedSize - The number of zero bytes appended at the end of the file.
+
+Returns:
+
+ EFI_SUCCESS - The file is expanded successfully.
+ other - An error occurred when expanding file.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINTN WritePos;
+
+ WritePos = OFile->FileSize;
+ Status = FatGrowEof (OFile, ExpandedSize);
+ if (!EFI_ERROR (Status)) {
+ Status = FatWriteZeroPool (OFile, WritePos);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+FatWriteZeroPool (
+ IN FAT_OFILE *OFile,
+ IN UINTN WritePos
+ )
+/*++
+
+Routine Description:
+
+ Write zero pool from the WritePos to the end of OFile.
+
+Arguments:
+
+ OFile - The open file to write zero pool.
+ WritePos - The number of zero bytes written.
+
+Returns:
+
+ EFI_SUCCESS - Write the zero pool successfully.
+ EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation.
+ other - An error occurred when writing disk.
+
+--*/
+{
+ EFI_STATUS Status;
+ VOID *ZeroBuffer;
+ UINTN AppendedSize;
+ UINTN BufferSize;
+ UINTN WriteSize;
+
+ AppendedSize = OFile->FileSize - WritePos;
+ BufferSize = AppendedSize;
+ if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) {
+ //
+ // If the appended size is larger, maybe we can not allocate the whole
+ // memory once. So if the growed size is larger than 10M, we just
+ // allocate 10M memory (one healthy system should have 10M available
+ // memory), and then write the zerobuffer to the file several times.
+ //
+ BufferSize = FAT_MAX_ALLOCATE_SIZE;
+ }
+
+ ZeroBuffer = AllocateZeroPool (BufferSize);
+ if (ZeroBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ do {
+ WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize;
+ AppendedSize -= WriteSize;
+ Status = FatAccessOFile (OFile, WRITE_DATA, WritePos, &WriteSize, ZeroBuffer);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ WritePos += WriteSize;
+ } while (AppendedSize > 0);
+
+ FreePool (ZeroBuffer);
+ return Status;
+}
+
+EFI_STATUS
+FatTruncateOFile (
+ IN FAT_OFILE *OFile,
+ IN UINTN TruncatedSize
+ )
+/*++
+
+Routine Description:
+
+ Truncate the OFile to smaller file size.
+
+Arguments:
+
+ OFile - The open file.
+ TruncatedSize - The new file size.
+
+Returns:
+
+ EFI_SUCCESS - The file is truncated successfully.
+ other - An error occurred when truncating file.
+
+--*/
+{
+ OFile->FileSize = TruncatedSize;
+ return FatShrinkEof (OFile);
+}
diff --git a/FatPkg/EnhancedFatDxe/UnicodeCollation.c b/FatPkg/EnhancedFatDxe/UnicodeCollation.c
new file mode 100644
index 0000000000..d74dc1e697
--- /dev/null
+++ b/FatPkg/EnhancedFatDxe/UnicodeCollation.c
@@ -0,0 +1,324 @@
+/** @file
+ Unicode Collation Library that hides the trival difference of Unicode Collation
+ and Unicode collation 2 Protocol.
+
+ Copyright (c) 2007, Intel Corporation<BR>
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Protocol/UnicodeCollation.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+STATIC EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollationInterface = NULL;
+
+typedef
+BOOLEAN
+(* SEARCH_LANG_CODE) (
+ IN CONST CHAR8 *Languages,
+ IN CONST CHAR8 *MatchLangCode
+ );
+
+struct _UNICODE_INTERFACE {
+ CHAR16 *VariableName;
+ CHAR8 *DefaultLangCode;
+ SEARCH_LANG_CODE SearchLangCode;
+ EFI_GUID *UnicodeProtocolGuid;
+};
+
+typedef struct _UNICODE_INTERFACE UNICODE_INTERFACE;
+
+STATIC
+BOOLEAN
+SearchIso639LangCode (
+ IN CONST CHAR8 *Languages,
+ IN CONST CHAR8 *MatchLangCode
+ )
+{
+ CONST CHAR8 *LangCode;
+
+ for (LangCode = Languages; *LangCode != '\0'; LangCode += 3) {
+ if (CompareMem (LangCode, MatchLangCode, 3) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+STATIC
+BOOLEAN
+SearchRfc3066LangCode (
+ IN CONST CHAR8 *Languages,
+ IN CONST CHAR8 *MatchLangCode
+ )
+{
+ CHAR8 *SubStr;
+ CHAR8 Terminal;
+
+ SubStr = AsciiStrStr (Languages, MatchLangCode);
+ if (SubStr == NULL) {
+ return FALSE;
+ }
+
+ if (SubStr != Languages && *(SubStr - 1) != ';') {
+ return FALSE;
+ }
+
+ Terminal = *(SubStr + AsciiStrLen (MatchLangCode));
+ if (Terminal != '\0' && Terminal != ';') {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED UNICODE_INTERFACE mIso639Lang = {
+ L"Lang",
+ (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultLang),
+ SearchIso639LangCode,
+ &gEfiUnicodeCollationProtocolGuid,
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UNICODE_INTERFACE mRfc3066Lang = {
+ L"PlatformLang",
+ (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang),
+ SearchRfc3066LangCode,
+ &gEfiUnicodeCollation2ProtocolGuid,
+};
+
+STATIC
+EFI_STATUS
+InitializeUnicodeCollationSupportWithConfig (
+ IN EFI_HANDLE AgentHandle,
+ IN UNICODE_INTERFACE *UnicodeInterface
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 Buffer[100];
+ UINTN BufferSize;
+ UINTN Index;
+ CHAR8 *LangCode;
+ UINTN NoHandles;
+ EFI_HANDLE *Handles;
+ EFI_UNICODE_COLLATION_PROTOCOL *Uci;
+
+ LangCode = Buffer;
+ BufferSize = sizeof (Buffer);
+ Status = gRT->GetVariable (
+ UnicodeInterface->VariableName,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ LangCode = UnicodeInterface->DefaultLangCode;
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ UnicodeInterface->UnicodeProtocolGuid,
+ NULL,
+ &NoHandles,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < NoHandles; Index++) {
+ //
+ // Open Unicode Collation Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Handles[Index],
+ UnicodeInterface->UnicodeProtocolGuid,
+ (VOID **) &Uci,
+ AgentHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (UnicodeInterface->SearchLangCode (Uci->SupportedLanguages, LangCode)) {
+ mUnicodeCollationInterface = Uci;
+ break;
+ }
+ }
+
+ FreePool (Handles);
+
+ return (mUnicodeCollationInterface != NULL)? EFI_SUCCESS : EFI_NOT_FOUND;
+}
+
+/**
+ Initialize Unicode Collation support.
+
+ @param AgentHandle The handle used to open Unicode Collation (2) protocol.
+
+ @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.
+ @retval Others The Unicode Collation (2) protocol has not been located.
+
+**/
+EFI_STATUS
+InitializeUnicodeCollationSupport (
+ IN EFI_HANDLE AgentHandle
+ )
+{
+
+ EFI_STATUS Status;
+
+ Status = EFI_UNSUPPORTED;
+ if (FeaturePcdGet (PcdUnicodeCollation2Support)) {
+ Status = InitializeUnicodeCollationSupportWithConfig (AgentHandle, &mRfc3066Lang);
+ }
+
+ if (FeaturePcdGet (PcdUnicodeCollationSupport) && EFI_ERROR (Status)) {
+ Status = InitializeUnicodeCollationSupportWithConfig (AgentHandle, &mIso639Lang);
+ }
+
+ return Status;
+}
+
+/**
+ Performs a case-insensitive comparison of two Null-terminated Unicode strings.
+
+ @param S1 A pointer to a Null-terminated Unicode string.
+ @param S2 A pointer to a Null-terminated Unicode string.
+
+ @retval 0 S1 is equivalent to S2.
+ @retval >0 S1 is lexically greater than S2.
+ @retval <0 S1 is lexically less than S2.
+**/
+INTN
+FatStriCmp (
+ IN CHAR16 *S1,
+ IN CHAR16 *S2
+ )
+{
+ ASSERT (StrSize (S1) != 0);
+ ASSERT (StrSize (S2) != 0);
+ ASSERT (mUnicodeCollationInterface != NULL);
+
+ return mUnicodeCollationInterface->StriColl (
+ mUnicodeCollationInterface,
+ S1,
+ S2
+ );
+}
+
+
+/**
+ Uppercase a string.
+
+ @param Str The string which will be upper-cased.
+
+ @return None.
+
+**/
+VOID
+FatStrUpr (
+ IN OUT CHAR16 *String
+ )
+{
+ ASSERT (StrSize (String) != 0);
+ ASSERT (mUnicodeCollationInterface != NULL);
+
+ mUnicodeCollationInterface->StrUpr (mUnicodeCollationInterface, String);
+}
+
+
+/**
+ Lowercase a string
+
+ @param Str The string which will be lower-cased.
+
+ @return None
+
+**/
+VOID
+FatStrLwr (
+ IN OUT CHAR16 *String
+ )
+{
+ ASSERT (StrSize (String) != 0);
+ ASSERT (mUnicodeCollationInterface != NULL);
+
+ mUnicodeCollationInterface->StrLwr (mUnicodeCollationInterface, String);
+}
+
+
+/**
+ Convert FAT string to unicode string.
+
+ @param FatSize The size of FAT string.
+ @param Fat The FAT string.
+ @param String The unicode string.
+
+ @return None.
+
+**/
+VOID
+FatFatToStr (
+ IN UINTN FatSize,
+ IN CHAR8 *Fat,
+ OUT CHAR16 *String
+ )
+{
+ ASSERT (Fat != NULL);
+ ASSERT (String != NULL);
+ ASSERT (((UINTN) String & 0x01) != 0);
+ ASSERT (mUnicodeCollationInterface != NULL);
+
+ mUnicodeCollationInterface->FatToStr (mUnicodeCollationInterface, FatSize, Fat, String);
+}
+
+
+/**
+ Convert unicode string to Fat string.
+
+ @param String The unicode string.
+ @param FatSize The size of the FAT string.
+ @param Fat The FAT string.
+
+ @retval TRUE Convert successfully.
+ @retval FALSE Convert error.
+
+**/
+BOOLEAN
+FatStrToFat (
+ IN CHAR16 *String,
+ IN UINTN FatSize,
+ OUT CHAR8 *Fat
+ )
+{
+ ASSERT (Fat != NULL);
+ ASSERT (StrSize (String) != 0);
+ ASSERT (mUnicodeCollationInterface != NULL);
+
+ return mUnicodeCollationInterface->StrToFat (
+ mUnicodeCollationInterface,
+ String,
+ FatSize,
+ Fat
+ );
+}
diff --git a/FatPkg/FatPkg.dec b/FatPkg/FatPkg.dec
new file mode 100644
index 0000000000..9d49e4ad44
--- /dev/null
+++ b/FatPkg/FatPkg.dec
@@ -0,0 +1,29 @@
+#/** @file
+#
+# FAT Package
+#
+# FAT 32 Driver
+# Copyright (c) 2007, Intel Corporation.
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+ DEC_VERSION = 0x00010005
+ PACKAGE_NAME = FatPkg
+ PACKAGE_GUID = 8EA68A2C-99CB-4332-85C6-DD5864EAA674
+
+[PcdsFeatureFlag.common]
+ gEfiFatPkgTokenSpaceGuid.PcdUnicodeCollationSupport|TRUE|BOOLEAN|0x00010001
+ gEfiFatPkgTokenSpaceGuid.PcdUnicodeCollation2Support|TRUE|BOOLEAN|0x00010002
+
+[Guids.common]
+ gEfiFatPkgTokenSpaceGuid = {0xc8e92dba, 0x1d92, 0x411f, {0xae, 0xa, 0x1d, 0xbe, 0xd8, 0xf1, 0x32, 0x99}};
+
diff --git a/FatPkg/FatPkg.dsc b/FatPkg/FatPkg.dsc
new file mode 100644
index 0000000000..03b69fab57
--- /dev/null
+++ b/FatPkg/FatPkg.dsc
@@ -0,0 +1,49 @@
+#/** @file
+#
+# Build Binary Enhanced Fat Driver Modules
+#
+# This Platform file is used to generate the Binary Fat Drivers
+# for EDK II Prime release.
+# Copyright (c) 2007, Intel Corporation
+#
+# This program and the accompanying materials are licensed and made available
+# under the terms and conditions of the BSD License which accompanies this
+# distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+ PLATFORM_NAME = Fat
+ PLATFORM_GUID = 25b55dbc-9d0b-4a32-80da-46e1273d622c
+ PLATFORM_VERSION = 0.1
+ DSC_SPECIFICATION = 0x00010005
+ SUPPORTED_ARCHITECTURES = IA32|X64|IPF|EBC
+ OUTPUT_DIRECTORY = Build/Fat
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+
+[LibraryClasses.common]
+ #
+ # Entry Point Libraries
+ #
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ #
+ # Common Libraries
+ #
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+ MemoryAllocationLib|MdePkg/Library/DxeMemoryAllocationLib/DxeMemoryAllocationLib.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+
+[Components.common]
+ FatPkg\EnhancedFatDxe\Fat.inf
diff --git a/FatPkg/License.txt b/FatPkg/License.txt
new file mode 100644
index 0000000000..2740e4dcac
--- /dev/null
+++ b/FatPkg/License.txt
@@ -0,0 +1,11 @@
+Copyright (c) 2006, Intel Corporation
+All rights reserved.
+
+This program and the accompanying materials are licensed and made available
+under the terms and conditions of the BSD License which accompanies this
+distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
diff --git a/FatPkg/ReadMe.txt b/FatPkg/ReadMe.txt
new file mode 100644
index 0000000000..7af215f555
--- /dev/null
+++ b/FatPkg/ReadMe.txt
@@ -0,0 +1,7 @@
+EDK II Prime FAT Package
+
+Build Validation:
+MYTOOLS(VS2005) IA32 X64 IPF EBC
+ICC IA32 X64 IPF
+CYGWINGCC IA32 X64
+