From b9ec93308b33bcb0bb37d6213a76c3fed0b5bc0b Mon Sep 17 00:00:00 2001 From: Qing Huang Date: Thu, 20 Dec 2007 09:16:45 +0000 Subject: [PATCH] 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 Acked-by: Mark Doran Acked-by: Laszlo Ersek --- FatPkg/EnhancedFatDxe/ComponentName.c | 355 +++++ FatPkg/EnhancedFatDxe/Data.c | 50 + FatPkg/EnhancedFatDxe/Debug.c | 80 ++ FatPkg/EnhancedFatDxe/Delete.c | 138 ++ FatPkg/EnhancedFatDxe/DirectoryCache.c | 238 ++++ FatPkg/EnhancedFatDxe/DirectoryManage.c | 1563 ++++++++++++++++++++++ FatPkg/EnhancedFatDxe/DiskCache.c | 541 ++++++++ FatPkg/EnhancedFatDxe/Fat.c | 393 ++++++ FatPkg/EnhancedFatDxe/Fat.h | 1119 ++++++++++++++++ FatPkg/EnhancedFatDxe/Fat.inf | 98 ++ FatPkg/EnhancedFatDxe/FatFileSystem.h | 221 +++ FatPkg/EnhancedFatDxe/FileName.c | 583 ++++++++ FatPkg/EnhancedFatDxe/FileSpace.c | 816 +++++++++++ FatPkg/EnhancedFatDxe/Flush.c | 480 +++++++ FatPkg/EnhancedFatDxe/Hash.c | 217 +++ FatPkg/EnhancedFatDxe/Info.c | 625 +++++++++ FatPkg/EnhancedFatDxe/Init.c | 431 ++++++ FatPkg/EnhancedFatDxe/Misc.c | 409 ++++++ FatPkg/EnhancedFatDxe/Open.c | 285 ++++ FatPkg/EnhancedFatDxe/OpenVolume.c | 80 ++ FatPkg/EnhancedFatDxe/ReadWrite.c | 612 +++++++++ FatPkg/EnhancedFatDxe/UnicodeCollation.c | 324 +++++ FatPkg/FatPkg.dec | 29 + FatPkg/FatPkg.dsc | 49 + FatPkg/License.txt | 11 + FatPkg/ReadMe.txt | 7 + 26 files changed, 9754 insertions(+) create mode 100644 FatPkg/EnhancedFatDxe/ComponentName.c create mode 100644 FatPkg/EnhancedFatDxe/Data.c create mode 100644 FatPkg/EnhancedFatDxe/Debug.c create mode 100644 FatPkg/EnhancedFatDxe/Delete.c create mode 100644 FatPkg/EnhancedFatDxe/DirectoryCache.c create mode 100644 FatPkg/EnhancedFatDxe/DirectoryManage.c create mode 100644 FatPkg/EnhancedFatDxe/DiskCache.c create mode 100644 FatPkg/EnhancedFatDxe/Fat.c create mode 100644 FatPkg/EnhancedFatDxe/Fat.h create mode 100644 FatPkg/EnhancedFatDxe/Fat.inf create mode 100644 FatPkg/EnhancedFatDxe/FatFileSystem.h create mode 100644 FatPkg/EnhancedFatDxe/FileName.c create mode 100644 FatPkg/EnhancedFatDxe/FileSpace.c create mode 100644 FatPkg/EnhancedFatDxe/Flush.c create mode 100644 FatPkg/EnhancedFatDxe/Hash.c create mode 100644 FatPkg/EnhancedFatDxe/Info.c create mode 100644 FatPkg/EnhancedFatDxe/Init.c create mode 100644 FatPkg/EnhancedFatDxe/Misc.c create mode 100644 FatPkg/EnhancedFatDxe/Open.c create mode 100644 FatPkg/EnhancedFatDxe/OpenVolume.c create mode 100644 FatPkg/EnhancedFatDxe/ReadWrite.c create mode 100644 FatPkg/EnhancedFatDxe/UnicodeCollation.c create mode 100644 FatPkg/FatPkg.dec create mode 100644 FatPkg/FatPkg.dsc create mode 100644 FatPkg/License.txt create mode 100644 FatPkg/ReadMe.txt 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) <= 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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) <= 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
+ 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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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 + -- 2.39.2