--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ ComponentName.c\r
+\r
+Abstract:\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FatComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FatComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gFatComponentName = {\r
+ FatComponentNameGetDriverName,\r
+ FatComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gFatComponentName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) FatComponentNameGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) FatComponentNameGetControllerName,\r
+ "en"\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFatDriverNameTable[] = {\r
+ {\r
+ "eng;en",\r
+ L"FAT File System Driver"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mFatControllerNameTable[] = {\r
+ {\r
+ "eng;en",\r
+ L"FAT File System"\r
+ },\r
+ {\r
+ NULL,\r
+ NULL\r
+ }\r
+};\r
+\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FatComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mFatDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN)(This == &gFatComponentName)\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FatComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // This is a device driver, so ChildHandle must be NULL.\r
+ //\r
+ if (ChildHandle != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Make sure this driver is currently managing ControllHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gFatDriverBinding.DriverBindingHandle,\r
+ &gEfiDiskIoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mFatControllerNameTable,\r
+ ControllerName,\r
+ (BOOLEAN)(This == &gFatComponentName)\r
+ );\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Data.c\r
+\r
+Abstract:\r
+\r
+ Global data in the FAT Filesystem driver\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+//\r
+// Globals\r
+//\r
+//\r
+// FatFsLock - Global lock for synchronizing all requests.\r
+//\r
+EFI_LOCK FatFsLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_CALLBACK);\r
+\r
+EFI_LOCK FatTaskLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);\r
+\r
+//\r
+// Filesystem interface functions\r
+//\r
+EFI_FILE_PROTOCOL FatFileInterface = {\r
+ EFI_FILE_PROTOCOL_REVISION,\r
+ FatOpen,\r
+ FatClose,\r
+ FatDelete,\r
+ FatRead,\r
+ FatWrite,\r
+ FatGetPosition,\r
+ FatSetPosition,\r
+ FatGetInfo,\r
+ FatSetInfo,\r
+ FatFlush,\r
+ FatOpenEx,\r
+ FatReadEx,\r
+ FatWriteEx,\r
+ FatFlushEx\r
+};\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ debug.c\r
+\r
+Abstract:\r
+\r
+ Debug functions for fat driver\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+VOID\r
+FatDumpFatTable (\r
+ IN FAT_VOLUME *Volume\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Dump all the FAT Entry of the FAT table in the volume\r
+\r
+Arguments:\r
+\r
+ Volume - The volume whose FAT info will be dumped\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ UINTN EntryValue;\r
+ UINTN MaxIndex;\r
+ UINTN Index;\r
+ CHAR16 *Pointer;\r
+\r
+ MaxIndex = Volume->MaxCluster + 2;\r
+\r
+ Print (L"Dump of Fat Table, MaxCluster %x\n", MaxIndex);\r
+ for (Index = 0; Index < MaxIndex; Index++) {\r
+ EntryValue = FatGetFatEntry (Volume, Index);\r
+ if (EntryValue != FAT_CLUSTER_FREE) {\r
+ Pointer = NULL;\r
+ switch (EntryValue) {\r
+ case FAT_CLUSTER_RESERVED:\r
+ Pointer = L"RESREVED";\r
+ break;\r
+\r
+ case FAT_CLUSTER_BAD:\r
+ Pointer = L"BAD";\r
+ break;\r
+ }\r
+\r
+ if (FAT_END_OF_FAT_CHAIN (EntryValue)) {\r
+ Pointer = L"LAST";\r
+ }\r
+\r
+ if (Pointer != NULL) {\r
+ Print (L"Entry %x = %s\n", Index, Pointer);\r
+ } else {\r
+ Print (L"Entry %x = %x\n", Index, EntryValue);\r
+ }\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ delete.c\r
+\r
+Abstract:\r
+\r
+ Function that deletes a file\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDelete (\r
+ IN EFI_FILE_PROTOCOL *FHand\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Deletes the file & Closes the file handle.\r
+\r
+Arguments:\r
+\r
+ FHand - Handle to the file to delete.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Delete the file successfully.\r
+ EFI_WARN_DELETE_FAILURE - Fail to delete the file.\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+ FAT_DIRENT *DirEnt;\r
+ EFI_STATUS Status;\r
+ UINTN Round;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+\r
+ FatWaitNonblockingTask (IFile);\r
+\r
+ //\r
+ // Lock the volume\r
+ //\r
+ FatAcquireLock ();\r
+\r
+ //\r
+ // If the file is read-only, then don't delete it\r
+ //\r
+ if (IFile->ReadOnly) {\r
+ Status = EFI_WRITE_PROTECTED;\r
+ goto Done;\r
+ }\r
+ //\r
+ // If the file is the root dir, then don't delete it\r
+ //\r
+ if (OFile->Parent == NULL) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+ //\r
+ // If the file has a permanant error, skip the delete\r
+ //\r
+ Status = OFile->Error;\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // If this is a directory, make sure it's empty before\r
+ // allowing it to be deleted\r
+ //\r
+ if (OFile->ODir != NULL) {\r
+ //\r
+ // We do not allow to delete nonempty directory\r
+ //\r
+ FatResetODirCursor (OFile);\r
+ for (Round = 0; Round < 3; Round++) {\r
+ Status = FatGetNextDirEnt (OFile, &DirEnt);\r
+ if ((EFI_ERROR (Status)) ||\r
+ ((Round < 2) && (DirEnt == NULL || !FatIsDotDirEnt (DirEnt))) ||\r
+ ((Round == 2) && (DirEnt != NULL))\r
+ ) {\r
+ Status = EFI_ACCESS_DENIED;\r
+ goto Done;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Return the file's space by setting its size to 0\r
+ //\r
+ FatTruncateOFile (OFile, 0);\r
+ //\r
+ // Free the directory entry for this file\r
+ //\r
+ Status = FatRemoveDirEnt (OFile->Parent, OFile->DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Set a permanent error for this OFile in case there\r
+ // are still opened IFiles attached\r
+ //\r
+ OFile->Error = EFI_NOT_FOUND;\r
+ } else if (OFile->Error == EFI_NOT_FOUND) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+Done:\r
+ //\r
+ // Always close the handle\r
+ //\r
+ FatIFileClose (IFile);\r
+ //\r
+ // Done\r
+ //\r
+ Status = FatCleanupVolume (OFile->Volume, NULL, Status, NULL);\r
+ FatReleaseLock ();\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_WARN_DELETE_FAILURE;\r
+ }\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ DirectoryCache.c\r
+\r
+Abstract:\r
+\r
+ Functions for directory cache operation\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+STATIC\r
+VOID\r
+FatFreeODir (\r
+ IN FAT_ODIR *ODir\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Free the directory structure and release the memory.\r
+\r
+Arguments:\r
+\r
+ ODir - The directory to be freed.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ FAT_DIRENT *DirEnt;\r
+\r
+ //\r
+ // Release Directory Entry Nodes\r
+ //\r
+ while (!IsListEmpty (&ODir->ChildList)) {\r
+ DirEnt = DIRENT_FROM_LINK (ODir->ChildList.ForwardLink);\r
+ RemoveEntryList (&DirEnt->Link);\r
+ //\r
+ // Make sure the OFile has been closed\r
+ //\r
+ ASSERT (DirEnt->OFile == NULL);\r
+ FatFreeDirEnt (DirEnt);\r
+ }\r
+\r
+ FreePool (ODir);\r
+}\r
+\r
+STATIC\r
+FAT_ODIR *\r
+FatAllocateODir (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Allocate the directory structure.\r
+\r
+Arguments:\r
+\r
+ OFile - The corresponding OFile.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ FAT_ODIR *ODir;\r
+\r
+ ODir = AllocateZeroPool (sizeof (FAT_ODIR));\r
+ if (ODir != NULL) {\r
+ //\r
+ // Initialize the directory entry list\r
+ //\r
+ ODir->Signature = FAT_ODIR_SIGNATURE;\r
+ InitializeListHead (&ODir->ChildList);\r
+ ODir->CurrentCursor = &ODir->ChildList;\r
+ }\r
+\r
+ return ODir;\r
+}\r
+\r
+VOID\r
+FatDiscardODir (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Discard the directory structure when an OFile will be freed.\r
+ Volume will cache this directory if the OFile does not represent a deleted file.\r
+\r
+Arguments:\r
+\r
+ OFile - The OFile whose directory structure is to be discarded.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ FAT_ODIR *ODir;\r
+ FAT_VOLUME *Volume;\r
+\r
+ Volume = OFile->Volume;\r
+ ODir = OFile->ODir;\r
+ if (!OFile->DirEnt->Invalid) {\r
+ //\r
+ // If OFile does not represent a deleted file, then we will cache the directory\r
+ // We use OFile's first cluster as the directory's tag\r
+ //\r
+ ODir->DirCacheTag = OFile->FileCluster;\r
+ InsertHeadList (&Volume->DirCacheList, &ODir->DirCacheLink);\r
+ if (Volume->DirCacheCount == FAT_MAX_DIR_CACHE_COUNT) {\r
+ //\r
+ // Replace the least recent used directory\r
+ //\r
+ ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);\r
+ RemoveEntryList (&ODir->DirCacheLink);\r
+ } else {\r
+ //\r
+ // No need to find a replace\r
+ //\r
+ Volume->DirCacheCount++;\r
+ ODir = NULL;\r
+ }\r
+ }\r
+ //\r
+ // Release ODir Structure\r
+ //\r
+ if (ODir != NULL) {\r
+ FatFreeODir (ODir);\r
+ }\r
+}\r
+\r
+VOID\r
+FatRequestODir (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Request the directory structure when an OFile is newly generated.\r
+ If the directory structure is cached by volume, then just return this directory;\r
+ Otherwise, allocate a new one for OFile.\r
+\r
+Arguments:\r
+\r
+ OFile - The OFile which requests directory structure.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ UINTN DirCacheTag;\r
+ FAT_VOLUME *Volume;\r
+ FAT_ODIR *ODir;\r
+ FAT_ODIR *CurrentODir;\r
+ LIST_ENTRY *CurrentODirLink;\r
+\r
+ Volume = OFile->Volume;\r
+ ODir = NULL;\r
+ DirCacheTag = OFile->FileCluster;\r
+ for (CurrentODirLink = Volume->DirCacheList.ForwardLink;\r
+ CurrentODirLink != &Volume->DirCacheList;\r
+ CurrentODirLink = CurrentODirLink->ForwardLink\r
+ ) {\r
+ CurrentODir = ODIR_FROM_DIRCACHELINK (CurrentODirLink);\r
+ if (CurrentODir->DirCacheTag == DirCacheTag) {\r
+ RemoveEntryList (&CurrentODir->DirCacheLink);\r
+ Volume->DirCacheCount--;\r
+ ODir = CurrentODir;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (ODir == NULL) {\r
+ //\r
+ // This directory is not cached, then allocate a new one\r
+ //\r
+ ODir = FatAllocateODir (OFile);\r
+ }\r
+\r
+ OFile->ODir = ODir;\r
+}\r
+\r
+VOID\r
+FatCleanupODirCache (\r
+ IN FAT_VOLUME *Volume\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Clean up all the cached directory structures when the volume is going to be abandoned.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ FAT_ODIR *ODir;\r
+ while (Volume->DirCacheCount > 0) {\r
+ ODir = ODIR_FROM_DIRCACHELINK (Volume->DirCacheList.BackLink);\r
+ RemoveEntryList (&ODir->DirCacheLink);\r
+ FatFreeODir (ODir);\r
+ Volume->DirCacheCount--;\r
+ }\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ DirectoryManage.c\r
+\r
+Abstract:\r
+\r
+ Functions for performing directory entry io\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatAccessEntry (\r
+ IN FAT_OFILE *Parent,\r
+ IN IO_MODE IoMode,\r
+ IN UINTN EntryPos,\r
+ IN OUT VOID *Entry\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get a directory entry from disk for the Ofile.\r
+\r
+Arguments:\r
+\r
+ Parent - The parent of the OFile which need to update.\r
+ IoMode - Indicate whether to read directory entry or write directroy entry.\r
+ EntryPos - The position of the directory entry to be accessed.\r
+ Entry - The directory entry read or written.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Access the directory entry sucessfully.\r
+ other - An error occurred when reading the directory entry.\r
+\r
+--*/\r
+{\r
+ UINTN Position;\r
+ UINTN BufferSize;\r
+\r
+ Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY);\r
+ if (Position >= Parent->FileSize) {\r
+ //\r
+ // End of directory\r
+ //\r
+ ASSERT (IoMode == READ_DATA);\r
+ ((FAT_DIRECTORY_ENTRY *) Entry)->FileName[0] = EMPTY_ENTRY_MARK;\r
+ ((FAT_DIRECTORY_ENTRY *) Entry)->Attributes = 0;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BufferSize = sizeof (FAT_DIRECTORY_ENTRY);\r
+ return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry, NULL);\r
+}\r
+\r
+EFI_STATUS\r
+FatStoreDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Save the directory entry to disk.\r
+\r
+Arguments:\r
+\r
+ OFile - The parent OFile which needs to update.\r
+ DirEnt - The directory entry to be saved.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Store the directory entry successfully.\r
+ other - An error occurred when writing the directory entry.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_DIRECTORY_LFN LfnEntry;\r
+ UINTN EntryPos;\r
+ CHAR16 *LfnBufferPointer;\r
+ CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];\r
+ UINT8 EntryCount;\r
+ UINT8 LfnOrdinal;\r
+\r
+ EntryPos = DirEnt->EntryPos;\r
+ EntryCount = DirEnt->EntryCount;\r
+ //\r
+ // Write directory entry\r
+ //\r
+ Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &DirEnt->Entry);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (--EntryCount > 0) {\r
+ //\r
+ // Write LFN directory entry\r
+ //\r
+ SetMem (LfnBuffer, sizeof (CHAR16) * LFN_CHAR_TOTAL * EntryCount, 0xff);\r
+ Status = StrCpyS (\r
+ LfnBuffer,\r
+ sizeof (LfnBuffer) / sizeof (LfnBuffer[0]),\r
+ DirEnt->FileString\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ LfnBufferPointer = LfnBuffer;\r
+ LfnEntry.Attributes = FAT_ATTRIBUTE_LFN;\r
+ LfnEntry.Type = 0;\r
+ LfnEntry.MustBeZero = 0;\r
+ LfnEntry.Checksum = FatCheckSum (DirEnt->Entry.FileName);\r
+ for (LfnOrdinal = 1; LfnOrdinal <= EntryCount; LfnOrdinal++) {\r
+ LfnEntry.Ordinal = LfnOrdinal;\r
+ if (LfnOrdinal == EntryCount) {\r
+ LfnEntry.Ordinal |= FAT_LFN_LAST;\r
+ }\r
+\r
+ CopyMem (LfnEntry.Name1, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR1_LEN);\r
+ LfnBufferPointer += LFN_CHAR1_LEN;\r
+ CopyMem (LfnEntry.Name2, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR2_LEN);\r
+ LfnBufferPointer += LFN_CHAR2_LEN;\r
+ CopyMem (LfnEntry.Name3, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR3_LEN);\r
+ LfnBufferPointer += LFN_CHAR3_LEN;\r
+ EntryPos--;\r
+ if (DirEnt->Invalid) {\r
+ LfnEntry.Ordinal = DELETE_ENTRY_MARK;\r
+ }\r
+\r
+ Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &LfnEntry);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+FatIsDotDirEnt (\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Determine whether the directory entry is "." or ".." entry.\r
+\r
+Arguments:\r
+\r
+ DirEnt - The corresponding directory entry.\r
+\r
+Returns:\r
+\r
+ TRUE - The directory entry is "." or ".." directory entry\r
+ FALSE - The directory entry is not "." or ".." directory entry\r
+\r
+--*/\r
+{\r
+ CHAR16 *FileString;\r
+ FileString = DirEnt->FileString;\r
+ if (StrCmp (FileString, L".") == 0 || StrCmp (FileString, L"..") == 0) {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatSetDirEntCluster (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the OFile's cluster info in its directory entry.\r
+\r
+Arguments:\r
+\r
+ OFile - The corresponding OFile.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ UINTN Cluster;\r
+ FAT_DIRENT *DirEnt;\r
+\r
+ DirEnt = OFile->DirEnt;\r
+ Cluster = OFile->FileCluster;\r
+ DirEnt->Entry.FileClusterHigh = (UINT16) (Cluster >> 16);\r
+ DirEnt->Entry.FileCluster = (UINT16) Cluster;\r
+}\r
+\r
+VOID\r
+FatUpdateDirEntClusterSizeInfo (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the OFile's cluster and size info in its directory entry.\r
+\r
+Arguments:\r
+\r
+ OFile - The corresponding OFile.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ ASSERT (OFile->ODir == NULL);\r
+ OFile->DirEnt->Entry.FileSize = (UINT32) OFile->FileSize;\r
+ FatSetDirEntCluster (OFile);\r
+}\r
+\r
+VOID\r
+FatCloneDirEnt (\r
+ IN FAT_DIRENT *DirEnt1,\r
+ IN FAT_DIRENT *DirEnt2\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.\r
+\r
+Arguments:\r
+\r
+ DirEnt1 - The destination directory entry.\r
+ DirEnt2 - The source directory entry.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ UINT8 *Entry1;\r
+ UINT8 *Entry2;\r
+ Entry1 = (UINT8 *) &DirEnt1->Entry;\r
+ Entry2 = (UINT8 *) &DirEnt2->Entry;\r
+ CopyMem (\r
+ Entry1 + FAT_ENTRY_INFO_OFFSET,\r
+ Entry2 + FAT_ENTRY_INFO_OFFSET,\r
+ sizeof (FAT_DIRECTORY_ENTRY) - FAT_ENTRY_INFO_OFFSET\r
+ );\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatLoadLongNameEntry (\r
+ IN FAT_OFILE *Parent,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the LFN for the directory entry.\r
+\r
+Arguments:\r
+\r
+ Parent - The parent directory.\r
+ DirEnt - The directory entry to get LFN.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];\r
+ CHAR16 *LfnBufferPointer;\r
+ CHAR8 *File8Dot3Name;\r
+ UINTN EntryPos;\r
+ UINT8 LfnOrdinal;\r
+ UINT8 LfnChecksum;\r
+ FAT_DIRECTORY_LFN LfnEntry;\r
+ EFI_STATUS Status;\r
+\r
+ EntryPos = DirEnt->EntryPos;\r
+ File8Dot3Name = DirEnt->Entry.FileName;\r
+ LfnBufferPointer = LfnBuffer;\r
+ //\r
+ // Computes checksum for LFN\r
+ //\r
+ LfnChecksum = FatCheckSum (File8Dot3Name);\r
+ LfnOrdinal = 1;\r
+ do {\r
+ if (EntryPos == 0) {\r
+ LfnBufferPointer = LfnBuffer;\r
+ break;\r
+ }\r
+\r
+ EntryPos--;\r
+ Status = FatAccessEntry (Parent, READ_DATA, EntryPos, &LfnEntry);\r
+ if (EFI_ERROR (Status) ||\r
+ LfnEntry.Attributes != FAT_ATTRIBUTE_LFN ||\r
+ LfnEntry.MustBeZero != 0 ||\r
+ LfnEntry.Checksum != LfnChecksum ||\r
+ (LfnEntry.Ordinal & (~FAT_LFN_LAST)) != LfnOrdinal ||\r
+ LfnOrdinal > MAX_LFN_ENTRIES\r
+ ) {\r
+ //\r
+ // The directory entry does not have a long file name or\r
+ // some error occurs when loading long file name for a directory entry,\r
+ // and then we load the long name from short name\r
+ //\r
+ LfnBufferPointer = LfnBuffer;\r
+ break;\r
+ }\r
+\r
+ CopyMem (LfnBufferPointer, LfnEntry.Name1, sizeof (CHAR16) * LFN_CHAR1_LEN);\r
+ LfnBufferPointer += LFN_CHAR1_LEN;\r
+ CopyMem (LfnBufferPointer, LfnEntry.Name2, sizeof (CHAR16) * LFN_CHAR2_LEN);\r
+ LfnBufferPointer += LFN_CHAR2_LEN;\r
+ CopyMem (LfnBufferPointer, LfnEntry.Name3, sizeof (CHAR16) * LFN_CHAR3_LEN);\r
+ LfnBufferPointer += LFN_CHAR3_LEN;\r
+ LfnOrdinal++;\r
+ } while ((LfnEntry.Ordinal & FAT_LFN_LAST) == 0);\r
+ DirEnt->EntryCount = LfnOrdinal;\r
+ //\r
+ // Terminate current Lfnbuffer\r
+ //\r
+ *LfnBufferPointer = 0;\r
+ if (LfnBufferPointer == LfnBuffer) {\r
+ //\r
+ // Fail to get the long file name from long file name entry,\r
+ // get the file name from short name\r
+ //\r
+ FatGetFileNameViaCaseFlag (\r
+ DirEnt,\r
+ LfnBuffer,\r
+ sizeof (LfnBuffer) / sizeof (LfnBuffer[0])\r
+ );\r
+ }\r
+\r
+ DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer);\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatAddDirEnt (\r
+ IN FAT_ODIR *ODir,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Add this directory entry node to the list of directory entries and hash table.\r
+\r
+Arguments:\r
+\r
+ ODir - The parent OFile which needs to be updated.\r
+ DirEnt - The directory entry to be added.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ if (DirEnt->Link.BackLink == NULL) {\r
+ DirEnt->Link.BackLink = &ODir->ChildList;\r
+ }\r
+ InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link);\r
+ FatInsertToHashTable (ODir, DirEnt);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatLoadNextDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ OUT FAT_DIRENT **PtrDirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Load from disk the next directory entry at current end of directory position\r
+\r
+Arguments:\r
+\r
+ OFile - The parent OFile.\r
+ PtrDirEnt - The directory entry that is loaded.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Load the directory entry successfully.\r
+ EFI_OUT_OF_RESOURCES - Out of resource.\r
+ other - An error occurred when reading the directory entries.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_DIRENT *DirEnt;\r
+ FAT_ODIR *ODir;\r
+ FAT_DIRECTORY_ENTRY Entry;\r
+\r
+ ODir = OFile->ODir;\r
+ //\r
+ // Make sure the parent's directory has been opened\r
+ //\r
+ ASSERT (ODir != NULL);\r
+ //\r
+ // Assert we have not reached the end of directory\r
+ //\r
+ ASSERT (!ODir->EndOfDir);\r
+ DirEnt = NULL;\r
+\r
+ for (;;) {\r
+ //\r
+ // Read the next directory entry until we find a valid directory entry (excluding lfn entry)\r
+ //\r
+ Status = FatAccessEntry (OFile, READ_DATA, ODir->CurrentEndPos, &Entry);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (((UINT8) Entry.FileName[0] != DELETE_ENTRY_MARK) && (Entry.Attributes & FAT_ATTRIBUTE_VOLUME_ID) == 0) {\r
+ //\r
+ // We get a valid directory entry, then handle it\r
+ //\r
+ break;\r
+ }\r
+\r
+ ODir->CurrentEndPos++;\r
+ }\r
+\r
+ if (Entry.FileName[0] != EMPTY_ENTRY_MARK) {\r
+ //\r
+ // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications\r
+ // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.\r
+ //\r
+ if (OFile->Volume->FatType != FAT32) {\r
+ Entry.FileClusterHigh = 0;\r
+ }\r
+\r
+ //\r
+ // This is a valid directory entry\r
+ //\r
+ DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));\r
+ if (DirEnt == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ DirEnt->Signature = FAT_DIRENT_SIGNATURE;\r
+ //\r
+ // Remember the directory's entry position on disk\r
+ //\r
+ DirEnt->EntryPos = (UINT16) ODir->CurrentEndPos;\r
+ CopyMem (&DirEnt->Entry, &Entry, sizeof (FAT_DIRECTORY_ENTRY));\r
+ FatLoadLongNameEntry (OFile, DirEnt);\r
+ if (DirEnt->FileString == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Add this directory entry to directory\r
+ //\r
+ FatAddDirEnt (ODir, DirEnt);\r
+ //\r
+ // Point to next directory entry\r
+ //\r
+ ODir->CurrentEndPos++;\r
+ } else {\r
+ ODir->EndOfDir = TRUE;\r
+ }\r
+\r
+ *PtrDirEnt = DirEnt;\r
+ return EFI_SUCCESS;\r
+\r
+Done:\r
+ FatFreeDirEnt (DirEnt);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatGetDirEntInfo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN FAT_DIRENT *DirEnt,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the directory entry's info into Buffer.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ DirEnt - The corresponding directory entry.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing file info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_BUFFER_TOO_SMALL - The buffer is too small.\r
+\r
+--*/\r
+{\r
+ UINTN Size;\r
+ UINTN NameSize;\r
+ UINTN ResultSize;\r
+ UINTN Cluster;\r
+ EFI_STATUS Status;\r
+ EFI_FILE_INFO *Info;\r
+ FAT_DIRECTORY_ENTRY *Entry;\r
+ FAT_DATE_TIME FatLastAccess;\r
+\r
+ ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+ Size = SIZE_OF_EFI_FILE_INFO;\r
+ NameSize = StrSize (DirEnt->FileString);\r
+ ResultSize = Size + NameSize;\r
+\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ if (*BufferSize >= ResultSize) {\r
+ Status = EFI_SUCCESS;\r
+ Entry = &DirEnt->Entry;\r
+ Info = Buffer;\r
+ Info->Size = ResultSize;\r
+ if ((Entry->Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {\r
+ Cluster = (Entry->FileClusterHigh << 16) | Entry->FileCluster;\r
+ Info->PhysicalSize = FatPhysicalDirSize (Volume, Cluster);\r
+ Info->FileSize = Info->PhysicalSize;\r
+ } else {\r
+ Info->FileSize = Entry->FileSize;\r
+ Info->PhysicalSize = FatPhysicalFileSize (Volume, Entry->FileSize);\r
+ }\r
+\r
+ ZeroMem (&FatLastAccess.Time, sizeof (FatLastAccess.Time));\r
+ CopyMem (&FatLastAccess.Date, &Entry->FileLastAccess, sizeof (FatLastAccess.Date));\r
+ FatFatTimeToEfiTime (&FatLastAccess, &Info->LastAccessTime);\r
+ FatFatTimeToEfiTime (&Entry->FileCreateTime, &Info->CreateTime);\r
+ FatFatTimeToEfiTime (&Entry->FileModificationTime, &Info->ModificationTime);\r
+ Info->Attribute = Entry->Attributes & EFI_FILE_VALID_ATTR;\r
+ CopyMem ((CHAR8 *) Buffer + Size, DirEnt->FileString, NameSize);\r
+ }\r
+\r
+ *BufferSize = ResultSize;\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatSearchODir (\r
+ IN FAT_OFILE *OFile,\r
+ IN CHAR16 *FileNameString,\r
+ OUT FAT_DIRENT **PtrDirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Search the directory for the directory entry whose filename is FileNameString.\r
+\r
+Arguments:\r
+\r
+ OFile - The parent OFile whose directory is to be searched.\r
+ FileNameString - The filename to be searched.\r
+ PtrDirEnt - pointer to the directory entry if found.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Find the directory entry or not found.\r
+ other - An error occurred when reading the directory entries.\r
+\r
+--*/\r
+{\r
+ BOOLEAN PossibleShortName;\r
+ CHAR8 File8Dot3Name[FAT_NAME_LEN];\r
+ FAT_ODIR *ODir;\r
+ FAT_DIRENT *DirEnt;\r
+ EFI_STATUS Status;\r
+\r
+ ODir = OFile->ODir;\r
+ ASSERT (ODir != NULL);\r
+ //\r
+ // Check if the file name is a valid short name\r
+ //\r
+ PossibleShortName = FatCheckIs8Dot3Name (FileNameString, File8Dot3Name);\r
+ //\r
+ // Search the hash table first\r
+ //\r
+ DirEnt = *FatLongNameHashSearch (ODir, FileNameString);\r
+ if (DirEnt == NULL && PossibleShortName) {\r
+ DirEnt = *FatShortNameHashSearch (ODir, File8Dot3Name);\r
+ }\r
+ if (DirEnt == NULL) {\r
+ //\r
+ // We fail to get the directory entry from hash table; we then\r
+ // search the rest directory\r
+ //\r
+ while (!ODir->EndOfDir) {\r
+ Status = FatLoadNextDirEnt (OFile, &DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (DirEnt != NULL) {\r
+ if (FatStriCmp (FileNameString, DirEnt->FileString) == 0) {\r
+ break;\r
+ }\r
+\r
+ if (PossibleShortName && CompareMem (File8Dot3Name, DirEnt->Entry.FileName, FAT_NAME_LEN) == 0) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ *PtrDirEnt = DirEnt;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+FatResetODirCursor (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the OFile's current directory cursor to the list head.\r
+\r
+Arguments:\r
+\r
+ OFile - The directory OFile whose directory cursor is reset.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ FAT_ODIR *ODir;\r
+\r
+ ODir = OFile->ODir;\r
+ ASSERT (ODir != NULL);\r
+ ODir->CurrentCursor = &(ODir->ChildList);\r
+ ODir->CurrentPos = 0;\r
+}\r
+\r
+EFI_STATUS\r
+FatGetNextDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ OUT FAT_DIRENT **PtrDirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the directory's cursor to the next and get the next directory entry.\r
+\r
+Arguments:\r
+\r
+ OFile - The parent OFile.\r
+ PtrDirEnt - The next directory entry.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - We get the next directory entry successfully.\r
+ other - An error occurred when get next directory entry.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_DIRENT *DirEnt;\r
+ FAT_ODIR *ODir;\r
+\r
+ ODir = OFile->ODir;\r
+ ASSERT (ODir != NULL);\r
+ if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {\r
+ //\r
+ // End of directory, we will try one more time\r
+ //\r
+ if (!ODir->EndOfDir) {\r
+ //\r
+ // Read directory from disk\r
+ //\r
+ Status = FatLoadNextDirEnt (OFile, &DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {\r
+ //\r
+ // End of directory, return NULL\r
+ //\r
+ DirEnt = NULL;\r
+ ODir->CurrentPos = ODir->CurrentEndPos;\r
+ } else {\r
+ ODir->CurrentCursor = ODir->CurrentCursor->ForwardLink;\r
+ DirEnt = DIRENT_FROM_LINK (ODir->CurrentCursor);\r
+ ODir->CurrentPos = DirEnt->EntryPos + 1;\r
+ }\r
+\r
+ *PtrDirEnt = DirEnt;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatSetEntryCount (\r
+ IN FAT_OFILE *OFile,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the directory entry count according to the filename.\r
+\r
+Arguments:\r
+\r
+ OFile - The corresponding OFile.\r
+ DirEnt - The directory entry to be set.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ CHAR16 *FileString;\r
+ CHAR8 *File8Dot3Name;\r
+\r
+ //\r
+ // Get new entry count and set the 8.3 name\r
+ //\r
+ DirEnt->EntryCount = 1;\r
+ FileString = DirEnt->FileString;\r
+ File8Dot3Name = DirEnt->Entry.FileName;\r
+ SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');\r
+ if (StrCmp (FileString, L".") == 0) {\r
+ //\r
+ // "." entry\r
+ //\r
+ File8Dot3Name[0] = '.';\r
+ FatCloneDirEnt (DirEnt, OFile->DirEnt);\r
+ } else if (StrCmp (FileString, L"..") == 0) {\r
+ //\r
+ // ".." entry\r
+ //\r
+ File8Dot3Name[0] = '.';\r
+ File8Dot3Name[1] = '.';\r
+ FatCloneDirEnt (DirEnt, OFile->Parent->DirEnt);\r
+ } else {\r
+ //\r
+ // Normal name\r
+ //\r
+ if (FatCheckIs8Dot3Name (FileString, File8Dot3Name)) {\r
+ //\r
+ // This file name is a valid 8.3 file name, we need to further check its case flag\r
+ //\r
+ FatSetCaseFlag (DirEnt);\r
+ } else {\r
+ //\r
+ // The file name is not a valid 8.3 name we need to generate an 8.3 name for it\r
+ //\r
+ FatCreate8Dot3Name (OFile, DirEnt);\r
+ DirEnt->EntryCount = (UINT8)(LFN_ENTRY_NUMBER (StrLen (FileString)) + DirEnt->EntryCount);\r
+ }\r
+ }\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatExpandODir (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Append a zero cluster to the current OFile.\r
+\r
+Arguments:\r
+\r
+ OFile - The directory OFile which needs to be updated.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Append a zero cluster to the OFile successfully.\r
+ other - An error occurred when appending the zero cluster.\r
+\r
+--*/\r
+{\r
+ return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatSeekVolumeId (\r
+ IN FAT_OFILE *Root,\r
+ OUT FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Search the Root OFile for the possible volume label.\r
+\r
+Arguments:\r
+\r
+ Root - The Root OFile.\r
+ DirEnt - The returned directory entry of volume label.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The search process is completed successfully.\r
+ other - An error occurred when searching volume label.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN EntryPos;\r
+ FAT_DIRECTORY_ENTRY *Entry;\r
+\r
+ EntryPos = 0;\r
+ Entry = &DirEnt->Entry;\r
+ DirEnt->Invalid = TRUE;\r
+ do {\r
+ Status = FatAccessEntry (Root, READ_DATA, EntryPos, Entry);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (((UINT8) Entry->FileName[0] != DELETE_ENTRY_MARK) && (((Entry->Attributes) & (~FAT_ATTRIBUTE_ARCHIVE)) == FAT_ATTRIBUTE_VOLUME_ID)) {\r
+ DirEnt->EntryPos = (UINT16) EntryPos;\r
+ DirEnt->EntryCount = 1;\r
+ DirEnt->Invalid = FALSE;\r
+ break;\r
+ }\r
+\r
+ EntryPos++;\r
+ } while (Entry->FileName[0] != EMPTY_ENTRY_MARK);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatFirstFitInsertDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Use First Fit Algorithm to insert directory entry.\r
+ Only this function will erase "E5" entries in a directory.\r
+ In view of safest recovery, this function will only be triggered\r
+ when maximum directory entry number has reached.\r
+\r
+Arguments:\r
+\r
+ OFile - The corresponding OFile.\r
+ DirEnt - The directory entry to be inserted.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The directory entry has been successfully inserted.\r
+ EFI_VOLUME_FULL - The directory can not hold more directory entries.\r
+ Others - Some error occurred when inserting new directory entries.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_ODIR *ODir;\r
+ LIST_ENTRY *CurrentEntry;\r
+ FAT_DIRENT *CurrentDirEnt;\r
+ UINT32 CurrentPos;\r
+ UINT32 LabelPos;\r
+ UINT32 NewEntryPos;\r
+ UINT16 EntryCount;\r
+ FAT_DIRENT LabelDirEnt;\r
+\r
+ LabelPos = 0;\r
+ if (OFile->Parent == NULL) {\r
+ Status = FatSeekVolumeId (OFile, &LabelDirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (!LabelDirEnt.Invalid) {\r
+ LabelPos = LabelDirEnt.EntryPos;\r
+ }\r
+ }\r
+\r
+ EntryCount = DirEnt->EntryCount;\r
+ NewEntryPos = EntryCount;\r
+ CurrentPos = 0;\r
+ ODir = OFile->ODir;\r
+ for (CurrentEntry = ODir->ChildList.ForwardLink;\r
+ CurrentEntry != &ODir->ChildList;\r
+ CurrentEntry = CurrentEntry->ForwardLink\r
+ ) {\r
+ CurrentDirEnt = DIRENT_FROM_LINK (CurrentEntry);\r
+ if (NewEntryPos + CurrentDirEnt->EntryCount <= CurrentDirEnt->EntryPos) {\r
+ if (LabelPos > NewEntryPos || LabelPos <= CurrentPos) {\r
+ //\r
+ // first fit succeeded\r
+ //\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ CurrentPos = CurrentDirEnt->EntryPos;\r
+ NewEntryPos = CurrentPos + EntryCount;\r
+ }\r
+\r
+ if (NewEntryPos >= ODir->CurrentEndPos) {\r
+ return EFI_VOLUME_FULL;\r
+ }\r
+\r
+Done:\r
+ DirEnt->EntryPos = (UINT16) NewEntryPos;\r
+ DirEnt->Link.BackLink = CurrentEntry;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatNewEntryPos (\r
+ IN FAT_OFILE *OFile,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Find the new directory entry position for the directory entry.\r
+\r
+Arguments:\r
+\r
+ OFile - The corresponding OFile.\r
+ DirEnt - The directory entry whose new position is to be set.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The new directory entry position is successfully found.\r
+ EFI_VOLUME_FULL - The directory has reach its maximum capacity.\r
+ other - An error occurred when reading the directory entry.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_ODIR *ODir;\r
+ FAT_DIRENT *TempDirEnt;\r
+ UINT32 NewEndPos;\r
+\r
+ ODir = OFile->ODir;\r
+ ASSERT (ODir != NULL);\r
+ //\r
+ // Make sure the whole directory has been loaded\r
+ //\r
+ while (!ODir->EndOfDir) {\r
+ Status = FatLoadNextDirEnt (OFile, &TempDirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // We will append this entry to the end of directory\r
+ //\r
+ FatGetCurrentFatTime (&DirEnt->Entry.FileCreateTime);\r
+ CopyMem (&DirEnt->Entry.FileModificationTime, &DirEnt->Entry.FileCreateTime, sizeof (FAT_DATE_TIME));\r
+ CopyMem (&DirEnt->Entry.FileLastAccess, &DirEnt->Entry.FileCreateTime.Date, sizeof (FAT_DATE));\r
+ NewEndPos = ODir->CurrentEndPos + DirEnt->EntryCount;\r
+ if (NewEndPos * sizeof (FAT_DIRECTORY_ENTRY) > OFile->FileSize) {\r
+ if (NewEndPos >= (OFile->IsFixedRootDir ? OFile->Volume->RootEntries : FAT_MAX_DIRENTRY_COUNT)) {\r
+ //\r
+ // We try to use fist fit algorithm to insert this directory entry\r
+ //\r
+ return FatFirstFitInsertDirEnt (OFile, DirEnt);\r
+ }\r
+ //\r
+ // We should allocate a new cluster for this directory\r
+ //\r
+ Status = FatExpandODir (OFile);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // We append our directory entry at the end of directory file\r
+ //\r
+ ODir->CurrentEndPos = NewEndPos;\r
+ DirEnt->EntryPos = (UINT16) (ODir->CurrentEndPos - 1);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatGetVolumeEntry (\r
+ IN FAT_VOLUME *Volume,\r
+ IN CHAR16 *Name\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the directory entry for the volume.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ Name - The file name of the volume.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Update the volume with the directory entry sucessfully.\r
+ others - An error occurred when getting volume label.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_DIRENT LabelDirEnt;\r
+\r
+ *Name = 0;\r
+ Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);\r
+ if (!EFI_ERROR (Status)) {\r
+ if (!LabelDirEnt.Invalid) {\r
+ FatNameToStr (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, FALSE, Name);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatSetVolumeEntry (\r
+ IN FAT_VOLUME *Volume,\r
+ IN CHAR16 *Name\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the relevant directory entry into disk for the volume.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ Name - The new file name of the volume.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Update the Volume sucessfully.\r
+ EFI_UNSUPPORTED - The input label is not a valid volume label.\r
+ other - An error occurred when setting volume label.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_DIRENT LabelDirEnt;\r
+ FAT_OFILE *Root;\r
+\r
+ Root = Volume->Root;\r
+ Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (LabelDirEnt.Invalid) {\r
+ //\r
+ // If there is not the relevant directory entry, create a new one\r
+ //\r
+ ZeroMem (&LabelDirEnt, sizeof (FAT_DIRENT));\r
+ LabelDirEnt.EntryCount = 1;\r
+ Status = FatNewEntryPos (Root, &LabelDirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ LabelDirEnt.Entry.Attributes = FAT_ATTRIBUTE_VOLUME_ID;\r
+ }\r
+\r
+ SetMem (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, ' ');\r
+ if (FatStrToFat (Name, FAT_NAME_LEN, LabelDirEnt.Entry.FileName)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ FatGetCurrentFatTime (&LabelDirEnt.Entry.FileModificationTime);\r
+ return FatStoreDirEnt (Root, &LabelDirEnt);\r
+}\r
+\r
+EFI_STATUS\r
+FatCreateDotDirEnts (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Create "." and ".." directory entries in the newly-created parent OFile.\r
+\r
+Arguments:\r
+\r
+ OFile - The parent OFile.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The dot directory entries are successfully created.\r
+ other - An error occurred when creating the directory entry.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_DIRENT *DirEnt;\r
+\r
+ Status = FatExpandODir (OFile);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FatSetDirEntCluster (OFile);\r
+ //\r
+ // Create "."\r
+ //\r
+ Status = FatCreateDirEnt (OFile, L".", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Create ".."\r
+ //\r
+ Status = FatCreateDirEnt (OFile, L"..", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatCreateDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ IN CHAR16 *FileName,\r
+ IN UINT8 Attributes,\r
+ OUT FAT_DIRENT **PtrDirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Create a directory entry in the parent OFile.\r
+\r
+Arguments:\r
+\r
+ OFile - The parent OFile.\r
+ FileName - The filename of the newly-created directory entry.\r
+ Attributes - The attribute of the newly-created directory entry.\r
+ PtrDirEnt - The pointer to the newly-created directory entry.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The directory entry is successfully created.\r
+ EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry.\r
+ other - An error occurred when creating the directory entry.\r
+\r
+--*/\r
+{\r
+ FAT_DIRENT *DirEnt;\r
+ FAT_ODIR *ODir;\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (OFile != NULL);\r
+ ODir = OFile->ODir;\r
+ ASSERT (ODir != NULL);\r
+ DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));\r
+ if (DirEnt == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ DirEnt->Signature = FAT_DIRENT_SIGNATURE;\r
+ DirEnt->FileString = AllocateCopyPool (StrSize (FileName), FileName);\r
+ if (DirEnt->FileString == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ //\r
+ // Determine how many directory entries we need\r
+ //\r
+ FatSetEntryCount (OFile, DirEnt);\r
+ //\r
+ // Determine the file's directory entry position\r
+ //\r
+ Status = FatNewEntryPos (OFile, DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ FatAddDirEnt (ODir, DirEnt);\r
+ DirEnt->Entry.Attributes = Attributes;\r
+ *PtrDirEnt = DirEnt;\r
+ DEBUG ((EFI_D_INFO, "FSOpen: Created new directory entry '%S'\n", DirEnt->FileString));\r
+ return FatStoreDirEnt (OFile, DirEnt);\r
+\r
+Done:\r
+ FatFreeDirEnt (DirEnt);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatRemoveDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Remove this directory entry node from the list of directory entries and hash table.\r
+\r
+Arguments:\r
+\r
+ OFile - The parent OFile.\r
+ DirEnt - The directory entry to be removed.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The directory entry is successfully removed.\r
+ other - An error occurred when removing the directory entry.\r
+\r
+--*/\r
+{\r
+ FAT_ODIR *ODir;\r
+\r
+ ODir = OFile->ODir;\r
+ if (ODir->CurrentCursor == &DirEnt->Link) {\r
+ //\r
+ // Move the directory cursor to its previous directory entry\r
+ //\r
+ ODir->CurrentCursor = ODir->CurrentCursor->BackLink;\r
+ }\r
+ //\r
+ // Remove from directory entry list\r
+ //\r
+ RemoveEntryList (&DirEnt->Link);\r
+ //\r
+ // Remove from hash table\r
+ //\r
+ FatDeleteFromHashTable (ODir, DirEnt);\r
+ DirEnt->Entry.FileName[0] = DELETE_ENTRY_MARK;\r
+ DirEnt->Invalid = TRUE;\r
+ return FatStoreDirEnt (OFile, DirEnt);\r
+}\r
+\r
+EFI_STATUS\r
+FatOpenDirEnt (\r
+ IN FAT_OFILE *Parent,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Open the directory entry to get the OFile.\r
+\r
+Arguments:\r
+\r
+ OFile - The parent OFile.\r
+ DirEnt - The directory entry to be opened.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The directory entry is successfully opened.\r
+ EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile.\r
+ other - An error occurred when opening the directory entry.\r
+\r
+--*/\r
+{\r
+ FAT_OFILE *OFile;\r
+ FAT_VOLUME *Volume;\r
+\r
+ if (DirEnt->OFile == NULL) {\r
+ //\r
+ // Open the directory entry\r
+ //\r
+ OFile = AllocateZeroPool (sizeof (FAT_OFILE));\r
+ if (OFile == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ OFile->Signature = FAT_OFILE_SIGNATURE;\r
+ InitializeListHead (&OFile->Opens);\r
+ InitializeListHead (&OFile->ChildHead);\r
+ OFile->Parent = Parent;\r
+ OFile->DirEnt = DirEnt;\r
+ if (Parent != NULL) {\r
+ //\r
+ // The newly created OFile is not root\r
+ //\r
+ Volume = Parent->Volume;\r
+ OFile->FullPathLen = Parent->FullPathLen + 1 + StrLen (DirEnt->FileString);\r
+ OFile->FileCluster = ((DirEnt->Entry.FileClusterHigh) << 16) | (DirEnt->Entry.FileCluster);\r
+ InsertTailList (&Parent->ChildHead, &OFile->ChildLink);\r
+ } else {\r
+ //\r
+ // The newly created OFile is root\r
+ //\r
+ Volume = VOLUME_FROM_ROOT_DIRENT (DirEnt);\r
+ Volume->Root = OFile;\r
+ OFile->FileCluster = Volume->RootCluster;\r
+ if (Volume->FatType != FAT32) {\r
+ OFile->IsFixedRootDir = TRUE;\r
+ }\r
+ }\r
+\r
+ OFile->FileCurrentCluster = OFile->FileCluster;\r
+ OFile->Volume = Volume;\r
+ InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);\r
+\r
+ OFile->FileSize = DirEnt->Entry.FileSize;\r
+ if ((DirEnt->Entry.Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {\r
+ if (OFile->IsFixedRootDir) {\r
+ OFile->FileSize = Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY);\r
+ } else {\r
+ OFile->FileSize = FatPhysicalDirSize (Volume, OFile->FileCluster);\r
+ }\r
+\r
+ FatRequestODir (OFile);\r
+ if (OFile->ODir == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ DirEnt->OFile = OFile;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+VOID\r
+FatCloseDirEnt (\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Close the directory entry and free the OFile.\r
+\r
+Arguments:\r
+\r
+ DirEnt - The directory entry to be closed.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The directory entry is successfully opened.\r
+ Other - An error occurred when opening the directory entry.\r
+\r
+--*/\r
+{\r
+ FAT_OFILE *OFile;\r
+ FAT_VOLUME *Volume;\r
+\r
+ OFile = DirEnt->OFile;\r
+ ASSERT (OFile != NULL);\r
+ Volume = OFile->Volume;\r
+\r
+ if (OFile->ODir != NULL) {\r
+ FatDiscardODir (OFile);\r
+ }\r
+\r
+ if (OFile->Parent == NULL) {\r
+ Volume->Root = NULL;\r
+ } else {\r
+ RemoveEntryList (&OFile->ChildLink);\r
+ }\r
+\r
+ FreePool (OFile);\r
+ DirEnt->OFile = NULL;\r
+ if (DirEnt->Invalid == TRUE) {\r
+ //\r
+ // Free directory entry itself\r
+ //\r
+ FatFreeDirEnt (DirEnt);\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+FatLocateOFile (\r
+ IN OUT FAT_OFILE **PtrOFile,\r
+ IN CHAR16 *FileName,\r
+ IN UINT8 Attributes,\r
+ OUT CHAR16 *NewFileName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Traverse filename and open all OFiles that can be opened.\r
+ Update filename pointer to the component that can't be opened.\r
+ If more than one name component remains, returns an error;\r
+ otherwise, return the remaining name component so that the caller might choose to create it.\r
+\r
+Arguments:\r
+ PtrOFile - As input, the reference OFile; as output, the located OFile.\r
+ FileName - The file name relevant to the OFile.\r
+ Attributes - The attribute of the destination OFile.\r
+ NewFileName - The remaining file name.\r
+\r
+Returns:\r
+\r
+ EFI_NOT_FOUND - The file name can't be opened and there is more than one\r
+ components within the name left (this means the name can\r
+ not be created either).\r
+ EFI_INVALID_PARAMETER - The parameter is not valid.\r
+ EFI_SUCCESS - Open the file successfully.\r
+ other - An error occured when locating the OFile.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_VOLUME *Volume;\r
+ CHAR16 ComponentName[EFI_PATH_STRING_LENGTH];\r
+ UINTN FileNameLen;\r
+ BOOLEAN DirIntended;\r
+ CHAR16 *Next;\r
+ FAT_OFILE *OFile;\r
+ FAT_DIRENT *DirEnt;\r
+\r
+ DirEnt = NULL;\r
+\r
+ FileNameLen = StrLen (FileName);\r
+ if (FileNameLen == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OFile = *PtrOFile;\r
+ Volume = OFile->Volume;\r
+\r
+ DirIntended = FALSE;\r
+ if (FileName[FileNameLen - 1] == PATH_NAME_SEPARATOR) {\r
+ DirIntended = TRUE;\r
+ }\r
+ //\r
+ // If name starts with path name separator, then move to root OFile\r
+ //\r
+ if (*FileName == PATH_NAME_SEPARATOR) {\r
+ OFile = Volume->Root;\r
+ FileName++;\r
+ FileNameLen--;\r
+ }\r
+ //\r
+ // Per FAT Spec the file name should meet the following criteria:\r
+ // C1. Length (FileLongName) <= 255\r
+ // C2. Length (X:FileFullPath<NUL>) <= 260\r
+ // Here we check C2 first.\r
+ //\r
+ if (2 + OFile->FullPathLen + 1 + FileNameLen + 1 > EFI_PATH_STRING_LENGTH) {\r
+ //\r
+ // Full path length can not surpass 256\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Start at current location\r
+ //\r
+ Next = FileName;\r
+ for (;;) {\r
+ //\r
+ // Get the next component name\r
+ //\r
+ FileName = Next;\r
+ Next = FatGetNextNameComponent (FileName, ComponentName);\r
+\r
+ //\r
+ // If end of the file name, we're done\r
+ //\r
+ if (ComponentName[0] == 0) {\r
+ if (DirIntended && OFile->ODir == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ NewFileName[0] = 0;\r
+ break;\r
+ }\r
+ //\r
+ // If "dot", then current\r
+ //\r
+ if (StrCmp (ComponentName, L".") == 0) {\r
+ continue;\r
+ }\r
+ //\r
+ // If "dot dot", then parent\r
+ //\r
+ if (StrCmp (ComponentName, L"..") == 0) {\r
+ if (OFile->Parent == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ OFile = OFile->Parent;\r
+ continue;\r
+ }\r
+\r
+ if (!FatFileNameIsValid (ComponentName, NewFileName)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // We have a component name, try to open it\r
+ //\r
+ if (OFile->ODir == NULL) {\r
+ //\r
+ // This file isn't a directory, can't open it\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Search the compName in the directory\r
+ //\r
+ Status = FatSearchODir (OFile, NewFileName, &DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (DirEnt == NULL) {\r
+ //\r
+ // component name is not found in the directory\r
+ //\r
+ if (*Next != 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (DirIntended && (Attributes & FAT_ATTRIBUTE_DIRECTORY) == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // It's the last component name - return with the open\r
+ // path and the remaining name\r
+ //\r
+ break;\r
+ }\r
+\r
+ Status = FatOpenDirEnt (OFile, DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ OFile = DirEnt->OFile;\r
+ }\r
+\r
+ *PtrOFile = OFile;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ DiskCache.c\r
+\r
+Abstract:\r
+\r
+ Cache implementation for EFI FAT File system driver\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+STATIC\r
+VOID\r
+FatFlushDataCacheRange (\r
+ IN FAT_VOLUME *Volume,\r
+ IN IO_MODE IoMode,\r
+ IN UINTN StartPageNo,\r
+ IN UINTN EndPageNo,\r
+ OUT UINT8 *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function is used by the Data Cache.\r
+\r
+ When this function is called by write command, all entries in this range\r
+ are older than the contents in disk, so they are invalid; just mark them invalid.\r
+\r
+ When this function is called by read command, if any entry in this range\r
+ is dirty, it means that the relative info directly readed from media is older than\r
+ than the info in the cache; So need to update the relative info in the Buffer.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ IoMode - This function is called by read command or write command\r
+ StartPageNo - First PageNo to be checked in the cache.\r
+ EndPageNo - Last PageNo to be checked in the cache.\r
+ Buffer - The user buffer need to update. Only when doing the read command\r
+ and there is dirty cache in the cache range, this parameter will be used.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ UINTN PageNo;\r
+ UINTN GroupNo;\r
+ UINTN GroupMask;\r
+ UINTN PageSize;\r
+ UINT8 PageAlignment;\r
+ DISK_CACHE *DiskCache;\r
+ CACHE_TAG *CacheTag;\r
+ UINT8 *BaseAddress;\r
+\r
+ DiskCache = &Volume->DiskCache[CACHE_DATA];\r
+ BaseAddress = DiskCache->CacheBase;\r
+ GroupMask = DiskCache->GroupMask;\r
+ PageAlignment = DiskCache->PageAlignment;\r
+ PageSize = (UINTN)1 << PageAlignment;\r
+\r
+ for (PageNo = StartPageNo; PageNo < EndPageNo; PageNo++) {\r
+ GroupNo = PageNo & GroupMask;\r
+ CacheTag = &DiskCache->CacheTag[GroupNo];\r
+ if (CacheTag->RealSize > 0 && CacheTag->PageNo == PageNo) {\r
+ //\r
+ // When reading data form disk directly, if some dirty data\r
+ // in cache is in this rang, this data in the Buffer need to\r
+ // be updated with the cache's dirty data.\r
+ //\r
+ if (IoMode == READ_DISK) {\r
+ if (CacheTag->Dirty) {\r
+ CopyMem (\r
+ Buffer + ((PageNo - StartPageNo) << PageAlignment),\r
+ BaseAddress + (GroupNo << PageAlignment),\r
+ PageSize\r
+ );\r
+ }\r
+ } else {\r
+ //\r
+ // Make all valid entries in this range invalid.\r
+ //\r
+ CacheTag->RealSize = 0;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatExchangeCachePage (\r
+ IN FAT_VOLUME *Volume,\r
+ IN CACHE_DATA_TYPE DataType,\r
+ IN IO_MODE IoMode,\r
+ IN CACHE_TAG *CacheTag,\r
+ IN FAT_TASK *Task\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Exchange the cache page with the image on the disk\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ DataType - Indicate the cache type.\r
+ IoMode - Indicate whether to load this page from disk or store this page to disk.\r
+ CacheTag - The Cache Tag for the current cache page.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Cache page exchanged successfully.\r
+ Others - An error occurred when exchanging cache page.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN GroupNo;\r
+ UINTN PageNo;\r
+ UINTN WriteCount;\r
+ UINTN RealSize;\r
+ UINT64 EntryPos;\r
+ UINT64 MaxSize;\r
+ DISK_CACHE *DiskCache;\r
+ VOID *PageAddress;\r
+ UINT8 PageAlignment;\r
+\r
+ DiskCache = &Volume->DiskCache[DataType];\r
+ PageNo = CacheTag->PageNo;\r
+ GroupNo = PageNo & DiskCache->GroupMask;\r
+ PageAlignment = DiskCache->PageAlignment;\r
+ PageAddress = DiskCache->CacheBase + (GroupNo << PageAlignment);\r
+ EntryPos = DiskCache->BaseAddress + LShiftU64 (PageNo, PageAlignment);\r
+ RealSize = CacheTag->RealSize;\r
+ if (IoMode == READ_DISK) {\r
+ RealSize = (UINTN)1 << PageAlignment;\r
+ MaxSize = DiskCache->LimitAddress - EntryPos;\r
+ if (MaxSize < RealSize) {\r
+ DEBUG ((EFI_D_INFO, "FatDiskIo: Cache Page OutBound occurred! \n"));\r
+ RealSize = (UINTN) MaxSize;\r
+ }\r
+ }\r
+\r
+ WriteCount = 1;\r
+ if (DataType == CACHE_FAT && IoMode == WRITE_DISK) {\r
+ WriteCount = Volume->NumFats;\r
+ }\r
+\r
+ do {\r
+ //\r
+ // Only fat table writing will execute more than once\r
+ //\r
+ Status = FatDiskIo (Volume, IoMode, EntryPos, RealSize, PageAddress, Task);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ EntryPos += Volume->FatSize;\r
+ } while (--WriteCount > 0);\r
+\r
+ CacheTag->Dirty = FALSE;\r
+ CacheTag->RealSize = RealSize;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatGetCachePage (\r
+ IN FAT_VOLUME *Volume,\r
+ IN CACHE_DATA_TYPE CacheDataType,\r
+ IN UINTN PageNo,\r
+ IN CACHE_TAG *CacheTag\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get one cache page by specified PageNo.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ CacheDataType - The cache type: CACHE_FAT or CACHE_DATA.\r
+ PageNo - PageNo to match with the cache.\r
+ CacheTag - The Cache Tag for the current cache page.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the cache page successfully.\r
+ other - An error occurred when accessing data.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN OldPageNo;\r
+\r
+ OldPageNo = CacheTag->PageNo;\r
+ if (CacheTag->RealSize > 0 && OldPageNo == PageNo) {\r
+ //\r
+ // Cache Hit occurred\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Write dirty cache page back to disk\r
+ //\r
+ if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
+ Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // Load new data from disk;\r
+ //\r
+ CacheTag->PageNo = PageNo;\r
+ Status = FatExchangeCachePage (Volume, CacheDataType, READ_DISK, CacheTag, NULL);\r
+\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatAccessUnalignedCachePage (\r
+ IN FAT_VOLUME *Volume,\r
+ IN CACHE_DATA_TYPE CacheDataType,\r
+ IN IO_MODE IoMode,\r
+ IN UINTN PageNo,\r
+ IN UINTN Offset,\r
+ IN UINTN Length,\r
+ IN OUT VOID *Buffer\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ Read Length bytes from the position of Offset into Buffer, or\r
+ write Length bytes from Buffer into the position of Offset.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
+ IoMode - Indicate the type of disk access.\r
+ PageNo - The number of unaligned cache page.\r
+ Offset - The starting byte of cache page.\r
+ Length - The number of bytes that is read or written\r
+ Buffer - Buffer containing cache data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The data was accessed correctly.\r
+ Others - An error occurred when accessing unaligned cache page.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *Source;\r
+ VOID *Destination;\r
+ DISK_CACHE *DiskCache;\r
+ CACHE_TAG *CacheTag;\r
+ UINTN GroupNo;\r
+\r
+ DiskCache = &Volume->DiskCache[CacheDataType];\r
+ GroupNo = PageNo & DiskCache->GroupMask;\r
+ CacheTag = &DiskCache->CacheTag[GroupNo];\r
+ Status = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag);\r
+ if (!EFI_ERROR (Status)) {\r
+ Source = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset;\r
+ Destination = Buffer;\r
+ if (IoMode != READ_DISK) {\r
+ CacheTag->Dirty = TRUE;\r
+ DiskCache->Dirty = TRUE;\r
+ Destination = Source;\r
+ Source = Buffer;\r
+ }\r
+\r
+ CopyMem (Destination, Source, Length);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatAccessCache (\r
+ IN FAT_VOLUME *Volume,\r
+ IN CACHE_DATA_TYPE CacheDataType,\r
+ IN IO_MODE IoMode,\r
+ IN UINT64 Offset,\r
+ IN UINTN BufferSize,\r
+ IN OUT UINT8 *Buffer,\r
+ IN FAT_TASK *Task\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ Read BufferSize bytes from the position of Offset into Buffer,\r
+ or write BufferSize bytes from Buffer into the position of Offset.\r
+\r
+ Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into\r
+ the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):\r
+\r
+ 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache\r
+ page hit, just return the cache page; else update the related cache page and return\r
+ the right cache page.\r
+ 2. Access of Data cache (CACHE_DATA):\r
+ The access data will be divided into UnderRun data, Aligned data and OverRun data;\r
+ The UnderRun data and OverRun data will be accessed by the Data cache,\r
+ but the Aligned data will be accessed with disk directly.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
+ IoMode - Indicate the type of disk access.\r
+ Offset - The starting byte offset to read from.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing cache data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The data was accessed correctly.\r
+ EFI_MEDIA_CHANGED - The MediaId does not match the current device.\r
+ Others - An error occurred when accessing cache.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN PageSize;\r
+ UINTN UnderRun;\r
+ UINTN OverRun;\r
+ UINTN AlignedSize;\r
+ UINTN Length;\r
+ UINTN PageNo;\r
+ UINTN AlignedPageCount;\r
+ UINTN OverRunPageNo;\r
+ DISK_CACHE *DiskCache;\r
+ UINT64 EntryPos;\r
+ UINT8 PageAlignment;\r
+\r
+ ASSERT (Volume->CacheBuffer != NULL);\r
+\r
+ Status = EFI_SUCCESS;\r
+ DiskCache = &Volume->DiskCache[CacheDataType];\r
+ EntryPos = Offset - DiskCache->BaseAddress;\r
+ PageAlignment = DiskCache->PageAlignment;\r
+ PageSize = (UINTN)1 << PageAlignment;\r
+ PageNo = (UINTN) RShiftU64 (EntryPos, PageAlignment);\r
+ UnderRun = ((UINTN) EntryPos) & (PageSize - 1);\r
+\r
+ if (UnderRun > 0) {\r
+ Length = PageSize - UnderRun;\r
+ if (Length > BufferSize) {\r
+ Length = BufferSize;\r
+ }\r
+\r
+ Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Buffer += Length;\r
+ BufferSize -= Length;\r
+ PageNo++;\r
+ }\r
+\r
+ AlignedPageCount = BufferSize >> PageAlignment;\r
+ OverRunPageNo = PageNo + AlignedPageCount;\r
+ //\r
+ // The access of the Aligned data\r
+ //\r
+ if (AlignedPageCount > 0) {\r
+ //\r
+ // Accessing fat table cannot have alignment data\r
+ //\r
+ ASSERT (CacheDataType == CACHE_DATA);\r
+\r
+ EntryPos = Volume->RootPos + LShiftU64 (PageNo, PageAlignment);\r
+ AlignedSize = AlignedPageCount << PageAlignment;\r
+ Status = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer, Task);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // If these access data over laps the relative cache range, these cache pages need\r
+ // to be updated.\r
+ //\r
+ FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer);\r
+ Buffer += AlignedSize;\r
+ BufferSize -= AlignedSize;\r
+ }\r
+ //\r
+ // The access of the OverRun data\r
+ //\r
+ OverRun = BufferSize;\r
+ if (OverRun > 0) {\r
+ //\r
+ // Last read is not a complete page\r
+ //\r
+ Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatVolumeFlushCache (\r
+ IN FAT_VOLUME *Volume,\r
+ IN FAT_TASK *Task\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Flush all the dirty cache back, include the FAT cache and the Data cache.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Flush all the dirty cache back successfully\r
+ other - An error occurred when writing the data into the disk\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ CACHE_DATA_TYPE CacheDataType;\r
+ UINTN GroupIndex;\r
+ UINTN GroupMask;\r
+ DISK_CACHE *DiskCache;\r
+ CACHE_TAG *CacheTag;\r
+\r
+ for (CacheDataType = (CACHE_DATA_TYPE) 0; CacheDataType < CACHE_MAX_TYPE; CacheDataType++) {\r
+ DiskCache = &Volume->DiskCache[CacheDataType];\r
+ if (DiskCache->Dirty) {\r
+ //\r
+ // Data cache or fat cache is dirty, write the dirty data back\r
+ //\r
+ GroupMask = DiskCache->GroupMask;\r
+ for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) {\r
+ CacheTag = &DiskCache->CacheTag[GroupIndex];\r
+ if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
+ //\r
+ // Write back all Dirty Data Cache Page to disk\r
+ //\r
+ Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag, Task);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ DiskCache->Dirty = FALSE;\r
+ }\r
+ }\r
+ //\r
+ // Flush the block device.\r
+ //\r
+ Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatInitializeDiskCache (\r
+ IN FAT_VOLUME *Volume\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Initialize the disk cache according to Volume's FatType.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The disk cache is successfully initialized.\r
+ EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.\r
+\r
+--*/\r
+{\r
+ DISK_CACHE *DiskCache;\r
+ UINTN FatCacheGroupCount;\r
+ UINTN DataCacheSize;\r
+ UINTN FatCacheSize;\r
+ UINT8 *CacheBuffer;\r
+\r
+ DiskCache = Volume->DiskCache;\r
+ //\r
+ // Configure the parameters of disk cache\r
+ //\r
+ if (Volume->FatType == FAT12) {\r
+ FatCacheGroupCount = FAT_FATCACHE_GROUP_MIN_COUNT;\r
+ DiskCache[CACHE_FAT].PageAlignment = FAT_FATCACHE_PAGE_MIN_ALIGNMENT;\r
+ DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT;\r
+ } else {\r
+ FatCacheGroupCount = FAT_FATCACHE_GROUP_MAX_COUNT;\r
+ DiskCache[CACHE_FAT].PageAlignment = FAT_FATCACHE_PAGE_MAX_ALIGNMENT;\r
+ DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT;\r
+ }\r
+\r
+ DiskCache[CACHE_DATA].GroupMask = FAT_DATACACHE_GROUP_COUNT - 1;\r
+ DiskCache[CACHE_DATA].BaseAddress = Volume->RootPos;\r
+ DiskCache[CACHE_DATA].LimitAddress = Volume->VolumeSize;\r
+ DiskCache[CACHE_FAT].GroupMask = FatCacheGroupCount - 1;\r
+ DiskCache[CACHE_FAT].BaseAddress = Volume->FatPos;\r
+ DiskCache[CACHE_FAT].LimitAddress = Volume->FatPos + Volume->FatSize;\r
+ FatCacheSize = FatCacheGroupCount << DiskCache[CACHE_FAT].PageAlignment;\r
+ DataCacheSize = FAT_DATACACHE_GROUP_COUNT << DiskCache[CACHE_DATA].PageAlignment;\r
+ //\r
+ // Allocate the Fat Cache buffer\r
+ //\r
+ CacheBuffer = AllocateZeroPool (FatCacheSize + DataCacheSize);\r
+ if (CacheBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Volume->CacheBuffer = CacheBuffer;\r
+ DiskCache[CACHE_FAT].CacheBase = CacheBuffer;\r
+ DiskCache[CACHE_DATA].CacheBase = CacheBuffer + FatCacheSize;\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Fat.c\r
+\r
+Abstract:\r
+\r
+ Fat File System driver routines that support EFI driver model\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatUnload (\r
+ IN EFI_HANDLE ImageHandle\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+//\r
+// DriverBinding protocol instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gFatDriverBinding = {\r
+ FatDriverBindingSupported,\r
+ FatDriverBindingStart,\r
+ FatDriverBindingStop,\r
+ 0xa,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Register Driver Binding protocol for this driver.\r
+\r
+Arguments:\r
+\r
+ ImageHandle - Handle for the image of this driver.\r
+ SystemTable - Pointer to the EFI System Table.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Driver loaded.\r
+ other - Driver not loaded.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Initialize the EFI Driver Library\r
+ //\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gFatDriverBinding,\r
+ ImageHandle,\r
+ &gFatComponentName,\r
+ &gFatComponentName2\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatUnload (\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Unload function for this image. Uninstall DriverBinding protocol.\r
+\r
+Arguments:\r
+\r
+ ImageHandle - Handle for the image of this driver.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Driver unloaded successfully.\r
+ other - Driver can not unloaded.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *DeviceHandleBuffer;\r
+ UINTN DeviceHandleCount;\r
+ UINTN Index;\r
+ VOID *ComponentName;\r
+ VOID *ComponentName2;\r
+\r
+ Status = gBS->LocateHandleBuffer (\r
+ AllHandles,\r
+ NULL,\r
+ NULL,\r
+ &DeviceHandleCount,\r
+ &DeviceHandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ for (Index = 0; Index < DeviceHandleCount; Index++) {\r
+ Status = EfiTestManagedDevice (DeviceHandleBuffer[Index], ImageHandle, &gEfiDiskIoProtocolGuid);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gBS->DisconnectController (\r
+ DeviceHandleBuffer[Index],\r
+ ImageHandle,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (Index == DeviceHandleCount) {\r
+ //\r
+ // Driver is stopped successfully.\r
+ //\r
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentNameProtocolGuid, &ComponentName);\r
+ if (EFI_ERROR (Status)) {\r
+ ComponentName = NULL;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentName2ProtocolGuid, &ComponentName2);\r
+ if (EFI_ERROR (Status)) {\r
+ ComponentName2 = NULL;\r
+ }\r
+\r
+ if (ComponentName == NULL) {\r
+ if (ComponentName2 == NULL) {\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ImageHandle,\r
+ &gEfiDriverBindingProtocolGuid, &gFatDriverBinding,\r
+ NULL\r
+ );\r
+ } else {\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ImageHandle,\r
+ &gEfiDriverBindingProtocolGuid, &gFatDriverBinding,\r
+ &gEfiComponentName2ProtocolGuid, ComponentName2,\r
+ NULL\r
+ );\r
+ }\r
+ } else {\r
+ if (ComponentName2 == NULL) {\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ImageHandle,\r
+ &gEfiDriverBindingProtocolGuid, &gFatDriverBinding,\r
+ &gEfiComponentNameProtocolGuid, ComponentName,\r
+ NULL\r
+ );\r
+ } else {\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ImageHandle,\r
+ &gEfiDriverBindingProtocolGuid, &gFatDriverBinding,\r
+ &gEfiComponentNameProtocolGuid, ComponentName,\r
+ &gEfiComponentName2ProtocolGuid, ComponentName2,\r
+ NULL\r
+ );\r
+ }\r
+ }\r
+ }\r
+\r
+ if (DeviceHandleBuffer != NULL) {\r
+ FreePool (DeviceHandleBuffer);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Test to see if this driver can add a file system to ControllerHandle.\r
+ ControllerHandle must support both Disk IO and Block IO protocols.\r
+\r
+Arguments:\r
+\r
+ This - Protocol instance pointer.\r
+ ControllerHandle - Handle of device to test.\r
+ RemainingDevicePath - Not used.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - This driver supports this device.\r
+ EFI_ALREADY_STARTED - This driver is already running on this device.\r
+ other - This driver does not support this device.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ (VOID **) &DiskIo,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Close the I/O Abstraction(s) used to perform the supported test\r
+ //\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+\r
+ //\r
+ // Open the IO Abstraction(s) needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Start this driver on ControllerHandle by opening a Block IO and Disk IO\r
+ protocol, reading Device Path. Add a Simple File System protocol to\r
+ ControllerHandle if the media contains a valid file system.\r
+\r
+Arguments:\r
+\r
+ This - Protocol instance pointer.\r
+ ControllerHandle - Handle of device to bind driver to.\r
+ RemainingDevicePath - Not used.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - This driver is added to DeviceHandle.\r
+ EFI_ALREADY_STARTED - This driver is already running on DeviceHandle.\r
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory.\r
+ other - This driver does not support this device.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;\r
+ BOOLEAN LockedByMe;\r
+\r
+ LockedByMe = FALSE;\r
+ //\r
+ // Acquire the lock.\r
+ // If caller has already acquired the lock, cannot lock it again.\r
+ //\r
+ Status = FatAcquireLockOrFail ();\r
+ if (!EFI_ERROR (Status)) {\r
+ LockedByMe = TRUE;\r
+ }\r
+\r
+ Status = InitializeUnicodeCollationSupport (This->DriverBindingHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ //\r
+ // Open our required BlockIo and DiskIo\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ (VOID **) &DiskIo,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIo2ProtocolGuid,\r
+ (VOID **) &DiskIo2,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DiskIo2 = NULL;\r
+ }\r
+\r
+ //\r
+ // Allocate Volume structure. In FatAllocateVolume(), Resources\r
+ // are allocated with protocol installed and cached initialized\r
+ //\r
+ Status = FatAllocateVolume (ControllerHandle, DiskIo, DiskIo2, BlockIo);\r
+\r
+ //\r
+ // When the media changes on a device it will Reinstall the BlockIo interaface.\r
+ // This will cause a call to our Stop(), and a subsequent reentrant call to our\r
+ // Start() successfully. We should leave the device open when this happen.\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ NULL,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+ gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIo2ProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+ }\r
+ }\r
+\r
+Exit:\r
+ //\r
+ // Unlock if locked by myself.\r
+ //\r
+ if (LockedByMe) {\r
+ FatReleaseLock ();\r
+ }\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Stop this driver on ControllerHandle.\r
+\r
+Arguments:\r
+ This - Protocol instance pointer.\r
+ ControllerHandle - Handle of device to stop driver on.\r
+ NumberOfChildren - Not used.\r
+ ChildHandleBuffer - Not used.\r
+\r
+Returns:\r
+ EFI_SUCCESS - This driver is removed DeviceHandle.\r
+ other - This driver was not removed from this device.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;\r
+ FAT_VOLUME *Volume;\r
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;\r
+\r
+ DiskIo2 = NULL;\r
+ //\r
+ // Get our context back\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ControllerHandle,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ (VOID **) &FileSystem,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Volume = VOLUME_FROM_VOL_INTERFACE (FileSystem);\r
+ DiskIo2 = Volume->DiskIo2;\r
+ Status = FatAbandonVolume (Volume);\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ if (DiskIo2 != NULL) {\r
+ Status = gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIo2ProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ Status = gBS->CloseProtocol (\r
+ ControllerHandle,\r
+ &gEfiDiskIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ ControllerHandle\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Fat.h\r
+\r
+Abstract:\r
+\r
+ Main header file for EFI FAT file system driver\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#ifndef _FAT_H_\r
+#define _FAT_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/FileSystemInfo.h>\r
+#include <Guid/FileSystemVolumeLabelInfo.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/DiskIo.h>\r
+#include <Protocol/DiskIo2.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/UnicodeCollation.h>\r
+\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+\r
+#include "FatFileSystem.h"\r
+\r
+//\r
+// The FAT signature\r
+//\r
+#define FAT_VOLUME_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'v')\r
+#define FAT_IFILE_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'i')\r
+#define FAT_ODIR_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'd')\r
+#define FAT_DIRENT_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'e')\r
+#define FAT_OFILE_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'o')\r
+#define FAT_TASK_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'T')\r
+#define FAT_SUBTASK_SIGNATURE SIGNATURE_32 ('f', 'a', 't', 'S')\r
+\r
+#define ASSERT_VOLUME_LOCKED(a) ASSERT_LOCKED (&FatFsLock)\r
+\r
+#define IFILE_FROM_FHAND(a) CR (a, FAT_IFILE, Handle, FAT_IFILE_SIGNATURE)\r
+\r
+#define DIRENT_FROM_LINK(a) CR (a, FAT_DIRENT, Link, FAT_DIRENT_SIGNATURE)\r
+\r
+#define VOLUME_FROM_ROOT_DIRENT(a) CR (a, FAT_VOLUME, RootDirEnt, FAT_VOLUME_SIGNATURE)\r
+\r
+#define VOLUME_FROM_VOL_INTERFACE(a) CR (a, FAT_VOLUME, VolumeInterface, FAT_VOLUME_SIGNATURE);\r
+\r
+#define ODIR_FROM_DIRCACHELINK(a) CR (a, FAT_ODIR, DirCacheLink, FAT_ODIR_SIGNATURE)\r
+\r
+#define OFILE_FROM_CHECKLINK(a) CR (a, FAT_OFILE, CheckLink, FAT_OFILE_SIGNATURE)\r
+\r
+#define OFILE_FROM_CHILDLINK(a) CR (a, FAT_OFILE, ChildLink, FAT_OFILE_SIGNATURE)\r
+\r
+//\r
+// Minimum sector size is 512B, Maximum sector size is 4096B\r
+// Max sectors per cluster is 128\r
+//\r
+#define MAX_BLOCK_ALIGNMENT 12\r
+#define MIN_BLOCK_ALIGNMENT 9\r
+#define MAX_SECTORS_PER_CLUSTER_ALIGNMENT 7\r
+\r
+//\r
+// Efi Time Definition\r
+//\r
+#define IS_LEAP_YEAR(a) (((a) % 4 == 0) && (((a) % 100 != 0) || ((a) % 400 == 0)))\r
+\r
+//\r
+// Minimum fat page size is 8K, maximum fat page alignment is 32K\r
+// Minimum data page size is 8K, maximum fat page alignment is 64K\r
+//\r
+#define FAT_FATCACHE_PAGE_MIN_ALIGNMENT 13\r
+#define FAT_FATCACHE_PAGE_MAX_ALIGNMENT 15\r
+#define FAT_DATACACHE_PAGE_MIN_ALIGNMENT 13\r
+#define FAT_DATACACHE_PAGE_MAX_ALIGNMENT 16\r
+#define FAT_DATACACHE_GROUP_COUNT 64\r
+#define FAT_FATCACHE_GROUP_MIN_COUNT 1\r
+#define FAT_FATCACHE_GROUP_MAX_COUNT 16\r
+\r
+//\r
+// Used in 8.3 generation algorithm\r
+//\r
+#define MAX_SPEC_RETRY 4\r
+#define SPEC_BASE_TAG_LEN 6\r
+#define HASH_BASE_TAG_LEN 2\r
+#define HASH_VALUE_TAG_LEN (SPEC_BASE_TAG_LEN - HASH_BASE_TAG_LEN)\r
+\r
+//\r
+// Path name separator is back slash\r
+//\r
+#define PATH_NAME_SEPARATOR L'\\'\r
+\r
+\r
+#define EFI_PATH_STRING_LENGTH 260\r
+#define EFI_FILE_STRING_LENGTH 255\r
+#define FAT_MAX_ALLOCATE_SIZE 0xA00000\r
+#define LC_ISO_639_2_ENTRY_SIZE 3\r
+#define MAX_LANG_CODE_SIZE 100\r
+\r
+#define FAT_MAX_DIR_CACHE_COUNT 8\r
+#define FAT_MAX_DIRENTRY_COUNT 0xFFFF\r
+typedef CHAR8 LC_ISO_639_2;\r
+\r
+//\r
+// The fat types we support\r
+//\r
+typedef enum {\r
+ FAT12,\r
+ FAT16,\r
+ FAT32,\r
+ FatUndefined\r
+} FAT_VOLUME_TYPE;\r
+\r
+typedef enum {\r
+ CACHE_FAT,\r
+ CACHE_DATA,\r
+ CACHE_MAX_TYPE\r
+} CACHE_DATA_TYPE;\r
+\r
+//\r
+// Used in FatDiskIo\r
+//\r
+typedef enum {\r
+ READ_DISK = 0, // raw disk read\r
+ WRITE_DISK = 1, // raw disk write\r
+ READ_FAT = 2, // read fat cache\r
+ WRITE_FAT = 3, // write fat cache\r
+ READ_DATA = 6, // read data cache\r
+ WRITE_DATA = 7 // write data cache\r
+} IO_MODE;\r
+\r
+#define CACHE_ENABLED(a) ((a) >= 2)\r
+#define RAW_ACCESS(a) ((IO_MODE)((a) & 0x1))\r
+#define CACHE_TYPE(a) ((CACHE_DATA_TYPE)((a) >> 2))\r
+\r
+//\r
+// Disk cache tag\r
+//\r
+typedef struct {\r
+ UINTN PageNo;\r
+ UINTN RealSize;\r
+ BOOLEAN Dirty;\r
+} CACHE_TAG;\r
+\r
+typedef struct {\r
+ UINT64 BaseAddress;\r
+ UINT64 LimitAddress;\r
+ UINT8 *CacheBase;\r
+ BOOLEAN Dirty;\r
+ UINT8 PageAlignment;\r
+ UINTN GroupMask;\r
+ CACHE_TAG CacheTag[FAT_DATACACHE_GROUP_COUNT];\r
+} DISK_CACHE;\r
+\r
+//\r
+// Hash table size\r
+//\r
+#define HASH_TABLE_SIZE 0x400\r
+#define HASH_TABLE_MASK (HASH_TABLE_SIZE - 1)\r
+\r
+//\r
+// The directory entry for opened directory\r
+//\r
+typedef struct _FAT_DIRENT {\r
+ UINTN Signature;\r
+ UINT16 EntryPos; // The position of this directory entry in the parent directory file\r
+ UINT8 EntryCount; // The count of the directory entry in the parent directory file\r
+ BOOLEAN Invalid; // Indicate whether this directory entry is valid\r
+ CHAR16 *FileString; // The unicode long file name for this directory entry\r
+ struct _FAT_OFILE *OFile; // The OFile of the corresponding directory entry\r
+ struct _FAT_DIRENT *ShortNameForwardLink; // Hash successor link for short filename\r
+ struct _FAT_DIRENT *LongNameForwardLink; // Hash successor link for long filename\r
+ LIST_ENTRY Link; // Connection of every directory entry\r
+ FAT_DIRECTORY_ENTRY Entry; // The physical directory entry stored in disk\r
+} FAT_DIRENT;\r
+\r
+typedef struct _FAT_ODIR {\r
+ UINTN Signature;\r
+ UINT32 CurrentEndPos; // Current end position of the directory\r
+ UINT32 CurrentPos; // Current position of the directory\r
+ LIST_ENTRY *CurrentCursor; // Current directory entry pointer\r
+ LIST_ENTRY ChildList; // List of all directory entries\r
+ BOOLEAN EndOfDir; // Indicate whether we have reached the end of the directory\r
+ LIST_ENTRY DirCacheLink; // Linked in Volume->DirCacheList when discarded\r
+ UINTN DirCacheTag; // The identification of the directory when in directory cache\r
+ FAT_DIRENT *LongNameHashTable[HASH_TABLE_SIZE];\r
+ FAT_DIRENT *ShortNameHashTable[HASH_TABLE_SIZE];\r
+} FAT_ODIR;\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_FILE_PROTOCOL Handle;\r
+ UINT64 Position;\r
+ BOOLEAN ReadOnly;\r
+ struct _FAT_OFILE *OFile;\r
+ LIST_ENTRY Tasks; // List of all FAT_TASKs\r
+ LIST_ENTRY Link; // Link to other IFiles\r
+} FAT_IFILE;\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_FILE_IO_TOKEN *FileIoToken;\r
+ FAT_IFILE *IFile;\r
+ LIST_ENTRY Subtasks; // List of all FAT_SUBTASKs\r
+ LIST_ENTRY Link; // Link to other FAT_TASKs\r
+} FAT_TASK;\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_DISK_IO2_TOKEN DiskIo2Token;\r
+ FAT_TASK *Task;\r
+ BOOLEAN Write;\r
+ UINT64 Offset;\r
+ VOID *Buffer;\r
+ UINTN BufferSize;\r
+ LIST_ENTRY Link;\r
+} FAT_SUBTASK;\r
+\r
+//\r
+// FAT_OFILE - Each opened file\r
+//\r
+typedef struct _FAT_OFILE {\r
+ UINTN Signature;\r
+ struct _FAT_VOLUME *Volume;\r
+ //\r
+ // A permanant error code to return to all accesses to\r
+ // this opened file\r
+ //\r
+ EFI_STATUS Error;\r
+ //\r
+ // A list of the IFILE instances for this OFile\r
+ //\r
+ LIST_ENTRY Opens;\r
+\r
+ //\r
+ // The dynamic infomation\r
+ //\r
+ UINTN FileSize;\r
+ UINTN FileCluster;\r
+ UINTN FileCurrentCluster;\r
+ UINTN FileLastCluster;\r
+\r
+ //\r
+ // Dirty is set if there have been any updates to the\r
+ // file\r
+ // Archive is set if the archive attribute in the file's\r
+ // directory entry needs to be set when performing flush\r
+ // PreserveLastMod is set if the last modification of the\r
+ // file is specified by SetInfo API\r
+ //\r
+ BOOLEAN Dirty;\r
+ BOOLEAN IsFixedRootDir;\r
+ BOOLEAN PreserveLastModification;\r
+ BOOLEAN Archive;\r
+ //\r
+ // Set by an OFile SetPosition\r
+ //\r
+ UINTN Position; // within file\r
+ UINT64 PosDisk; // on the disk\r
+ UINTN PosRem; // remaining in this disk run\r
+ //\r
+ // The opened parent, full path length and currently opened child files\r
+ //\r
+ struct _FAT_OFILE *Parent;\r
+ UINTN FullPathLen;\r
+ LIST_ENTRY ChildHead;\r
+ LIST_ENTRY ChildLink;\r
+\r
+ //\r
+ // The opened directory structure for a directory; if this\r
+ // OFile represents a file, then ODir = NULL\r
+ //\r
+ FAT_ODIR *ODir;\r
+ //\r
+ // The directory entry for the Ofile\r
+ //\r
+ FAT_DIRENT *DirEnt;\r
+\r
+ //\r
+ // Link in Volume's reference list\r
+ //\r
+ LIST_ENTRY CheckLink;\r
+} FAT_OFILE;\r
+\r
+typedef struct _FAT_VOLUME {\r
+ UINTN Signature;\r
+\r
+ EFI_HANDLE Handle;\r
+ BOOLEAN Valid;\r
+ BOOLEAN DiskError;\r
+\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL VolumeInterface;\r
+\r
+ //\r
+ // If opened, the parent handle and BlockIo interface\r
+ //\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ EFI_DISK_IO2_PROTOCOL *DiskIo2;\r
+ UINT32 MediaId;\r
+ BOOLEAN ReadOnly;\r
+\r
+ //\r
+ // Computed values from fat bpb info\r
+ //\r
+ UINT64 VolumeSize;\r
+ UINT64 FatPos; // Disk pos of fat tables\r
+ UINT64 RootPos; // Disk pos of root directory\r
+ UINT64 FirstClusterPos; // Disk pos of first cluster\r
+ UINTN FatSize; // Number of bytes in each fat\r
+ UINTN MaxCluster; // Max cluster number\r
+ UINTN ClusterSize; // Cluster size of fat partition\r
+ UINT8 ClusterAlignment; // Equal to log_2 (clustersize);\r
+ FAT_VOLUME_TYPE FatType;\r
+\r
+ //\r
+ // Current part of fat table that's present\r
+ //\r
+ UINT64 FatEntryPos; // Location of buffer\r
+ UINTN FatEntrySize; // Size of buffer\r
+ UINT32 FatEntryBuffer; // The buffer\r
+ FAT_INFO_SECTOR FatInfoSector; // Free cluster info\r
+ UINTN FreeInfoPos; // Pos with the free cluster info\r
+ BOOLEAN FreeInfoValid; // If free cluster info is valid\r
+ //\r
+ // Unpacked Fat BPB info\r
+ //\r
+ UINTN NumFats;\r
+ UINTN RootEntries; // < FAT32, root dir is fixed size\r
+ UINTN RootCluster; // >= FAT32, root cluster chain head\r
+ //\r
+ // info for marking the volume dirty or not\r
+ //\r
+ BOOLEAN FatDirty; // If fat-entries have been updated\r
+ UINT32 DirtyValue;\r
+ UINT32 NotDirtyValue;\r
+\r
+ //\r
+ // The root directory entry and opened root file\r
+ //\r
+ FAT_DIRENT RootDirEnt;\r
+ //\r
+ // File Name of root OFile, it is empty string\r
+ //\r
+ CHAR16 RootFileString[1];\r
+ struct _FAT_OFILE *Root;\r
+\r
+ //\r
+ // New OFiles are added to this list so they\r
+ // can be cleaned up if they aren't referenced.\r
+ //\r
+ LIST_ENTRY CheckRef;\r
+\r
+ //\r
+ // Directory cache List\r
+ //\r
+ LIST_ENTRY DirCacheList;\r
+ UINTN DirCacheCount;\r
+\r
+ //\r
+ // Disk Cache for this volume\r
+ //\r
+ VOID *CacheBuffer;\r
+ DISK_CACHE DiskCache[CACHE_MAX_TYPE];\r
+} FAT_VOLUME;\r
+\r
+//\r
+// Function Prototypes\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+FatOpen (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ OUT EFI_FILE_PROTOCOL **NewHandle,\r
+ IN CHAR16 *FileName,\r
+ IN UINT64 OpenMode,\r
+ IN UINT64 Attributes\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ Implements Open() of Simple File System Protocol.\r
+\r
+Arguments:\r
+\r
+ FHand - File handle of the file serves as a starting reference point.\r
+ NewHandle - Handle of the file that is newly opened.\r
+ FileName - File name relative to FHand.\r
+ OpenMode - Open mode.\r
+ Attributes - Attributes to set if the file is created.\r
+\r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.\r
+ The OpenMode is not supported.\r
+ The Attributes is not the valid attributes.\r
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string.\r
+ EFI_SUCCESS - Open the file successfully.\r
+ Others - The status of open file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatOpenEx (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ OUT EFI_FILE_PROTOCOL **NewHandle,\r
+ IN CHAR16 *FileName,\r
+ IN UINT64 OpenMode,\r
+ IN UINT64 Attributes,\r
+ IN OUT EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ Implements OpenEx() of Simple File System Protocol.\r
+\r
+Arguments:\r
+\r
+ FHand - File handle of the file serves as a starting reference point.\r
+ NewHandle - Handle of the file that is newly opened.\r
+ FileName - File name relative to FHand.\r
+ OpenMode - Open mode.\r
+ Attributes - Attributes to set if the file is created.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.\r
+ The OpenMode is not supported.\r
+ The Attributes is not the valid attributes.\r
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string.\r
+ EFI_SUCCESS - Open the file successfully.\r
+ Others - The status of open file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatGetPosition (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ OUT UINT64 *Position\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file's position of the file\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file.\r
+ Position - The file's position of the file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_UNSUPPORTED - The open file is not a file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatGetInfo (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN EFI_GUID *Type,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the some types info of the file into Buffer\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file.\r
+ Type - The type of the info.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatSetInfo (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN EFI_GUID *Type,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the some types info of the file into Buffer\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file.\r
+ Type - The type of the info.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatFlush (\r
+ IN EFI_FILE_PROTOCOL *FHand\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Flushes all data associated with the file handle\r
+\r
+Arguments:\r
+\r
+ FHand - Handle to file to flush\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Flushed the file successfully\r
+ EFI_WRITE_PROTECTED - The volume is read only\r
+ EFI_ACCESS_DENIED - The volume is not read only\r
+ but the file is read only\r
+ Others - Flushing of the file is failed\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatFlushEx (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Flushes all data associated with the file handle.\r
+\r
+Arguments:\r
+\r
+ FHand - Handle to file to flush.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Flushed the file successfully.\r
+ EFI_WRITE_PROTECTED - The volume is read only.\r
+ EFI_ACCESS_DENIED - The file is read only.\r
+ Others - Flushing of the file failed.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatClose (\r
+ IN EFI_FILE_PROTOCOL *FHand\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Flushes & Closes the file handle.\r
+\r
+Arguments:\r
+\r
+ FHand - Handle to the file to delete.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Closed the file successfully.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatDelete (\r
+ IN EFI_FILE_PROTOCOL *FHand\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Deletes the file & Closes the file handle.\r
+\r
+Arguments:\r
+\r
+ FHand - Handle to the file to delete.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Delete the file successfully.\r
+ EFI_WARN_DELETE_FAILURE - Fail to delete the file.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatSetPosition (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN UINT64 Position\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the file's position of the file\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file\r
+ Position - The file's position of the file\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the info successfully\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file\r
+ EFI_UNSUPPORTED - Set a directory with a not-zero position\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatRead (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing read data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatReadEx (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN OUT EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatWrite (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the file info.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing write data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the file info successfully.\r
+ EFI_WRITE_PROTECTED - The disk is write protected.\r
+ EFI_ACCESS_DENIED - The file is read-only.\r
+ EFI_DEVICE_ERROR - The OFile is not valid.\r
+ EFI_UNSUPPORTED - The open file is not a file.\r
+ - The writing file size is larger than 4GB.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+;\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatWriteEx (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN OUT EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+;\r
+\r
+//\r
+// DiskCache.c\r
+//\r
+EFI_STATUS\r
+FatInitializeDiskCache (\r
+ IN FAT_VOLUME *Volume\r
+ );\r
+\r
+EFI_STATUS\r
+FatAccessCache (\r
+ IN FAT_VOLUME *Volume,\r
+ IN CACHE_DATA_TYPE CacheDataType,\r
+ IN IO_MODE IoMode,\r
+ IN UINT64 Offset,\r
+ IN UINTN BufferSize,\r
+ IN OUT UINT8 *Buffer,\r
+ IN FAT_TASK *Task\r
+ );\r
+\r
+EFI_STATUS\r
+FatVolumeFlushCache (\r
+ IN FAT_VOLUME *Volume,\r
+ IN FAT_TASK *Task\r
+ );\r
+\r
+//\r
+// Flush.c\r
+//\r
+EFI_STATUS\r
+FatOFileFlush (\r
+ IN FAT_OFILE *OFile\r
+ );\r
+\r
+BOOLEAN\r
+FatCheckOFileRef (\r
+ IN FAT_OFILE *OFile\r
+ );\r
+\r
+VOID\r
+FatSetVolumeError (\r
+ IN FAT_OFILE *OFile,\r
+ IN EFI_STATUS Status\r
+ );\r
+\r
+EFI_STATUS\r
+FatIFileClose (\r
+ FAT_IFILE *IFile\r
+ );\r
+\r
+EFI_STATUS\r
+FatCleanupVolume (\r
+ IN FAT_VOLUME *Volume,\r
+ IN FAT_OFILE *OFile,\r
+ IN EFI_STATUS EfiStatus,\r
+ IN FAT_TASK *Task\r
+ );\r
+\r
+//\r
+// FileSpace.c\r
+//\r
+EFI_STATUS\r
+FatShrinkEof (\r
+ IN FAT_OFILE *OFile\r
+ );\r
+\r
+EFI_STATUS\r
+FatGrowEof (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINT64 NewSizeInBytes\r
+ );\r
+\r
+UINTN\r
+FatPhysicalDirSize (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN Cluster\r
+ );\r
+\r
+UINT64\r
+FatPhysicalFileSize (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN RealSize\r
+ );\r
+\r
+EFI_STATUS\r
+FatOFilePosition (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINTN Position,\r
+ IN UINTN PosLimit\r
+ );\r
+\r
+VOID\r
+FatComputeFreeInfo (\r
+ IN FAT_VOLUME *Volume\r
+ );\r
+\r
+//\r
+// Init.c\r
+//\r
+EFI_STATUS\r
+FatAllocateVolume (\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo\r
+ );\r
+\r
+EFI_STATUS\r
+FatOpenDevice (\r
+ IN OUT FAT_VOLUME *Volume\r
+ );\r
+\r
+EFI_STATUS\r
+FatAbandonVolume (\r
+ IN FAT_VOLUME *Volume\r
+ );\r
+\r
+//\r
+// Misc.c\r
+//\r
+FAT_TASK *\r
+FatCreateTask (\r
+ FAT_IFILE *IFile,\r
+ EFI_FILE_IO_TOKEN *Token\r
+ );\r
+\r
+VOID\r
+FatDestroyTask (\r
+ FAT_TASK *Task\r
+ );\r
+\r
+VOID\r
+FatWaitNonblockingTask (\r
+ FAT_IFILE *IFile\r
+ );\r
+\r
+LIST_ENTRY *\r
+FatDestroySubtask (\r
+ FAT_SUBTASK *Subtask\r
+ );\r
+\r
+EFI_STATUS\r
+FatQueueTask (\r
+ IN FAT_IFILE *IFile,\r
+ IN FAT_TASK *Task\r
+ );\r
+\r
+EFI_STATUS\r
+FatAccessVolumeDirty (\r
+ IN FAT_VOLUME *Volume,\r
+ IN IO_MODE IoMode,\r
+ IN VOID *DirtyValue\r
+ );\r
+\r
+EFI_STATUS\r
+FatDiskIo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN IO_MODE IoMode,\r
+ IN UINT64 Offset,\r
+ IN UINTN BufferSize,\r
+ IN OUT VOID *Buffer,\r
+ IN FAT_TASK *Task\r
+ );\r
+\r
+VOID\r
+FatAcquireLock (\r
+ VOID\r
+ );\r
+\r
+VOID\r
+FatReleaseLock (\r
+ VOID\r
+ );\r
+\r
+EFI_STATUS\r
+FatAcquireLockOrFail (\r
+ VOID\r
+ );\r
+\r
+VOID\r
+FatFreeDirEnt (\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+VOID\r
+FatFreeVolume (\r
+ IN FAT_VOLUME *Volume\r
+ );\r
+\r
+VOID\r
+FatEfiTimeToFatTime (\r
+ IN EFI_TIME *ETime,\r
+ OUT FAT_DATE_TIME *FTime\r
+ );\r
+\r
+VOID\r
+FatFatTimeToEfiTime (\r
+ IN FAT_DATE_TIME *FTime,\r
+ OUT EFI_TIME *ETime\r
+ );\r
+\r
+VOID\r
+FatGetCurrentFatTime (\r
+ OUT FAT_DATE_TIME *FatTime\r
+ );\r
+\r
+BOOLEAN\r
+FatIsValidTime (\r
+ IN EFI_TIME *Time\r
+ );\r
+\r
+//\r
+// UnicodeCollation.c\r
+//\r
+EFI_STATUS\r
+InitializeUnicodeCollationSupport (\r
+ IN EFI_HANDLE AgentHandle\r
+ );\r
+\r
+VOID\r
+FatFatToStr (\r
+ IN UINTN FatSize,\r
+ IN CHAR8 *Fat,\r
+ OUT CHAR16 *String\r
+ );\r
+\r
+BOOLEAN\r
+FatStrToFat (\r
+ IN CHAR16 *String,\r
+ IN UINTN FatSize,\r
+ OUT CHAR8 *Fat\r
+ );\r
+\r
+VOID\r
+FatStrLwr (\r
+ IN CHAR16 *Str\r
+ );\r
+\r
+VOID\r
+FatStrUpr (\r
+ IN CHAR16 *Str\r
+ );\r
+\r
+INTN\r
+FatStriCmp (\r
+ IN CHAR16 *Str1,\r
+ IN CHAR16 *Str2\r
+ );\r
+\r
+//\r
+// Open.c\r
+//\r
+EFI_STATUS\r
+FatOFileOpen (\r
+ IN FAT_OFILE *OFile,\r
+ OUT FAT_IFILE **NewIFile,\r
+ IN CHAR16 *FileName,\r
+ IN UINT64 OpenMode,\r
+ IN UINT8 Attributes\r
+ );\r
+\r
+EFI_STATUS\r
+FatAllocateIFile (\r
+ IN FAT_OFILE *OFile,\r
+ OUT FAT_IFILE **PtrIFile\r
+ );\r
+\r
+//\r
+// OpenVolume.c\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+FatOpenVolume (\r
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
+ OUT EFI_FILE_PROTOCOL **File\r
+ );\r
+\r
+//\r
+// ReadWrite.c\r
+//\r
+EFI_STATUS\r
+FatAccessOFile (\r
+ IN FAT_OFILE *OFile,\r
+ IN IO_MODE IoMode,\r
+ IN UINTN Position,\r
+ IN UINTN *DataBufferSize,\r
+ IN UINT8 *UserBuffer,\r
+ IN FAT_TASK *Task\r
+ );\r
+\r
+EFI_STATUS\r
+FatExpandOFile (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINT64 ExpandedSize\r
+ );\r
+\r
+EFI_STATUS\r
+FatWriteZeroPool (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINTN WritePos\r
+ );\r
+\r
+EFI_STATUS\r
+FatTruncateOFile (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINTN TruncatedSize\r
+ );\r
+\r
+//\r
+// DirectoryManage.c\r
+//\r
+VOID\r
+FatResetODirCursor (\r
+ IN FAT_OFILE *OFile\r
+ );\r
+\r
+EFI_STATUS\r
+FatGetNextDirEnt (\r
+ IN FAT_OFILE *OFILE,\r
+ OUT FAT_DIRENT **PtrDirEnt\r
+ );\r
+\r
+EFI_STATUS\r
+FatRemoveDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+EFI_STATUS\r
+FatStoreDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+EFI_STATUS\r
+FatCreateDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ IN CHAR16 *FileName,\r
+ IN UINT8 Attributes,\r
+ OUT FAT_DIRENT **PtrDirEnt\r
+ );\r
+\r
+BOOLEAN\r
+FatIsDotDirEnt (\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+VOID\r
+FatUpdateDirEntClusterSizeInfo (\r
+ IN FAT_OFILE *OFile\r
+ );\r
+\r
+VOID\r
+FatCloneDirEnt (\r
+ IN FAT_DIRENT *DirEnt1,\r
+ IN FAT_DIRENT *DirEnt2\r
+ );\r
+\r
+EFI_STATUS\r
+FatGetDirEntInfo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN FAT_DIRENT *DirEnt,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+EFI_STATUS\r
+FatOpenDirEnt (\r
+ IN FAT_OFILE *OFile,\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+EFI_STATUS\r
+FatCreateDotDirEnts (\r
+ IN FAT_OFILE *OFile\r
+ );\r
+\r
+VOID\r
+FatCloseDirEnt (\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+EFI_STATUS\r
+FatLocateOFile (\r
+ IN OUT FAT_OFILE **PtrOFile,\r
+ IN CHAR16 *FileName,\r
+ IN UINT8 Attributes,\r
+ OUT CHAR16 *NewFileName\r
+ );\r
+\r
+EFI_STATUS\r
+FatGetVolumeEntry (\r
+ IN FAT_VOLUME *Volume,\r
+ IN CHAR16 *Name\r
+ );\r
+\r
+EFI_STATUS\r
+FatSetVolumeEntry (\r
+ IN FAT_VOLUME *Volume,\r
+ IN CHAR16 *Name\r
+ );\r
+\r
+//\r
+// Hash.c\r
+//\r
+FAT_DIRENT **\r
+FatLongNameHashSearch (\r
+ IN FAT_ODIR *ODir,\r
+ IN CHAR16 *LongNameString\r
+ );\r
+\r
+FAT_DIRENT **\r
+FatShortNameHashSearch (\r
+ IN FAT_ODIR *ODir,\r
+ IN CHAR8 *ShortNameString\r
+ );\r
+\r
+VOID\r
+FatInsertToHashTable (\r
+ IN FAT_ODIR *ODir,\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+VOID\r
+FatDeleteFromHashTable (\r
+ IN FAT_ODIR *ODir,\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+//\r
+// FileName.c\r
+//\r
+BOOLEAN\r
+FatCheckIs8Dot3Name (\r
+ IN CHAR16 *FileName,\r
+ OUT CHAR8 *File8Dot3Name\r
+ );\r
+\r
+VOID\r
+FatCreate8Dot3Name (\r
+ IN FAT_OFILE *Parent,\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+VOID\r
+FatNameToStr (\r
+ IN CHAR8 *FatName,\r
+ IN UINTN Len,\r
+ IN UINTN LowerCase,\r
+ IN CHAR16 *Str\r
+ );\r
+\r
+VOID\r
+FatSetCaseFlag (\r
+ IN FAT_DIRENT *DirEnt\r
+ );\r
+\r
+VOID\r
+FatGetFileNameViaCaseFlag (\r
+ IN FAT_DIRENT *DirEnt,\r
+ IN OUT CHAR16 *FileString,\r
+ IN UINTN FileStringMax\r
+ );\r
+\r
+UINT8\r
+FatCheckSum (\r
+ IN CHAR8 *ShortNameString\r
+ );\r
+\r
+CHAR16*\r
+FatGetNextNameComponent (\r
+ IN CHAR16 *Path,\r
+ OUT CHAR16 *Name\r
+ );\r
+\r
+BOOLEAN\r
+FatFileNameIsValid (\r
+ IN CHAR16 *InputFileName,\r
+ OUT CHAR16 *OutputFileName\r
+ );\r
+\r
+//\r
+// DirectoryCache.c\r
+//\r
+VOID\r
+FatDiscardODir (\r
+ IN FAT_OFILE *OFile\r
+ );\r
+\r
+VOID\r
+FatRequestODir (\r
+ IN FAT_OFILE *OFile\r
+ );\r
+\r
+VOID\r
+FatCleanupODirCache (\r
+ IN FAT_VOLUME *Volume\r
+ );\r
+\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL gFatDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gFatComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gFatComponentName2;\r
+extern EFI_LOCK FatFsLock;\r
+extern EFI_LOCK FatTaskLock;\r
+extern EFI_FILE_PROTOCOL FatFileInterface;\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# Component description file for FAT module.\r
+#\r
+# This UEFI driver detects the FAT file system in the disk.\r
+# It also produces the Simple File System protocol for the consumer to\r
+# perform file and directory operations on the disk.\r
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are licensed and made available\r
+# under the terms and conditions of the BSD License which accompanies this\r
+# distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = Fat\r
+ MODULE_UNI_FILE = Fat.uni\r
+ FILE_GUID = 961578FE-B6B7-44c3-AF35-6BC705CD2B1F\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = FatEntryPoint\r
+ UNLOAD_IMAGE = FatUnload\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+# DRIVER_BINDING = gFatDriverBinding\r
+# COMPONENT_NAME = gFatComponentName\r
+# COMPONENT_NAME2 = gFatComponentName2\r
+#\r
+\r
+[Sources]\r
+ DirectoryCache.c\r
+ DiskCache.c\r
+ FileName.c\r
+ Hash.c\r
+ DirectoryManage.c\r
+ ComponentName.c\r
+ FatFileSystem.h\r
+ Fat.h\r
+ ReadWrite.c\r
+ OpenVolume.c\r
+ Open.c\r
+ Misc.c\r
+ Init.c\r
+ Info.c\r
+ FileSpace.c\r
+ Flush.c\r
+ Fat.c\r
+ Delete.c\r
+ Data.c\r
+ UnicodeCollation.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+ UefiRuntimeServicesTableLib\r
+ UefiBootServicesTableLib\r
+ MemoryAllocationLib\r
+ BaseMemoryLib\r
+ BaseLib\r
+ UefiLib\r
+ UefiDriverEntryPoint\r
+ DebugLib\r
+ PcdLib\r
+\r
+[Guids]\r
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## UNDEFINED\r
+ gEfiFileSystemInfoGuid ## SOMETIMES_CONSUMES ## UNDEFINED\r
+ gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## UNDEFINED\r
+\r
+[Protocols]\r
+ gEfiDiskIoProtocolGuid ## TO_START\r
+ gEfiDiskIo2ProtocolGuid ## TO_START\r
+ gEfiBlockIoProtocolGuid ## TO_START\r
+ gEfiSimpleFileSystemProtocolGuid ## BY_START\r
+ gEfiUnicodeCollationProtocolGuid ## TO_START\r
+ gEfiUnicodeCollation2ProtocolGuid ## TO_START\r
+\r
+[Pcd]\r
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang ## SOMETIMES_CONSUMES\r
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang ## SOMETIMES_CONSUMES\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ FatExtra.uni\r
--- /dev/null
+// /** @file\r
+// Component description file for FAT module.\r
+//\r
+// This UEFI driver detects the FAT file system in the disk.\r
+// It also produces the Simple File System protocol for the consumer to\r
+// perform file and directory operations on the disk.\r
+//\r
+// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials are licensed and made available\r
+// under the terms and conditions of the BSD License which accompanies this\r
+// distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "This UEFI driver detects the FAT file system in the disk."\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "It also produces the Simple File System protocol for the consumer to perform file and directory operations on the disk."\r
+\r
--- /dev/null
+// /** @file\r
+// Fat Localized Strings and Content\r
+//\r
+// Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials are licensed and made available\r
+// under the terms and conditions of the BSD License which accompanies this\r
+// distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME \r
+#language en-US \r
+"FAT File System DXE Driver"\r
+\r
+\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ FatFileSystem.h\r
+\r
+Abstract:\r
+\r
+ Definitions for on-disk FAT structures\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#ifndef _FATFILESYSTEM_H_\r
+#define _FATFILESYSTEM_H_\r
+\r
+#pragma pack(1)\r
+//\r
+// FAT info signature\r
+//\r
+#define FAT_INFO_SIGNATURE 0x41615252\r
+#define FAT_INFO_BEGIN_SIGNATURE 0x61417272\r
+#define FAT_INFO_END_SIGNATURE 0xAA550000\r
+//\r
+// FAT entry values\r
+//\r
+#define FAT_CLUSTER_SPECIAL_EXT (-1 & (~0xF))\r
+#define FAT_CLUSTER_SPECIAL ((FAT_CLUSTER_SPECIAL_EXT) | 0x07)\r
+#define FAT_CLUSTER_FREE 0\r
+#define FAT_CLUSTER_RESERVED (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_BAD (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_LAST (-1)\r
+#define FAT_END_OF_FAT_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL))\r
+#define FAT_MIN_CLUSTER 2\r
+#define FAT_MAX_FAT12_CLUSTER 0xFF5\r
+#define FAT_MAX_FAT16_CLUSTER 0xFFF5\r
+#define FAT_CLUSTER_SPECIAL_FAT12 0xFF7\r
+#define FAT_CLUSTER_SPECIAL_FAT16 0xFFF7\r
+#define FAT_CLUSTER_SPECIAL_FAT32 0x0FFFFFF7\r
+#define FAT_CLUSTER_MASK_FAT12 0xFFF\r
+#define FAT_CLUSTER_UNMASK_FAT12 0xF000\r
+#define FAT_CLUSTER_MASK_FAT32 0x0FFFFFFF\r
+#define FAT_CLUSTER_UNMASK_FAT32 0xF0000000\r
+#define FAT_POS_FAT12(a) ((a) * 3 / 2)\r
+#define FAT_POS_FAT16(a) ((a) * 2)\r
+#define FAT_POS_FAT32(a) ((a) * 4)\r
+#define FAT_ODD_CLUSTER_FAT12(a) (((a) & 1) != 0)\r
+\r
+\r
+//\r
+// FAT attribute define\r
+//\r
+#define FAT_ATTRIBUTE_READ_ONLY 0x01\r
+#define FAT_ATTRIBUTE_HIDDEN 0x02\r
+#define FAT_ATTRIBUTE_SYSTEM 0x04\r
+#define FAT_ATTRIBUTE_VOLUME_ID 0x08\r
+#define FAT_ATTRIBUTE_DIRECTORY 0x10\r
+#define FAT_ATTRIBUTE_ARCHIVE 0x20\r
+#define FAT_ATTRIBUTE_DEVICE 0x40\r
+#define FAT_ATTRIBUTE_LFN 0x0F\r
+//\r
+// Some Long File Name definitions\r
+//\r
+#define FAT_LFN_LAST 0x40 // Ordinal field\r
+#define MAX_LFN_ENTRIES 20\r
+#define LFN_CHAR1_LEN 5\r
+#define LFN_CHAR2_LEN 6\r
+#define LFN_CHAR3_LEN 2\r
+#define LFN_CHAR_TOTAL (LFN_CHAR1_LEN + LFN_CHAR2_LEN + LFN_CHAR3_LEN)\r
+#define LFN_ENTRY_NUMBER(a) (((a) + LFN_CHAR_TOTAL - 1) / LFN_CHAR_TOTAL)\r
+//\r
+// Some 8.3 File Name definitions\r
+//\r
+#define FAT_MAIN_NAME_LEN 8\r
+#define FAT_EXTEND_NAME_LEN 3\r
+#define FAT_NAME_LEN (FAT_MAIN_NAME_LEN + FAT_EXTEND_NAME_LEN)\r
+//\r
+// Some directory entry information\r
+//\r
+#define FAT_ENTRY_INFO_OFFSET 13\r
+#define DELETE_ENTRY_MARK 0xE5\r
+#define EMPTY_ENTRY_MARK 0x00\r
+\r
+//\r
+// Volume dirty Mask\r
+//\r
+#define FAT16_DIRTY_MASK 0x7fff\r
+#define FAT32_DIRTY_MASK 0xf7ffffff\r
+//\r
+// internal flag\r
+//\r
+#define FAT_CASE_MIXED 0x01\r
+#define FAT_CASE_NAME_LOWER 0x08\r
+#define FAT_CASE_EXT_LOWER 0x10\r
+\r
+typedef struct {\r
+ UINT8 Ia32Jump[3];\r
+ CHAR8 OemId[8];\r
+ UINT16 SectorSize;\r
+ UINT8 SectorsPerCluster;\r
+ UINT16 ReservedSectors;\r
+ UINT8 NumFats;\r
+ UINT16 RootEntries; // < FAT32, root dir is fixed size\r
+ UINT16 Sectors;\r
+ UINT8 Media;\r
+ UINT16 SectorsPerFat; // < FAT32\r
+ UINT16 SectorsPerTrack; // (ignored)\r
+ UINT16 Heads; // (ignored)\r
+ UINT32 HiddenSectors; // (ignored)\r
+ UINT32 LargeSectors; // Used if Sectors==0\r
+} FAT_BOOT_SECTOR_BASIC;\r
+\r
+typedef struct {\r
+ UINT8 PhysicalDriveNumber; // (ignored)\r
+ UINT8 CurrentHead; // holds boot_sector_dirty bit\r
+ UINT8 Signature; // (ignored)\r
+ CHAR8 Id[4];\r
+ CHAR8 FatLabel[11];\r
+ CHAR8 SystemId[8];\r
+} FAT_BOOT_SECTOR_EXT;\r
+\r
+typedef struct {\r
+ UINT32 LargeSectorsPerFat; // FAT32\r
+ UINT16 ExtendedFlags; // FAT32 (ignored)\r
+ UINT16 FsVersion; // FAT32 (ignored)\r
+ UINT32 RootDirFirstCluster; // FAT32\r
+ UINT16 FsInfoSector; // FAT32\r
+ UINT16 BackupBootSector; // FAT32\r
+ UINT8 Reserved[12]; // FAT32 (ignored)\r
+ UINT8 PhysicalDriveNumber; // (ignored)\r
+ UINT8 CurrentHead; // holds boot_sector_dirty bit\r
+ UINT8 Signature; // (ignored)\r
+ CHAR8 Id[4];\r
+ CHAR8 FatLabel[11];\r
+ CHAR8 SystemId[8];\r
+} FAT32_BOOT_SECTOR_EXT;\r
+\r
+typedef struct {\r
+ FAT_BOOT_SECTOR_BASIC FatBsb;\r
+ union {\r
+ FAT_BOOT_SECTOR_EXT FatBse;\r
+ FAT32_BOOT_SECTOR_EXT Fat32Bse;\r
+ } FatBse;\r
+} FAT_BOOT_SECTOR;\r
+\r
+//\r
+// FAT Info Structure\r
+//\r
+typedef struct {\r
+ UINT32 ClusterCount;\r
+ UINT32 NextCluster;\r
+} FAT_FREE_INFO;\r
+\r
+typedef struct {\r
+ UINT32 Signature;\r
+ UINT8 ExtraBootCode[480];\r
+ UINT32 InfoBeginSignature;\r
+ FAT_FREE_INFO FreeInfo;\r
+ UINT8 Reserved[12];\r
+ UINT32 InfoEndSignature;\r
+} FAT_INFO_SECTOR;\r
+\r
+//\r
+// Directory Entry\r
+//\r
+#define FAT_MAX_YEAR_FROM_1980 0x7f\r
+typedef struct {\r
+ UINT16 Day : 5;\r
+ UINT16 Month : 4;\r
+ UINT16 Year : 7; // From 1980\r
+} FAT_DATE;\r
+\r
+typedef struct {\r
+ UINT16 DoubleSecond : 5;\r
+ UINT16 Minute : 6;\r
+ UINT16 Hour : 5;\r
+} FAT_TIME;\r
+\r
+typedef struct {\r
+ FAT_TIME Time;\r
+ FAT_DATE Date;\r
+} FAT_DATE_TIME;\r
+\r
+typedef struct {\r
+ CHAR8 FileName[11]; // 8.3 filename\r
+ UINT8 Attributes;\r
+ UINT8 CaseFlag;\r
+ UINT8 CreateMillisecond; // (creation milliseconds - ignored)\r
+ FAT_DATE_TIME FileCreateTime;\r
+ FAT_DATE FileLastAccess;\r
+ UINT16 FileClusterHigh; // >= FAT32\r
+ FAT_DATE_TIME FileModificationTime;\r
+ UINT16 FileCluster;\r
+ UINT32 FileSize;\r
+} FAT_DIRECTORY_ENTRY;\r
+\r
+typedef struct {\r
+ UINT8 Ordinal;\r
+ CHAR8 Name1[10]; // (Really 5 chars, but not WCHAR aligned)\r
+ UINT8 Attributes;\r
+ UINT8 Type;\r
+ UINT8 Checksum;\r
+ CHAR16 Name2[6];\r
+ UINT16 MustBeZero;\r
+ CHAR16 Name3[2];\r
+} FAT_DIRECTORY_LFN;\r
+\r
+#pragma pack()\r
+\r
+#endif\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ FileName.c\r
+\r
+Abstract:\r
+\r
+ Functions for manipulating file names\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+BOOLEAN\r
+FatCheckIs8Dot3Name (\r
+ IN CHAR16 *FileName,\r
+ OUT CHAR8 *File8Dot3Name\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function checks whether the input FileName is a valid 8.3 short name.\r
+ If the input FileName is a valid 8.3, the output is the 8.3 short name;\r
+ otherwise, the output is the base tag of 8.3 short name.\r
+\r
+Arguments:\r
+\r
+ FileName - The input unicode filename.\r
+ File8Dot3Name - The output ascii 8.3 short name or base tag of 8.3 short name.\r
+\r
+Returns:\r
+\r
+ TRUE - The input unicode filename is a valid 8.3 short name.\r
+ FALSE - The input unicode filename is not a valid 8.3 short name.\r
+\r
+--*/\r
+{\r
+ BOOLEAN PossibleShortName;\r
+ CHAR16 *TempName;\r
+ CHAR16 *ExtendName;\r
+ CHAR16 *SeparateDot;\r
+ UINTN MainNameLen;\r
+ UINTN ExtendNameLen;\r
+\r
+ PossibleShortName = TRUE;\r
+ SeparateDot = NULL;\r
+ SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');\r
+ for (TempName = FileName; *TempName; TempName++) {\r
+ if (*TempName == L'.') {\r
+ SeparateDot = TempName;\r
+ }\r
+ }\r
+\r
+ if (SeparateDot == NULL) {\r
+ //\r
+ // Extended filename is not detected\r
+ //\r
+ MainNameLen = TempName - FileName;\r
+ ExtendName = TempName;\r
+ ExtendNameLen = 0;\r
+ } else {\r
+ //\r
+ // Extended filename is detected\r
+ //\r
+ MainNameLen = SeparateDot - FileName;\r
+ ExtendName = SeparateDot + 1;\r
+ ExtendNameLen = TempName - ExtendName;\r
+ }\r
+ //\r
+ // We scan the filename for the second time\r
+ // to check if there exists any extra blanks and dots\r
+ //\r
+ while (--TempName >= FileName) {\r
+ if ((*TempName == L'.' || *TempName == L' ') && (TempName != SeparateDot)) {\r
+ //\r
+ // There exist extra blanks and dots\r
+ //\r
+ PossibleShortName = FALSE;\r
+ }\r
+ }\r
+\r
+ if (MainNameLen == 0) {\r
+ PossibleShortName = FALSE;\r
+ }\r
+\r
+ if (MainNameLen > FAT_MAIN_NAME_LEN) {\r
+ PossibleShortName = FALSE;\r
+ MainNameLen = FAT_MAIN_NAME_LEN;\r
+ }\r
+\r
+ if (ExtendNameLen > FAT_EXTEND_NAME_LEN) {\r
+ PossibleShortName = FALSE;\r
+ ExtendNameLen = FAT_EXTEND_NAME_LEN;\r
+ }\r
+\r
+ if (FatStrToFat (FileName, MainNameLen, File8Dot3Name)) {\r
+ PossibleShortName = FALSE;\r
+ }\r
+\r
+ if (FatStrToFat (ExtendName, ExtendNameLen, File8Dot3Name + FAT_MAIN_NAME_LEN)) {\r
+ PossibleShortName = FALSE;\r
+ }\r
+\r
+ return PossibleShortName;\r
+}\r
+\r
+STATIC\r
+UINTN\r
+FatTrimAsciiTrailingBlanks (\r
+ IN CHAR8 *Name,\r
+ IN UINTN Len\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Trim the trailing blanks of fat name.\r
+\r
+Arguments:\r
+\r
+ Name - The Char8 string needs to be trimed.\r
+ Len - The length of the fat name.\r
+\r
+Returns:\r
+\r
+ The real length of the fat name after the trailing blanks are trimmed.\r
+\r
+--*/\r
+{\r
+ while (Len > 0 && Name[Len - 1] == ' ') {\r
+ Len--;\r
+ }\r
+\r
+ return Len;\r
+}\r
+\r
+VOID\r
+FatNameToStr (\r
+ IN CHAR8 *FatName,\r
+ IN UINTN Len,\r
+ IN UINTN LowerCase,\r
+ OUT CHAR16 *Str\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Convert the ascii fat name to the unicode string and strip trailing spaces,\r
+ and if necessary, convert the unicode string to lower case.\r
+\r
+Arguments:\r
+\r
+ FatName - The Char8 string needs to be converted.\r
+ Len - The length of the fat name.\r
+ LowerCase - Indicate whether to convert the string to lower case.\r
+ Str - The result of the convertion.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ //\r
+ // First, trim the trailing blanks\r
+ //\r
+ Len = FatTrimAsciiTrailingBlanks (FatName, Len);\r
+ //\r
+ // Convert fat string to unicode string\r
+ //\r
+ FatFatToStr (Len, FatName, Str);\r
+\r
+ //\r
+ // If the name is to be lower cased, do it now\r
+ //\r
+ if (LowerCase != 0) {\r
+ FatStrLwr (Str);\r
+ }\r
+}\r
+\r
+VOID\r
+FatCreate8Dot3Name (\r
+ IN FAT_OFILE *Parent,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function generates 8Dot3 name from user specified name for a newly created file.\r
+\r
+Arguments:\r
+\r
+ Parent - The parent directory.\r
+ DirEnt - The directory entry whose 8Dot3Name needs to be generated.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ CHAR8 *ShortName;\r
+ CHAR8 *ShortNameChar;\r
+ UINTN BaseTagLen;\r
+ UINTN Index;\r
+ UINTN Retry;\r
+ UINT8 Segment;\r
+ union {\r
+ UINT32 Crc;\r
+ struct HEX_DATA {\r
+ UINT8 Segment : HASH_VALUE_TAG_LEN;\r
+ } Hex[HASH_VALUE_TAG_LEN];\r
+ } HashValue;\r
+ //\r
+ // Make sure the whole directory has been loaded\r
+ //\r
+ ASSERT (Parent->ODir->EndOfDir);\r
+ ShortName = DirEnt->Entry.FileName;\r
+\r
+ //\r
+ // Trim trailing blanks of 8.3 name\r
+ //\r
+ BaseTagLen = FatTrimAsciiTrailingBlanks (ShortName, FAT_MAIN_NAME_LEN);\r
+ if (BaseTagLen > SPEC_BASE_TAG_LEN) {\r
+ BaseTagLen = SPEC_BASE_TAG_LEN;\r
+ }\r
+ //\r
+ // We first use the algorithm described by spec.\r
+ //\r
+ ShortNameChar = ShortName + BaseTagLen;\r
+ *ShortNameChar++ = '~';\r
+ *ShortNameChar = '1';\r
+ Retry = 0;\r
+ while (*FatShortNameHashSearch (Parent->ODir, ShortName) != NULL) {\r
+ *ShortNameChar = (CHAR8)(*ShortNameChar + 1);\r
+ if (++Retry == MAX_SPEC_RETRY) {\r
+ //\r
+ // We use new algorithm to generate 8.3 name\r
+ //\r
+ ASSERT (DirEnt->FileString != NULL);\r
+ gBS->CalculateCrc32 (DirEnt->FileString, StrSize (DirEnt->FileString), &HashValue.Crc);\r
+\r
+ if (BaseTagLen > HASH_BASE_TAG_LEN) {\r
+ BaseTagLen = HASH_BASE_TAG_LEN;\r
+ }\r
+\r
+ ShortNameChar = ShortName + BaseTagLen;\r
+ for (Index = 0; Index < HASH_VALUE_TAG_LEN; Index++) {\r
+ Segment = HashValue.Hex[Index].Segment;\r
+ if (Segment > 9) {\r
+ *ShortNameChar++ = (CHAR8)(Segment - 10 + 'A');\r
+ } else {\r
+ *ShortNameChar++ = (CHAR8)(Segment + '0');\r
+ }\r
+ }\r
+\r
+ *ShortNameChar++ = '~';\r
+ *ShortNameChar = '1';\r
+ }\r
+ }\r
+}\r
+\r
+STATIC\r
+UINT8\r
+FatCheckNameCase (\r
+ IN CHAR16 *Str,\r
+ IN UINT8 InCaseFlag\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Check the string is lower case or upper case\r
+ and it is used by fatname to dir entry count\r
+\r
+Arguments:\r
+\r
+ Str - The string which needs to be checked.\r
+ InCaseFlag - The input case flag which is returned when the string is lower case.\r
+\r
+Returns:\r
+\r
+ OutCaseFlag - The output case flag.\r
+\r
+--*/\r
+{\r
+ CHAR16 Buffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1];\r
+ UINT8 OutCaseFlag;\r
+\r
+ //\r
+ // Assume the case of input string is mixed\r
+ //\r
+ OutCaseFlag = FAT_CASE_MIXED;\r
+ //\r
+ // Lower case a copy of the string, if it matches the\r
+ // original then the string is lower case\r
+ //\r
+ StrCpyS (Buffer, sizeof (Buffer) / sizeof (Buffer[0]), Str);\r
+ FatStrLwr (Buffer);\r
+ if (StrCmp (Str, Buffer) == 0) {\r
+ OutCaseFlag = InCaseFlag;\r
+ }\r
+ //\r
+ // Upper case a copy of the string, if it matches the\r
+ // original then the string is upper case\r
+ //\r
+ StrCpyS (Buffer, sizeof (Buffer) / sizeof (Buffer[0]), Str);\r
+ FatStrUpr (Buffer);\r
+ if (StrCmp (Str, Buffer) == 0) {\r
+ OutCaseFlag = 0;\r
+ }\r
+\r
+ return OutCaseFlag;\r
+}\r
+\r
+VOID\r
+FatSetCaseFlag (\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the caseflag value for the directory entry.\r
+\r
+Arguments:\r
+\r
+ DirEnt - The logical directory entry whose caseflag value is to be set.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ CHAR16 LfnBuffer[FAT_MAIN_NAME_LEN + 1 + FAT_EXTEND_NAME_LEN + 1];\r
+ CHAR16 *TempCharPtr;\r
+ CHAR16 *ExtendName;\r
+ CHAR16 *FileNameCharPtr;\r
+ UINT8 CaseFlag;\r
+\r
+ ExtendName = NULL;\r
+ TempCharPtr = LfnBuffer;\r
+ FileNameCharPtr = DirEnt->FileString;\r
+ ASSERT (StrSize (DirEnt->FileString) <= sizeof (LfnBuffer));\r
+ while ((*TempCharPtr = *FileNameCharPtr) != 0) {\r
+ if (*TempCharPtr == L'.') {\r
+ ExtendName = TempCharPtr;\r
+ }\r
+\r
+ TempCharPtr++;\r
+ FileNameCharPtr++;\r
+ }\r
+\r
+ CaseFlag = 0;\r
+ if (ExtendName != NULL) {\r
+ *ExtendName = 0;\r
+ ExtendName++;\r
+ CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (ExtendName, FAT_CASE_EXT_LOWER));\r
+ }\r
+\r
+ CaseFlag = (UINT8)(CaseFlag | FatCheckNameCase (LfnBuffer, FAT_CASE_NAME_LOWER));\r
+ if ((CaseFlag & FAT_CASE_MIXED) == 0) {\r
+ //\r
+ // We just need one directory entry to store this file name entry\r
+ //\r
+ DirEnt->Entry.CaseFlag = CaseFlag;\r
+ } else {\r
+ //\r
+ // We need one extra directory entry to store the mixed case entry\r
+ //\r
+ DirEnt->Entry.CaseFlag = 0;\r
+ DirEnt->EntryCount++;\r
+ }\r
+}\r
+\r
+VOID\r
+FatGetFileNameViaCaseFlag (\r
+ IN FAT_DIRENT *DirEnt,\r
+ IN OUT CHAR16 *FileString,\r
+ IN UINTN FileStringMax\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Convert the 8.3 ASCII fat name to cased Unicode string according to case flag.\r
+\r
+Arguments:\r
+\r
+ DirEnt - The corresponding directory entry.\r
+ FileString - The output Unicode file name.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ UINT8 CaseFlag;\r
+ CHAR8 *File8Dot3Name;\r
+ CHAR16 TempExt[1 + FAT_EXTEND_NAME_LEN + 1];\r
+ //\r
+ // Store file extension like ".txt"\r
+ //\r
+ CaseFlag = DirEnt->Entry.CaseFlag;\r
+ File8Dot3Name = DirEnt->Entry.FileName;\r
+\r
+ FatNameToStr (File8Dot3Name, FAT_MAIN_NAME_LEN, CaseFlag & FAT_CASE_NAME_LOWER, FileString);\r
+ FatNameToStr (File8Dot3Name + FAT_MAIN_NAME_LEN, FAT_EXTEND_NAME_LEN, CaseFlag & FAT_CASE_EXT_LOWER, &TempExt[1]);\r
+ if (TempExt[1] != 0) {\r
+ TempExt[0] = L'.';\r
+ StrCatS (FileString, FileStringMax, TempExt);\r
+ }\r
+}\r
+\r
+UINT8\r
+FatCheckSum (\r
+ IN CHAR8 *ShortNameString\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the Check sum for a short name.\r
+\r
+Arguments:\r
+\r
+ ShortNameString - The short name for a file.\r
+\r
+Returns:\r
+\r
+ Sum - UINT8 checksum.\r
+\r
+--*/\r
+{\r
+ UINTN ShortNameLen;\r
+ UINT8 Sum;\r
+ Sum = 0;\r
+ for (ShortNameLen = FAT_NAME_LEN; ShortNameLen != 0; ShortNameLen--) {\r
+ Sum = (UINT8)(((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *ShortNameString++);\r
+ }\r
+\r
+ return Sum;\r
+}\r
+\r
+CHAR16 *\r
+FatGetNextNameComponent (\r
+ IN CHAR16 *Path,\r
+ OUT CHAR16 *Name\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Takes Path as input, returns the next name component\r
+ in Name, and returns the position after Name (e.g., the\r
+ start of the next name component)\r
+\r
+Arguments:\r
+\r
+ Path - The path of one file.\r
+ Name - The next name component in Path.\r
+\r
+Returns:\r
+\r
+ The position after Name in the Path\r
+\r
+--*/\r
+{\r
+ while (*Path != 0 && *Path != PATH_NAME_SEPARATOR) {\r
+ *Name++ = *Path++;\r
+ }\r
+ *Name = 0;\r
+ //\r
+ // Get off of trailing path name separator\r
+ //\r
+ while (*Path == PATH_NAME_SEPARATOR) {\r
+ Path++;\r
+ }\r
+\r
+ return Path;\r
+}\r
+\r
+BOOLEAN\r
+FatFileNameIsValid (\r
+ IN CHAR16 *InputFileName,\r
+ OUT CHAR16 *OutputFileName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Check whether the IFileName is valid long file name. If the IFileName is a valid\r
+ long file name, then we trim the possible leading blanks and leading/trailing dots.\r
+ the trimmed filename is stored in OutputFileName\r
+\r
+Arguments:\r
+\r
+ InputFileName - The input file name.\r
+ OutputFileName - The output file name.\r
+\r
+\r
+Returns:\r
+\r
+ TRUE - The InputFileName is a valid long file name.\r
+ FALSE - The InputFileName is not a valid long file name.\r
+\r
+--*/\r
+{\r
+ CHAR16 *TempNamePointer;\r
+ CHAR16 TempChar;\r
+ //\r
+ // Trim Leading blanks\r
+ //\r
+ while (*InputFileName == L' ') {\r
+ InputFileName++;\r
+ }\r
+\r
+ TempNamePointer = OutputFileName;\r
+ while (*InputFileName != 0) {\r
+ *TempNamePointer++ = *InputFileName++;\r
+ }\r
+ //\r
+ // Trim Trailing blanks and dots\r
+ //\r
+ while (TempNamePointer > OutputFileName) {\r
+ TempChar = *(TempNamePointer - 1);\r
+ if (TempChar != L' ' && TempChar != L'.') {\r
+ break;\r
+ }\r
+\r
+ TempNamePointer--;\r
+ }\r
+\r
+ *TempNamePointer = 0;\r
+\r
+ //\r
+ // Per FAT Spec the file name should meet the following criteria:\r
+ // C1. Length (FileLongName) <= 255\r
+ // C2. Length (X:FileFullPath<NUL>) <= 260\r
+ // Here we check C1.\r
+ //\r
+ if (TempNamePointer - OutputFileName > EFI_FILE_STRING_LENGTH) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // See if there is any illegal characters within the name\r
+ //\r
+ do {\r
+ if (*OutputFileName < 0x20 ||\r
+ *OutputFileName == '\"' ||\r
+ *OutputFileName == '*' ||\r
+ *OutputFileName == '/' ||\r
+ *OutputFileName == ':' ||\r
+ *OutputFileName == '<' ||\r
+ *OutputFileName == '>' ||\r
+ *OutputFileName == '?' ||\r
+ *OutputFileName == '\\' ||\r
+ *OutputFileName == '|'\r
+ ) {\r
+ return FALSE;\r
+ }\r
+\r
+ OutputFileName++;\r
+ } while (*OutputFileName != 0);\r
+ return TRUE;\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ FileSpace.c\r
+\r
+Abstract:\r
+\r
+ Routines dealing with disk spaces and FAT table entries\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+\r
+STATIC\r
+VOID *\r
+FatLoadFatEntry (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN Index\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the FAT entry of the volume, which is identified with the Index.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ Index - The index of the FAT entry of the volume.\r
+\r
+Returns:\r
+\r
+ The buffer of the FAT entry\r
+\r
+--*/\r
+{\r
+ UINTN Pos;\r
+ EFI_STATUS Status;\r
+\r
+ if (Index > (Volume->MaxCluster + 1)) {\r
+ Volume->FatEntryBuffer = (UINT32) -1;\r
+ return &Volume->FatEntryBuffer;\r
+ }\r
+ //\r
+ // Compute buffer position needed\r
+ //\r
+ switch (Volume->FatType) {\r
+ case FAT12:\r
+ Pos = FAT_POS_FAT12 (Index);\r
+ break;\r
+\r
+ case FAT16:\r
+ Pos = FAT_POS_FAT16 (Index);\r
+ break;\r
+\r
+ default:\r
+ Pos = FAT_POS_FAT32 (Index);\r
+ }\r
+ //\r
+ // Set the position and read the buffer\r
+ //\r
+ Volume->FatEntryPos = Volume->FatPos + Pos;\r
+ Status = FatDiskIo (\r
+ Volume,\r
+ READ_FAT,\r
+ Volume->FatEntryPos,\r
+ Volume->FatEntrySize,\r
+ &Volume->FatEntryBuffer,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Volume->FatEntryBuffer = (UINT32) -1;\r
+ }\r
+\r
+ return &Volume->FatEntryBuffer;\r
+}\r
+\r
+STATIC\r
+UINTN\r
+FatGetFatEntry (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN Index\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the FAT entry value of the volume, which is identified with the Index.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ Index - The index of the FAT entry of the volume.\r
+\r
+Returns:\r
+\r
+ The value of the FAT entry.\r
+\r
+--*/\r
+{\r
+ VOID *Pos;\r
+ UINT8 *E12;\r
+ UINT16 *E16;\r
+ UINT32 *E32;\r
+ UINTN Accum;\r
+\r
+ Pos = FatLoadFatEntry (Volume, Index);\r
+\r
+ if (Index > (Volume->MaxCluster + 1)) {\r
+ return (UINTN) -1;\r
+ }\r
+\r
+ switch (Volume->FatType) {\r
+ case FAT12:\r
+ E12 = Pos;\r
+ Accum = E12[0] | (E12[1] << 8);\r
+ Accum = FAT_ODD_CLUSTER_FAT12 (Index) ? (Accum >> 4) : (Accum & FAT_CLUSTER_MASK_FAT12);\r
+ Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT12) ? FAT_CLUSTER_SPECIAL_EXT : 0);\r
+ break;\r
+\r
+ case FAT16:\r
+ E16 = Pos;\r
+ Accum = *E16;\r
+ Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT16) ? FAT_CLUSTER_SPECIAL_EXT : 0);\r
+ break;\r
+\r
+ default:\r
+ E32 = Pos;\r
+ Accum = *E32 & FAT_CLUSTER_MASK_FAT32;\r
+ Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT32) ? FAT_CLUSTER_SPECIAL_EXT : 0);\r
+ }\r
+\r
+ return Accum;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatSetFatEntry (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN Index,\r
+ IN UINTN Value\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the FAT entry value of the volume, which is identified with the Index.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ Index - The index of the FAT entry of the volume.\r
+ Value - The new value of the FAT entry.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the new FAT entry value sucessfully.\r
+ EFI_VOLUME_CORRUPTED - The FAT type of the volume is error.\r
+ other - An error occurred when operation the FAT entries.\r
+\r
+--*/\r
+{\r
+ VOID *Pos;\r
+ UINT8 *E12;\r
+ UINT16 *E16;\r
+ UINT32 *E32;\r
+ UINTN Accum;\r
+ EFI_STATUS Status;\r
+ UINTN OriginalVal;\r
+\r
+ if (Index < FAT_MIN_CLUSTER) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ OriginalVal = FatGetFatEntry (Volume, Index);\r
+ if (Value == FAT_CLUSTER_FREE && OriginalVal != FAT_CLUSTER_FREE) {\r
+ Volume->FatInfoSector.FreeInfo.ClusterCount += 1;\r
+ if (Index < Volume->FatInfoSector.FreeInfo.NextCluster) {\r
+ Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;\r
+ }\r
+ } else if (Value != FAT_CLUSTER_FREE && OriginalVal == FAT_CLUSTER_FREE) {\r
+ if (Volume->FatInfoSector.FreeInfo.ClusterCount != 0) {\r
+ Volume->FatInfoSector.FreeInfo.ClusterCount -= 1;\r
+ }\r
+ }\r
+ //\r
+ // Make sure the entry is in memory\r
+ //\r
+ Pos = FatLoadFatEntry (Volume, Index);\r
+\r
+ //\r
+ // Update the value\r
+ //\r
+ switch (Volume->FatType) {\r
+ case FAT12:\r
+ E12 = Pos;\r
+ Accum = E12[0] | (E12[1] << 8);\r
+ Value = Value & FAT_CLUSTER_MASK_FAT12;\r
+\r
+ if (FAT_ODD_CLUSTER_FAT12 (Index)) {\r
+ Accum = (Value << 4) | (Accum & 0xF);\r
+ } else {\r
+ Accum = Value | (Accum & FAT_CLUSTER_UNMASK_FAT12);\r
+ }\r
+\r
+ E12[0] = (UINT8) (Accum & 0xFF);\r
+ E12[1] = (UINT8) (Accum >> 8);\r
+ break;\r
+\r
+ case FAT16:\r
+ E16 = Pos;\r
+ *E16 = (UINT16) Value;\r
+ break;\r
+\r
+ default:\r
+ E32 = Pos;\r
+ *E32 = (*E32 & FAT_CLUSTER_UNMASK_FAT32) | (UINT32) (Value & FAT_CLUSTER_MASK_FAT32);\r
+ }\r
+ //\r
+ // If the volume's dirty bit is not set, set it now\r
+ //\r
+ if (!Volume->FatDirty && Volume->FatType != FAT12) {\r
+ Volume->FatDirty = TRUE;\r
+ FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->DirtyValue);\r
+ }\r
+ //\r
+ // Write the updated fat entry value to the volume\r
+ // The fat is the first fat, and other fat will be in sync\r
+ // when the FAT cache flush back.\r
+ //\r
+ Status = FatDiskIo (\r
+ Volume,\r
+ WRITE_FAT,\r
+ Volume->FatEntryPos,\r
+ Volume->FatEntrySize,\r
+ &Volume->FatEntryBuffer,\r
+ NULL\r
+ );\r
+ return Status;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+FatFreeClusters (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN Cluster\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Free the cluster clain.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ Cluster - The first cluster of cluster chain.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The cluster chain is freed successfully.\r
+ EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.\r
+\r
+--*/\r
+{\r
+ UINTN LastCluster;\r
+\r
+ while (!FAT_END_OF_FAT_CHAIN (Cluster)) {\r
+ if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {\r
+\r
+ DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ LastCluster = Cluster;\r
+ Cluster = FatGetFatEntry (Volume, Cluster);\r
+ FatSetFatEntry (Volume, LastCluster, FAT_CLUSTER_FREE);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+UINTN\r
+FatAllocateCluster (\r
+ IN FAT_VOLUME *Volume\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Allocate a free cluster and return the cluster index.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+\r
+Returns:\r
+\r
+ The index of the free cluster\r
+\r
+--*/\r
+{\r
+ UINTN Cluster;\r
+\r
+ //\r
+ // Start looking at FatFreePos for the next unallocated cluster\r
+ //\r
+ if (Volume->DiskError) {\r
+ return (UINTN) FAT_CLUSTER_LAST;\r
+ }\r
+\r
+ for (;;) {\r
+ //\r
+ // If the end of the list, return no available cluster\r
+ //\r
+ if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {\r
+ if (Volume->FreeInfoValid && 0 < (INT32) (Volume->FatInfoSector.FreeInfo.ClusterCount)) {\r
+ Volume->FreeInfoValid = FALSE;\r
+ }\r
+\r
+ FatComputeFreeInfo (Volume);\r
+ if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {\r
+ return (UINTN) FAT_CLUSTER_LAST;\r
+ }\r
+ }\r
+\r
+ Cluster = FatGetFatEntry (Volume, Volume->FatInfoSector.FreeInfo.NextCluster);\r
+ if (Cluster == FAT_CLUSTER_FREE) {\r
+ break;\r
+ }\r
+ //\r
+ // Try the next cluster\r
+ //\r
+ Volume->FatInfoSector.FreeInfo.NextCluster += 1;\r
+ }\r
+\r
+ Cluster = Volume->FatInfoSector.FreeInfo.NextCluster;\r
+ Volume->FatInfoSector.FreeInfo.NextCluster += 1;\r
+ return Cluster;\r
+}\r
+\r
+STATIC\r
+UINTN\r
+FatSizeToClusters (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN Size\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Count the number of clusters given a size\r
+\r
+Arguments:\r
+\r
+ Volume - The file system volume.\r
+ Size - The size in bytes.\r
+\r
+Returns:\r
+\r
+ The number of the clusters.\r
+\r
+--*/\r
+{\r
+ UINTN Clusters;\r
+\r
+ Clusters = Size >> Volume->ClusterAlignment;\r
+ if ((Size & (Volume->ClusterSize - 1)) > 0) {\r
+ Clusters += 1;\r
+ }\r
+\r
+ return Clusters;\r
+}\r
+\r
+EFI_STATUS\r
+FatShrinkEof (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Shrink the end of the open file base on the file size.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Shrinked sucessfully.\r
+ EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.\r
+\r
+--*/\r
+{\r
+ FAT_VOLUME *Volume;\r
+ UINTN NewSize;\r
+ UINTN CurSize;\r
+ UINTN Cluster;\r
+ UINTN LastCluster;\r
+\r
+ Volume = OFile->Volume;\r
+ ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+ NewSize = FatSizeToClusters (Volume, OFile->FileSize);\r
+\r
+ //\r
+ // Find the address of the last cluster\r
+ //\r
+ Cluster = OFile->FileCluster;\r
+ LastCluster = FAT_CLUSTER_FREE;\r
+\r
+ if (NewSize != 0) {\r
+\r
+ for (CurSize = 0; CurSize < NewSize; CurSize++) {\r
+ if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {\r
+\r
+ DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ LastCluster = Cluster;\r
+ Cluster = FatGetFatEntry (Volume, Cluster);\r
+ }\r
+\r
+ FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);\r
+\r
+ } else {\r
+ //\r
+ // Check to see if the file is already completely truncated\r
+ //\r
+ if (Cluster == FAT_CLUSTER_FREE) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // The file is being completely truncated.\r
+ //\r
+ OFile->FileCluster = FAT_CLUSTER_FREE;\r
+ }\r
+ //\r
+ // Set CurrentCluster == FileCluster\r
+ // to force a recalculation of Position related stuffs\r
+ //\r
+ OFile->FileCurrentCluster = OFile->FileCluster;\r
+ OFile->FileLastCluster = LastCluster;\r
+ OFile->Dirty = TRUE;\r
+ //\r
+ // Free the remaining cluster chain\r
+ //\r
+ return FatFreeClusters (Volume, Cluster);\r
+}\r
+\r
+EFI_STATUS\r
+FatGrowEof (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINT64 NewSizeInBytes\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Grow the end of the open file base on the NewSizeInBytes.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+ NewSizeInBytes - The new size in bytes of the open file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The file is grown sucessfully.\r
+ EFI_UNSUPPORTED - The file size is larger than 4GB.\r
+ EFI_VOLUME_CORRUPTED - There are errors in the files' clusters.\r
+ EFI_VOLUME_FULL - The volume is full and can not grow the file.\r
+\r
+--*/\r
+{\r
+ FAT_VOLUME *Volume;\r
+ EFI_STATUS Status;\r
+ UINTN Cluster;\r
+ UINTN CurSize;\r
+ UINTN NewSize;\r
+ UINTN LastCluster;\r
+ UINTN NewCluster;\r
+ UINTN ClusterCount;\r
+\r
+ //\r
+ // For FAT file system, the max file is 4GB.\r
+ //\r
+ if (NewSizeInBytes > 0x0FFFFFFFFL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Volume = OFile->Volume;\r
+ ASSERT_VOLUME_LOCKED (Volume);\r
+ //\r
+ // If the file is already large enough, do nothing\r
+ //\r
+ CurSize = FatSizeToClusters (Volume, OFile->FileSize);\r
+ NewSize = FatSizeToClusters (Volume, (UINTN) NewSizeInBytes);\r
+\r
+ if (CurSize < NewSize) {\r
+ //\r
+ // If we haven't found the files last cluster do it now\r
+ //\r
+ if ((OFile->FileCluster != 0) && (OFile->FileLastCluster == 0)) {\r
+ Cluster = OFile->FileCluster;\r
+ ClusterCount = 0;\r
+\r
+ while (!FAT_END_OF_FAT_CHAIN (Cluster)) {\r
+ if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {\r
+\r
+ DEBUG (\r
+ (EFI_D_INIT | EFI_D_ERROR,\r
+ "FatGrowEof: cluster chain corrupt\n")\r
+ );\r
+ Status = EFI_VOLUME_CORRUPTED;\r
+ goto Done;\r
+ }\r
+\r
+ ClusterCount++;\r
+ OFile->FileLastCluster = Cluster;\r
+ Cluster = FatGetFatEntry (Volume, Cluster);\r
+ }\r
+\r
+ if (ClusterCount != CurSize) {\r
+ DEBUG (\r
+ (EFI_D_INIT | EFI_D_ERROR,\r
+ "FatGrowEof: cluster chain size does not match file size\n")\r
+ );\r
+ Status = EFI_VOLUME_CORRUPTED;\r
+ goto Done;\r
+ }\r
+\r
+ }\r
+ //\r
+ // Loop until we've allocated enough space\r
+ //\r
+ LastCluster = OFile->FileLastCluster;\r
+\r
+ while (CurSize < NewSize) {\r
+ NewCluster = FatAllocateCluster (Volume);\r
+ if (FAT_END_OF_FAT_CHAIN (NewCluster)) {\r
+ if (LastCluster != FAT_CLUSTER_FREE) {\r
+ FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);\r
+ OFile->FileLastCluster = LastCluster;\r
+ }\r
+\r
+ Status = EFI_VOLUME_FULL;\r
+ goto Done;\r
+ }\r
+\r
+ if (LastCluster != 0) {\r
+ FatSetFatEntry (Volume, LastCluster, NewCluster);\r
+ } else {\r
+ OFile->FileCluster = NewCluster;\r
+ OFile->FileCurrentCluster = NewCluster;\r
+ }\r
+\r
+ LastCluster = NewCluster;\r
+ CurSize += 1;\r
+ }\r
+ //\r
+ // Terminate the cluster list\r
+ //\r
+ FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);\r
+ OFile->FileLastCluster = LastCluster;\r
+ }\r
+\r
+ OFile->FileSize = (UINTN) NewSizeInBytes;\r
+ OFile->Dirty = TRUE;\r
+ return EFI_SUCCESS;\r
+\r
+Done:\r
+ FatShrinkEof (OFile);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatOFilePosition (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINTN Position,\r
+ IN UINTN PosLimit\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Seek OFile to requested position, and calculate the number of\r
+ consecutive clusters from the position in the file\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+ Position - The file's position which will be accessed.\r
+ PosLimit - The maximum length current reading/writing may access\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the info successfully.\r
+ EFI_VOLUME_CORRUPTED - Cluster chain corrupt.\r
+\r
+--*/\r
+{\r
+ FAT_VOLUME *Volume;\r
+ UINTN ClusterSize;\r
+ UINTN Cluster;\r
+ UINTN StartPos;\r
+ UINTN Run;\r
+\r
+ Volume = OFile->Volume;\r
+ ClusterSize = Volume->ClusterSize;\r
+\r
+ ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+ //\r
+ // If this is the fixed root dir, then compute it's position\r
+ // from it's fixed info in the fat bpb\r
+ //\r
+ if (OFile->IsFixedRootDir) {\r
+ OFile->PosDisk = Volume->RootPos + Position;\r
+ Run = OFile->FileSize - Position;\r
+ } else {\r
+ //\r
+ // Run the file's cluster chain to find the current position\r
+ // If possible, run from the current cluster rather than\r
+ // start from beginning\r
+ // Assumption: OFile->Position is always consistent with\r
+ // OFile->FileCurrentCluster.\r
+ // OFile->Position is not modified outside this function;\r
+ // OFile->FileCurrentCluster is modified outside this function\r
+ // to be the same as OFile->FileCluster\r
+ // when OFile->FileCluster is updated, so make a check of this\r
+ // and invalidate the original OFile->Position in this case\r
+ //\r
+ Cluster = OFile->FileCurrentCluster;\r
+ StartPos = OFile->Position;\r
+ if (Position < StartPos || OFile->FileCluster == Cluster) {\r
+ StartPos = 0;\r
+ Cluster = OFile->FileCluster;\r
+ }\r
+\r
+ while (StartPos + ClusterSize <= Position) {\r
+ StartPos += ClusterSize;\r
+ if (Cluster == FAT_CLUSTER_FREE || (Cluster >= FAT_CLUSTER_SPECIAL)) {\r
+ DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatOFilePosition:"" cluster chain corrupt\n"));\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ Cluster = FatGetFatEntry (Volume, Cluster);\r
+ }\r
+\r
+ if (Cluster < FAT_MIN_CLUSTER) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ OFile->PosDisk = Volume->FirstClusterPos +\r
+ LShiftU64 (Cluster - FAT_MIN_CLUSTER, Volume->ClusterAlignment) +\r
+ Position - StartPos;\r
+ OFile->FileCurrentCluster = Cluster;\r
+ OFile->Position = StartPos;\r
+\r
+ //\r
+ // Compute the number of consecutive clusters in the file\r
+ //\r
+ Run = StartPos + ClusterSize - Position;\r
+ if (!FAT_END_OF_FAT_CHAIN (Cluster)) {\r
+ while ((FatGetFatEntry (Volume, Cluster) == Cluster + 1) && Run < PosLimit) {\r
+ Run += ClusterSize;\r
+ Cluster += 1;\r
+ }\r
+ }\r
+ }\r
+\r
+ OFile->PosRem = Run;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+UINTN\r
+FatPhysicalDirSize (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN Cluster\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the size of directory of the open file\r
+\r
+Arguments:\r
+\r
+ Volume - The File System Volume.\r
+ Cluster - The Starting cluster.\r
+\r
+Returns:\r
+\r
+ The physical size of the file starting at the input cluster, if there is error in the\r
+ cluster chain, the return value is 0.\r
+\r
+--*/\r
+{\r
+ UINTN Size;\r
+ ASSERT_VOLUME_LOCKED (Volume);\r
+ //\r
+ // Run the cluster chain for the OFile\r
+ //\r
+ Size = 0;\r
+ //\r
+ // N.B. ".." directories on some media do not contain a starting\r
+ // cluster. In the case of "." or ".." we don't need the size anyway.\r
+ //\r
+ if (Cluster != 0) {\r
+ while (!FAT_END_OF_FAT_CHAIN (Cluster)) {\r
+ if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {\r
+ DEBUG (\r
+ (EFI_D_INIT | EFI_D_ERROR,\r
+ "FATDirSize: cluster chain corrupt\n")\r
+ );\r
+ return 0;\r
+ }\r
+\r
+ Size += Volume->ClusterSize;\r
+ Cluster = FatGetFatEntry (Volume, Cluster);\r
+ }\r
+ }\r
+\r
+ return Size;\r
+}\r
+\r
+UINT64\r
+FatPhysicalFileSize (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN RealSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the physical size of a file on the disk.\r
+\r
+Arguments:\r
+\r
+ Volume - The file system volume.\r
+ RealSize - The real size of a file.\r
+\r
+Returns:\r
+\r
+ The physical size of a file on the disk.\r
+\r
+--*/\r
+{\r
+ UINTN ClusterSizeMask;\r
+ UINT64 PhysicalSize;\r
+ ClusterSizeMask = Volume->ClusterSize - 1;\r
+ PhysicalSize = (RealSize + ClusterSizeMask) & (~((UINT64) ClusterSizeMask));\r
+ return PhysicalSize;\r
+}\r
+\r
+VOID\r
+FatComputeFreeInfo (\r
+ IN FAT_VOLUME *Volume\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Update the free cluster info of FatInfoSector of the volume.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // If we don't have valid info, compute it now\r
+ //\r
+ if (!Volume->FreeInfoValid) {\r
+\r
+ Volume->FreeInfoValid = TRUE;\r
+ Volume->FatInfoSector.FreeInfo.ClusterCount = 0;\r
+ for (Index = Volume->MaxCluster + 1; Index >= FAT_MIN_CLUSTER; Index--) {\r
+ if (Volume->DiskError) {\r
+ break;\r
+ }\r
+\r
+ if (FatGetFatEntry (Volume, Index) == FAT_CLUSTER_FREE) {\r
+ Volume->FatInfoSector.FreeInfo.ClusterCount += 1;\r
+ Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;\r
+ }\r
+ }\r
+\r
+ Volume->FatInfoSector.Signature = FAT_INFO_SIGNATURE;\r
+ Volume->FatInfoSector.InfoBeginSignature = FAT_INFO_BEGIN_SIGNATURE;\r
+ Volume->FatInfoSector.InfoEndSignature = FAT_INFO_END_SIGNATURE;\r
+ }\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ flush.c\r
+\r
+Abstract:\r
+\r
+ Routines that check references and flush OFiles\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatFlushEx (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Flushes all data associated with the file handle.\r
+\r
+Arguments:\r
+\r
+ FHand - Handle to file to flush.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Flushed the file successfully.\r
+ EFI_WRITE_PROTECTED - The volume is read only.\r
+ EFI_ACCESS_DENIED - The file is read only.\r
+ Others - Flushing of the file failed.\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+ FAT_VOLUME *Volume;\r
+ EFI_STATUS Status;\r
+ FAT_TASK *Task;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+ Volume = OFile->Volume;\r
+ Task = NULL;\r
+\r
+ //\r
+ // If the file has a permanent error, return it\r
+ //\r
+ if (EFI_ERROR (OFile->Error)) {\r
+ return OFile->Error;\r
+ }\r
+\r
+ if (Volume->ReadOnly) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+ //\r
+ // If read only, return error\r
+ //\r
+ if (IFile->ReadOnly) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (Token == NULL) {\r
+ FatWaitNonblockingTask (IFile);\r
+ } else {\r
+ //\r
+ // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.\r
+ // But if it calls, the below check can avoid crash.\r
+ //\r
+ if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Task = FatCreateTask (IFile, Token);\r
+ if (Task == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Flush the OFile\r
+ //\r
+ FatAcquireLock ();\r
+ Status = FatOFileFlush (OFile);\r
+ Status = FatCleanupVolume (OFile->Volume, OFile, Status, Task);\r
+ FatReleaseLock ();\r
+\r
+ if (Token != NULL) {\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = FatQueueTask (IFile, Task);\r
+ } else {\r
+ FatDestroyTask (Task);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatFlush (\r
+ IN EFI_FILE_PROTOCOL *FHand\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Flushes all data associated with the file handle.\r
+\r
+Arguments:\r
+\r
+ FHand - Handle to file to flush.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Flushed the file successfully.\r
+ EFI_WRITE_PROTECTED - The volume is read only.\r
+ EFI_ACCESS_DENIED - The file is read only.\r
+ Others - Flushing of the file failed.\r
+\r
+--*/\r
+{\r
+ return FatFlushEx (FHand, NULL);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatClose (\r
+ IN EFI_FILE_PROTOCOL *FHand\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Flushes & Closes the file handle.\r
+\r
+Arguments:\r
+\r
+ FHand - Handle to the file to delete.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Closed the file successfully.\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+ FAT_VOLUME *Volume;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+ Volume = OFile->Volume;\r
+\r
+ //\r
+ // Lock the volume\r
+ //\r
+ FatAcquireLock ();\r
+\r
+ //\r
+ // Close the file instance handle\r
+ //\r
+ FatIFileClose (IFile);\r
+\r
+ //\r
+ // Done. Unlock the volume\r
+ //\r
+ FatCleanupVolume (Volume, OFile, EFI_SUCCESS, NULL);\r
+ FatReleaseLock ();\r
+\r
+ //\r
+ // Close always succeed\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatIFileClose (\r
+ FAT_IFILE *IFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Close the open file instance.\r
+\r
+Arguments:\r
+\r
+ IFile - Open file instance.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Closed the file successfully.\r
+\r
+--*/\r
+{\r
+ FAT_OFILE *OFile;\r
+ FAT_VOLUME *Volume;\r
+\r
+ OFile = IFile->OFile;\r
+ Volume = OFile->Volume;\r
+\r
+ ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+ FatWaitNonblockingTask (IFile);\r
+\r
+ //\r
+ // Remove the IFile struct\r
+ //\r
+ RemoveEntryList (&IFile->Link);\r
+\r
+ //\r
+ // Add the OFile to the check reference list\r
+ //\r
+ if (OFile->CheckLink.ForwardLink == NULL) {\r
+ InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);\r
+ }\r
+ //\r
+ // Done. Free the open instance structure\r
+ //\r
+ FreePool (IFile);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatOFileFlush (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Flush the data associated with an open file.\r
+ In this implementation, only last Mod/Access time is updated.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The OFile is flushed successfully.\r
+ Others - An error occurred when flushing this OFile.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_OFILE *Parent;\r
+ FAT_DIRENT *DirEnt;\r
+ FAT_DATE_TIME FatNow;\r
+\r
+ //\r
+ // Flush each entry up the tree while dirty\r
+ //\r
+ do {\r
+ //\r
+ // If the file has a permanant error, then don't write any\r
+ // of its data to the device (may be from different media)\r
+ //\r
+ if (EFI_ERROR (OFile->Error)) {\r
+ return OFile->Error;\r
+ }\r
+\r
+ Parent = OFile->Parent;\r
+ DirEnt = OFile->DirEnt;\r
+ if (OFile->Dirty) {\r
+ //\r
+ // Update the last modification time\r
+ //\r
+ FatGetCurrentFatTime (&FatNow);\r
+ CopyMem (&DirEnt->Entry.FileLastAccess, &FatNow.Date, sizeof (FAT_DATE));\r
+ if (!OFile->PreserveLastModification) {\r
+ FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime);\r
+ }\r
+\r
+ OFile->PreserveLastModification = FALSE;\r
+ if (OFile->Archive) {\r
+ DirEnt->Entry.Attributes |= FAT_ATTRIBUTE_ARCHIVE;\r
+ OFile->Archive = FALSE;\r
+ }\r
+ //\r
+ // Write the directory entry\r
+ //\r
+ if (Parent != NULL && !DirEnt->Invalid) {\r
+ //\r
+ // Write the OFile's directory entry\r
+ //\r
+ Status = FatStoreDirEnt (Parent, DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ OFile->Dirty = FALSE;\r
+ }\r
+ //\r
+ // Check the parent\r
+ //\r
+ OFile = Parent;\r
+ } while (OFile != NULL);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+BOOLEAN\r
+FatCheckOFileRef (\r
+ IN FAT_OFILE *OFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Check the references of the OFile.\r
+ If the OFile (that is checked) is no longer\r
+ referenced, then it is freed.\r
+\r
+Arguments:\r
+\r
+ OFile - The OFile to be checked.\r
+\r
+Returns:\r
+\r
+ TRUE - The OFile is not referenced and freed.\r
+ FALSE - The OFile is kept.\r
+\r
+--*/\r
+{\r
+ //\r
+ // If the OFile is on the check ref list, remove it\r
+ //\r
+ if (OFile->CheckLink.ForwardLink != NULL) {\r
+ RemoveEntryList (&OFile->CheckLink);\r
+ OFile->CheckLink.ForwardLink = NULL;\r
+ }\r
+\r
+ FatOFileFlush (OFile);\r
+ //\r
+ // Are there any references to this OFile?\r
+ //\r
+ if (!IsListEmpty (&OFile->Opens) || !IsListEmpty (&OFile->ChildHead)) {\r
+ //\r
+ // The OFile cannot be freed\r
+ //\r
+ return FALSE;\r
+ }\r
+ //\r
+ // Free the Ofile\r
+ //\r
+ FatCloseDirEnt (OFile->DirEnt);\r
+ return TRUE;\r
+}\r
+\r
+STATIC\r
+VOID\r
+FatCheckVolumeRef (\r
+ IN FAT_VOLUME *Volume\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Check the references of all open files on the volume.\r
+ Any open file (that is checked) that is no longer\r
+ referenced, is freed - and it's parent open file\r
+ is then referenced checked.\r
+\r
+Arguments:\r
+\r
+ Volume - The volume to check the pending open file list.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ FAT_OFILE *OFile;\r
+ FAT_OFILE *Parent;\r
+\r
+ //\r
+ // Check all files on the pending check list\r
+ //\r
+ while (!IsListEmpty (&Volume->CheckRef)) {\r
+ //\r
+ // Start with the first file listed\r
+ //\r
+ Parent = OFILE_FROM_CHECKLINK (Volume->CheckRef.ForwardLink);\r
+ //\r
+ // Go up the tree cleaning up any un-referenced OFiles\r
+ //\r
+ while (Parent != NULL) {\r
+ OFile = Parent;\r
+ Parent = OFile->Parent;\r
+ if (!FatCheckOFileRef (OFile)) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+FatCleanupVolume (\r
+ IN FAT_VOLUME *Volume,\r
+ IN FAT_OFILE *OFile,\r
+ IN EFI_STATUS EfiStatus,\r
+ IN FAT_TASK *Task\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set error status for a specific OFile, reference checking the volume.\r
+ If volume is already marked as invalid, and all resources are freed\r
+ after reference checking, the file system protocol is uninstalled and\r
+ the volume structure is freed.\r
+\r
+Arguments:\r
+\r
+ Volume - the Volume that is to be reference checked and unlocked.\r
+ OFile - the OFile whose permanent error code is to be set.\r
+ EfiStatus - error code to be set.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Clean up the volume successfully.\r
+ Others - Cleaning up of the volume is failed.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ //\r
+ // Flag the OFile\r
+ //\r
+ if (OFile != NULL) {\r
+ FatSetVolumeError (OFile, EfiStatus);\r
+ }\r
+ //\r
+ // Clean up any dangling OFiles that don't have IFiles\r
+ // we don't check return status here because we want the\r
+ // volume be cleaned up even the volume is invalid.\r
+ //\r
+ FatCheckVolumeRef (Volume);\r
+ if (Volume->Valid) {\r
+ //\r
+ // Update the free hint info. Volume->FreeInfoPos != 0\r
+ // indicates this a FAT32 volume\r
+ //\r
+ if (Volume->FreeInfoValid && Volume->FatDirty && Volume->FreeInfoPos) {\r
+ Status = FatDiskIo (Volume, WRITE_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, Task);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // Update that the volume is not dirty\r
+ //\r
+ if (Volume->FatDirty && Volume->FatType != FAT12) {\r
+ Volume->FatDirty = FALSE;\r
+ Status = FatAccessVolumeDirty (Volume, WRITE_FAT, &Volume->NotDirtyValue);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // Flush all dirty cache entries to disk\r
+ //\r
+ Status = FatVolumeFlushCache (Volume, Task);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ //\r
+ // If the volume is cleared , remove it.\r
+ // The only time volume be invalidated is in DriverBindingStop.\r
+ //\r
+ if (Volume->Root == NULL && !Volume->Valid) {\r
+ //\r
+ // Free the volume structure\r
+ //\r
+ FatFreeVolume (Volume);\r
+ }\r
+\r
+ return EfiStatus;\r
+}\r
+\r
+VOID\r
+FatSetVolumeError (\r
+ IN FAT_OFILE *OFile,\r
+ IN EFI_STATUS Status\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the OFile and its child OFile with the error Status\r
+\r
+Arguments:\r
+\r
+ OFile - The OFile whose permanent error code is to be set.\r
+ Status - Error code to be set.\r
+\r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ LIST_ENTRY *Link;\r
+ FAT_OFILE *ChildOFile;\r
+\r
+ //\r
+ // If this OFile doesn't already have an error, set one\r
+ //\r
+ if (!EFI_ERROR (OFile->Error)) {\r
+ OFile->Error = Status;\r
+ }\r
+ //\r
+ // Set the error on each child OFile\r
+ //\r
+ for (Link = OFile->ChildHead.ForwardLink; Link != &OFile->ChildHead; Link = Link->ForwardLink) {\r
+ ChildOFile = OFILE_FROM_CHILDLINK (Link);\r
+ FatSetVolumeError (ChildOFile, Status);\r
+ }\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Hash.c\r
+\r
+Abstract:\r
+\r
+ Hash table operations\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+STATIC\r
+UINT32\r
+FatHashLongName (\r
+ IN CHAR16 *LongNameString\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get hash value for long name.\r
+\r
+Arguments:\r
+\r
+ LongNameString - The long name string to be hashed.\r
+\r
+Returns:\r
+\r
+ HashValue.\r
+\r
+--*/\r
+{\r
+ UINT32 HashValue;\r
+ CHAR16 UpCasedLongFileName[EFI_PATH_STRING_LENGTH];\r
+ StrnCpyS (\r
+ UpCasedLongFileName,\r
+ sizeof (UpCasedLongFileName) / sizeof (UpCasedLongFileName[0]),\r
+ LongNameString,\r
+ sizeof (UpCasedLongFileName) / sizeof (UpCasedLongFileName[0]) - 1\r
+ );\r
+ FatStrUpr (UpCasedLongFileName);\r
+ gBS->CalculateCrc32 (UpCasedLongFileName, StrSize (UpCasedLongFileName), &HashValue);\r
+ return (HashValue & HASH_TABLE_MASK);\r
+}\r
+\r
+STATIC\r
+UINT32\r
+FatHashShortName (\r
+ IN CHAR8 *ShortNameString\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get hash value for short name.\r
+\r
+Arguments:\r
+\r
+ ShortNameString - The short name string to be hashed.\r
+\r
+Returns:\r
+\r
+ HashValue\r
+\r
+--*/\r
+{\r
+ UINT32 HashValue;\r
+ gBS->CalculateCrc32 (ShortNameString, FAT_NAME_LEN, &HashValue);\r
+ return (HashValue & HASH_TABLE_MASK);\r
+}\r
+\r
+FAT_DIRENT **\r
+FatLongNameHashSearch (\r
+ IN FAT_ODIR *ODir,\r
+ IN CHAR16 *LongNameString\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Search the long name hash table for the directory entry.\r
+\r
+Arguments:\r
+\r
+ ODir - The directory to be searched.\r
+ LongNameString - The long name string to search.\r
+\r
+Returns:\r
+\r
+ The previous long name hash node of the directory entry.\r
+\r
+--*/\r
+{\r
+ FAT_DIRENT **PreviousHashNode;\r
+ for (PreviousHashNode = &ODir->LongNameHashTable[FatHashLongName (LongNameString)];\r
+ *PreviousHashNode != NULL;\r
+ PreviousHashNode = &(*PreviousHashNode)->LongNameForwardLink\r
+ ) {\r
+ if (FatStriCmp (LongNameString, (*PreviousHashNode)->FileString) == 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return PreviousHashNode;\r
+}\r
+\r
+FAT_DIRENT **\r
+FatShortNameHashSearch (\r
+ IN FAT_ODIR *ODir,\r
+ IN CHAR8 *ShortNameString\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Search the short name hash table for the directory entry.\r
+\r
+Arguments:\r
+\r
+ ODir - The directory to be searched.\r
+ ShortNameString - The short name string to search.\r
+\r
+Returns:\r
+\r
+ The previous short name hash node of the directory entry.\r
+\r
+--*/\r
+{\r
+ FAT_DIRENT **PreviousHashNode;\r
+ for (PreviousHashNode = &ODir->ShortNameHashTable[FatHashShortName (ShortNameString)];\r
+ *PreviousHashNode != NULL;\r
+ PreviousHashNode = &(*PreviousHashNode)->ShortNameForwardLink\r
+ ) {\r
+ if (CompareMem (ShortNameString, (*PreviousHashNode)->Entry.FileName, FAT_NAME_LEN) == 0) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ return PreviousHashNode;\r
+}\r
+\r
+VOID\r
+FatInsertToHashTable (\r
+ IN FAT_ODIR *ODir,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Insert directory entry to hash table.\r
+\r
+Arguments:\r
+\r
+ ODir - The parent directory.\r
+ DirEnt - The directory entry node.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ FAT_DIRENT **HashTable;\r
+ UINT32 HashTableIndex;\r
+\r
+ //\r
+ // Insert hash table index for short name\r
+ //\r
+ HashTableIndex = FatHashShortName (DirEnt->Entry.FileName);\r
+ HashTable = ODir->ShortNameHashTable;\r
+ DirEnt->ShortNameForwardLink = HashTable[HashTableIndex];\r
+ HashTable[HashTableIndex] = DirEnt;\r
+ //\r
+ // Insert hash table index for long name\r
+ //\r
+ HashTableIndex = FatHashLongName (DirEnt->FileString);\r
+ HashTable = ODir->LongNameHashTable;\r
+ DirEnt->LongNameForwardLink = HashTable[HashTableIndex];\r
+ HashTable[HashTableIndex] = DirEnt;\r
+}\r
+\r
+VOID\r
+FatDeleteFromHashTable (\r
+ IN FAT_ODIR *ODir,\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Delete directory entry from hash table.\r
+\r
+Arguments:\r
+\r
+ ODir - The parent directory.\r
+ DirEnt - The directory entry node.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ *FatShortNameHashSearch (ODir, DirEnt->Entry.FileName) = DirEnt->ShortNameForwardLink;\r
+ *FatLongNameHashSearch (ODir, DirEnt->FileString) = DirEnt->LongNameForwardLink;\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Info.c\r
+\r
+Abstract:\r
+\r
+ Routines dealing with setting/getting file/volume info\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+FatGetVolumeInfo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+EFI_STATUS\r
+FatSetVolumeInfo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN OUT UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+EFI_STATUS\r
+FatSetOrGetInfo (\r
+ IN BOOLEAN IsSet,\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN EFI_GUID *Type,\r
+ IN OUT UINTN *BufferSize,\r
+ IN OUT VOID *Buffer\r
+ );\r
+\r
+EFI_STATUS\r
+FatGetFileInfo (\r
+ IN FAT_OFILE *OFile,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the open file's info into Buffer.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing file info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_BUFFER_TOO_SMALL - The buffer is too small.\r
+\r
+--*/\r
+{\r
+ return FatGetDirEntInfo (OFile->Volume, OFile->DirEnt, BufferSize, Buffer);\r
+}\r
+\r
+EFI_STATUS\r
+FatGetVolumeInfo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the volume's info into Buffer.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the volume info successfully.\r
+ EFI_BUFFER_TOO_SMALL - The buffer is too small.\r
+\r
+--*/\r
+{\r
+ UINTN Size;\r
+ UINTN NameSize;\r
+ UINTN ResultSize;\r
+ CHAR16 Name[FAT_NAME_LEN + 1];\r
+ EFI_STATUS Status;\r
+ EFI_FILE_SYSTEM_INFO *Info;\r
+ UINT8 ClusterAlignment;\r
+\r
+ Size = SIZE_OF_EFI_FILE_SYSTEM_INFO;\r
+ Status = FatGetVolumeEntry (Volume, Name);\r
+ NameSize = StrSize (Name);\r
+ ResultSize = Size + NameSize;\r
+ ClusterAlignment = Volume->ClusterAlignment;\r
+\r
+ //\r
+ // If we don't have valid info, compute it now\r
+ //\r
+ FatComputeFreeInfo (Volume);\r
+\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ if (*BufferSize >= ResultSize) {\r
+ Status = EFI_SUCCESS;\r
+\r
+ Info = Buffer;\r
+ ZeroMem (Info, SIZE_OF_EFI_FILE_SYSTEM_INFO);\r
+\r
+ Info->Size = ResultSize;\r
+ Info->ReadOnly = Volume->ReadOnly;\r
+ Info->BlockSize = (UINT32) Volume->ClusterSize;\r
+ Info->VolumeSize = LShiftU64 (Volume->MaxCluster, ClusterAlignment);\r
+ Info->FreeSpace = LShiftU64 (\r
+ Volume->FatInfoSector.FreeInfo.ClusterCount,\r
+ ClusterAlignment\r
+ );\r
+ CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);\r
+ }\r
+\r
+ *BufferSize = ResultSize;\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatGetVolumeLabelInfo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the volume's label info into Buffer.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing volume's label info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the volume's label info successfully.\r
+ EFI_BUFFER_TOO_SMALL - The buffer is too small.\r
+\r
+--*/\r
+{\r
+ UINTN Size;\r
+ UINTN NameSize;\r
+ UINTN ResultSize;\r
+ CHAR16 Name[FAT_NAME_LEN + 1];\r
+ EFI_STATUS Status;\r
+\r
+ Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL;\r
+ Status = FatGetVolumeEntry (Volume, Name);\r
+ NameSize = StrSize (Name);\r
+ ResultSize = Size + NameSize;\r
+\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ if (*BufferSize >= ResultSize) {\r
+ Status = EFI_SUCCESS;\r
+ CopyMem ((CHAR8 *) Buffer + Size, Name, NameSize);\r
+ }\r
+\r
+ *BufferSize = ResultSize;\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatSetVolumeInfo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the volume's info.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing the new volume info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the volume info successfully.\r
+ EFI_BAD_BUFFER_SIZE - The buffer size is error.\r
+ EFI_WRITE_PROTECTED - The volume is read only.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ EFI_FILE_SYSTEM_INFO *Info;\r
+\r
+ Info = (EFI_FILE_SYSTEM_INFO *) Buffer;\r
+\r
+ if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + 2 || Info->Size > BufferSize) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ return FatSetVolumeEntry (Volume, Info->VolumeLabel);\r
+}\r
+\r
+EFI_STATUS\r
+FatSetVolumeLabelInfo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the volume's label info\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing the new volume label info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the volume label info successfully.\r
+ EFI_WRITE_PROTECTED - The disk is write protected.\r
+ EFI_BAD_BUFFER_SIZE - The buffer size is error.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ EFI_FILE_SYSTEM_VOLUME_LABEL *Info;\r
+\r
+ Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) Buffer;\r
+\r
+ if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 2) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ return FatSetVolumeEntry (Volume, Info->VolumeLabel);\r
+}\r
+\r
+EFI_STATUS\r
+FatSetFileInfo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN FAT_IFILE *IFile,\r
+ IN FAT_OFILE *OFile,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the file info.\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ IFile - The instance of the open file.\r
+ OFile - The open file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing the new file info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the file info successfully.\r
+ EFI_ACCESS_DENIED - It is the root directory\r
+ or the directory attribute bit can not change\r
+ or try to change a directory size\r
+ or something else.\r
+ EFI_UNSUPPORTED - The new file size is larger than 4GB.\r
+ EFI_WRITE_PROTECTED - The disk is write protected.\r
+ EFI_BAD_BUFFER_SIZE - The buffer size is error.\r
+ EFI_INVALID_PARAMETER - The time info or attributes info is error.\r
+ EFI_OUT_OF_RESOURCES - Can not allocate new memory.\r
+ EFI_VOLUME_CORRUPTED - The volume is corrupted.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE_INFO *NewInfo;\r
+ FAT_OFILE *DotOFile;\r
+ FAT_OFILE *Parent;\r
+ CHAR16 NewFileName[EFI_PATH_STRING_LENGTH];\r
+ EFI_TIME ZeroTime;\r
+ FAT_DIRENT *DirEnt;\r
+ FAT_DIRENT *TempDirEnt;\r
+ UINT8 NewAttribute;\r
+ BOOLEAN ReadOnly;\r
+\r
+ ZeroMem (&ZeroTime, sizeof (EFI_TIME));\r
+ Parent = OFile->Parent;\r
+ DirEnt = OFile->DirEnt;\r
+ //\r
+ // If this is the root directory, we can't make any updates\r
+ //\r
+ if (Parent == NULL) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ //\r
+ // Make sure there's a valid input buffer\r
+ //\r
+ NewInfo = Buffer;\r
+ if (BufferSize < SIZE_OF_EFI_FILE_INFO + 2 || NewInfo->Size > BufferSize) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ ReadOnly = (BOOLEAN)(IFile->ReadOnly || (DirEnt->Entry.Attributes & EFI_FILE_READ_ONLY));\r
+ //\r
+ // if a zero time is specified, then the original time is preserved\r
+ //\r
+ if (CompareMem (&ZeroTime, &NewInfo->CreateTime, sizeof (EFI_TIME)) != 0) {\r
+ if (!FatIsValidTime (&NewInfo->CreateTime)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!ReadOnly) {\r
+ FatEfiTimeToFatTime (&NewInfo->CreateTime, &DirEnt->Entry.FileCreateTime);\r
+ }\r
+ }\r
+\r
+ if (CompareMem (&ZeroTime, &NewInfo->ModificationTime, sizeof (EFI_TIME)) != 0) {\r
+ if (!FatIsValidTime (&NewInfo->ModificationTime)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (!ReadOnly) {\r
+ FatEfiTimeToFatTime (&NewInfo->ModificationTime, &DirEnt->Entry.FileModificationTime);\r
+ }\r
+\r
+ OFile->PreserveLastModification = TRUE;\r
+ }\r
+\r
+ if (NewInfo->Attribute & (~EFI_FILE_VALID_ATTR)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NewAttribute = (UINT8) NewInfo->Attribute;\r
+ //\r
+ // Can not change the directory attribute bit\r
+ //\r
+ if ((NewAttribute ^ DirEnt->Entry.Attributes) & EFI_FILE_DIRECTORY) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ //\r
+ // Set the current attributes even if the IFile->ReadOnly is TRUE\r
+ //\r
+ DirEnt->Entry.Attributes = (UINT8) ((DirEnt->Entry.Attributes &~EFI_FILE_VALID_ATTR) | NewAttribute);\r
+ //\r
+ // Open the filename and see if it refers to an existing file\r
+ //\r
+ Status = FatLocateOFile (&Parent, NewInfo->FileName, DirEnt->Entry.Attributes, NewFileName);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (*NewFileName != 0) {\r
+ //\r
+ // File was not found. We do not allow rename of the current directory if\r
+ // there are open files below the current directory\r
+ //\r
+ if (!IsListEmpty (&OFile->ChildHead) || Parent == OFile) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (ReadOnly) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ Status = FatRemoveDirEnt (OFile->Parent, DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Create new dirent\r
+ //\r
+ Status = FatCreateDirEnt (Parent, NewFileName, DirEnt->Entry.Attributes, &TempDirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FatCloneDirEnt (TempDirEnt, DirEnt);\r
+ FatFreeDirEnt (DirEnt);\r
+ DirEnt = TempDirEnt;\r
+ DirEnt->OFile = OFile;\r
+ OFile->DirEnt = DirEnt;\r
+ OFile->Parent = Parent;\r
+ RemoveEntryList (&OFile->ChildLink);\r
+ InsertHeadList (&Parent->ChildHead, &OFile->ChildLink);\r
+ //\r
+ // If this is a directory, synchronize its dot directory entry\r
+ //\r
+ if (OFile->ODir != NULL) {\r
+ //\r
+ // Syncronize its dot entry\r
+ //\r
+ FatResetODirCursor (OFile);\r
+ ASSERT (OFile->Parent != NULL);\r
+ for (DotOFile = OFile; DotOFile != OFile->Parent->Parent; DotOFile = DotOFile->Parent) {\r
+ Status = FatGetNextDirEnt (OFile, &DirEnt);\r
+ if (EFI_ERROR (Status) || DirEnt == NULL || !FatIsDotDirEnt (DirEnt)) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ FatCloneDirEnt (DirEnt, DotOFile->DirEnt);\r
+ Status = FatStoreDirEnt (OFile, DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // If the file is renamed, we should append the ARCHIVE attribute\r
+ //\r
+ OFile->Archive = TRUE;\r
+ } else if (Parent != OFile) {\r
+ //\r
+ // filename is to a different filename that already exists\r
+ //\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ //\r
+ // If the file size has changed, apply it\r
+ //\r
+ if (NewInfo->FileSize != OFile->FileSize) {\r
+ if (OFile->ODir != NULL || ReadOnly) {\r
+ //\r
+ // If this is a directory or the file is read only, we can't change the file size\r
+ //\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ if (NewInfo->FileSize > OFile->FileSize) {\r
+ Status = FatExpandOFile (OFile, NewInfo->FileSize);\r
+ } else {\r
+ Status = FatTruncateOFile (OFile, (UINTN) NewInfo->FileSize);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ FatUpdateDirEntClusterSizeInfo (OFile);\r
+ }\r
+\r
+ OFile->Dirty = TRUE;\r
+ return FatOFileFlush (OFile);\r
+}\r
+\r
+EFI_STATUS\r
+FatSetOrGetInfo (\r
+ IN BOOLEAN IsSet,\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN EFI_GUID *Type,\r
+ IN OUT UINTN *BufferSize,\r
+ IN OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set or Get the some types info of the file into Buffer\r
+\r
+Arguments:\r
+\r
+ IsSet - TRUE:The access is set, else is get\r
+ FHand - The handle of file\r
+ Type - The type of the info\r
+ BufferSize - Size of Buffer\r
+ Buffer - Buffer containing volume info\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the info successfully\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+ FAT_VOLUME *Volume;\r
+ EFI_STATUS Status;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+ Volume = OFile->Volume;\r
+\r
+ Status = OFile->Error;\r
+ if (Status == EFI_NOT_FOUND) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ FatWaitNonblockingTask (IFile);\r
+\r
+ FatAcquireLock ();\r
+\r
+ //\r
+ // Verify the file handle isn't in an error state\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Get the proper information based on the request\r
+ //\r
+ Status = EFI_UNSUPPORTED;\r
+ if (IsSet) {\r
+ if (CompareGuid (Type, &gEfiFileInfoGuid)) {\r
+ Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetFileInfo (Volume, IFile, OFile, *BufferSize, Buffer);\r
+ }\r
+\r
+ if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {\r
+ Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeInfo (Volume, *BufferSize, Buffer);\r
+ }\r
+\r
+ if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
+ Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeLabelInfo (Volume, *BufferSize, Buffer);\r
+ }\r
+ } else {\r
+ if (CompareGuid (Type, &gEfiFileInfoGuid)) {\r
+ Status = FatGetFileInfo (OFile, BufferSize, Buffer);\r
+ }\r
+\r
+ if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {\r
+ Status = FatGetVolumeInfo (Volume, BufferSize, Buffer);\r
+ }\r
+\r
+ if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
+ Status = FatGetVolumeLabelInfo (Volume, BufferSize, Buffer);\r
+ }\r
+ }\r
+ }\r
+\r
+ Status = FatCleanupVolume (Volume, NULL, Status, NULL);\r
+\r
+ FatReleaseLock ();\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatGetInfo (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN EFI_GUID *Type,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the some types info of the file into Buffer.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file.\r
+ Type - The type of the info.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+\r
+--*/\r
+{\r
+ return FatSetOrGetInfo (FALSE, FHand, Type, BufferSize, Buffer);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatSetInfo (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN EFI_GUID *Type,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the some types info of the file into Buffer.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file.\r
+ Type - The type of the info.\r
+ BufferSize - Size of Buffer\r
+ Buffer - Buffer containing volume info.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+\r
+--*/\r
+{\r
+ return FatSetOrGetInfo (TRUE, FHand, Type, &BufferSize, Buffer);\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Init.c\r
+\r
+Abstract:\r
+\r
+ Initialization routines\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+FatAllocateVolume (\r
+ IN EFI_HANDLE Handle,\r
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
+ IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
+ IN EFI_BLOCK_IO_PROTOCOL *BlockIo\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Allocates volume structure, detects FAT file system, installs protocol,\r
+ and initialize cache.\r
+\r
+Arguments:\r
+\r
+ Handle - The handle of parent device.\r
+ DiskIo - The DiskIo of parent device.\r
+ BlockIo - The BlockIo of parent devicel\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Allocate a new volume successfully.\r
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory.\r
+ Others - Allocating a new volume failed.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_VOLUME *Volume;\r
+\r
+ //\r
+ // Allocate a volume structure\r
+ //\r
+ Volume = AllocateZeroPool (sizeof (FAT_VOLUME));\r
+ if (Volume == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Initialize the structure\r
+ //\r
+ Volume->Signature = FAT_VOLUME_SIGNATURE;\r
+ Volume->Handle = Handle;\r
+ Volume->DiskIo = DiskIo;\r
+ Volume->DiskIo2 = DiskIo2;\r
+ Volume->BlockIo = BlockIo;\r
+ Volume->MediaId = BlockIo->Media->MediaId;\r
+ Volume->ReadOnly = BlockIo->Media->ReadOnly;\r
+ Volume->VolumeInterface.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;\r
+ Volume->VolumeInterface.OpenVolume = FatOpenVolume;\r
+ InitializeListHead (&Volume->CheckRef);\r
+ InitializeListHead (&Volume->DirCacheList);\r
+ //\r
+ // Initialize Root Directory entry\r
+ //\r
+ Volume->RootDirEnt.FileString = Volume->RootFileString;\r
+ Volume->RootDirEnt.Entry.Attributes = FAT_ATTRIBUTE_DIRECTORY;\r
+ //\r
+ // Check to see if there's a file system on the volume\r
+ //\r
+ Status = FatOpenDevice (Volume);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Initialize cache\r
+ //\r
+ Status = FatInitializeDiskCache (Volume);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Install our protocol interfaces on the device's handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Volume->Handle,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ &Volume->VolumeInterface,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Volume installed\r
+ //\r
+ DEBUG ((EFI_D_INIT, "Installed Fat filesystem on %p\n", Handle));\r
+ Volume->Valid = TRUE;\r
+\r
+Done:\r
+ if (EFI_ERROR (Status)) {\r
+ FatFreeVolume (Volume);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatAbandonVolume (\r
+ IN FAT_VOLUME *Volume\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Called by FatDriverBindingStop(), Abandon the volume.\r
+\r
+Arguments:\r
+\r
+ Volume - The volume to be abandoned.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Abandoned the volume successfully.\r
+ Others - Can not uninstall the protocol interfaces.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN LockedByMe;\r
+\r
+ //\r
+ // Uninstall the protocol interface.\r
+ //\r
+ if (Volume->Handle != NULL) {\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ Volume->Handle,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ &Volume->VolumeInterface,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ LockedByMe = FALSE;\r
+\r
+ //\r
+ // Acquire the lock.\r
+ // If the caller has already acquired the lock (which\r
+ // means we are in the process of some Fat operation),\r
+ // we can not acquire again.\r
+ //\r
+ Status = FatAcquireLockOrFail ();\r
+ if (!EFI_ERROR (Status)) {\r
+ LockedByMe = TRUE;\r
+ }\r
+ //\r
+ // The volume is still being used. Hence, set error flag for all OFiles still in\r
+ // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is\r
+ // EFI_NO_MEDIA.\r
+ //\r
+ if (Volume->Root != NULL) {\r
+ FatSetVolumeError (\r
+ Volume->Root,\r
+ Volume->BlockIo->Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA\r
+ );\r
+ }\r
+\r
+ Volume->Valid = FALSE;\r
+\r
+ //\r
+ // Release the lock.\r
+ // If locked by me, this means DriverBindingStop is NOT\r
+ // called within an on-going Fat operation, so we should\r
+ // take responsibility to cleanup and free the volume.\r
+ // Otherwise, the DriverBindingStop is called within an on-going\r
+ // Fat operation, we shouldn't check reference, so just let outer\r
+ // FatCleanupVolume do the task.\r
+ //\r
+ if (LockedByMe) {\r
+ FatCleanupVolume (Volume, NULL, EFI_SUCCESS, NULL);\r
+ FatReleaseLock ();\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatOpenDevice (\r
+ IN OUT FAT_VOLUME *Volume\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Detects FAT file system on Disk and set relevant fields of Volume\r
+\r
+Arguments:\r
+\r
+ Volume - The volume structure.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The Fat File System is detected successfully\r
+ EFI_UNSUPPORTED - The volume is not FAT file system.\r
+ EFI_VOLUME_CORRUPTED - The volume is corrupted.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ UINT32 DirtyMask;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ FAT_BOOT_SECTOR FatBs;\r
+ FAT_VOLUME_TYPE FatType;\r
+ UINTN RootDirSectors;\r
+ UINTN FatLba;\r
+ UINTN RootLba;\r
+ UINTN FirstClusterLba;\r
+ UINTN Sectors;\r
+ UINTN SectorsPerFat;\r
+ UINT8 SectorsPerClusterAlignment;\r
+ UINT8 BlockAlignment;\r
+\r
+ //\r
+ // Read the FAT_BOOT_SECTOR BPB info\r
+ // This is the only part of FAT code that uses parent DiskIo,\r
+ // Others use FatDiskIo which utilizes a Cache.\r
+ //\r
+ DiskIo = Volume->DiskIo;\r
+ Status = DiskIo->ReadDisk (DiskIo, Volume->MediaId, 0, sizeof (FatBs), &FatBs);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INIT, "FatOpenDevice: read of part_lba failed %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ FatType = FatUndefined;\r
+\r
+ //\r
+ // Use LargeSectors if Sectors is 0\r
+ //\r
+ Sectors = FatBs.FatBsb.Sectors;\r
+ if (Sectors == 0) {\r
+ Sectors = FatBs.FatBsb.LargeSectors;\r
+ }\r
+\r
+ SectorsPerFat = FatBs.FatBsb.SectorsPerFat;\r
+ if (SectorsPerFat == 0) {\r
+ SectorsPerFat = FatBs.FatBse.Fat32Bse.LargeSectorsPerFat;\r
+ FatType = FAT32;\r
+ }\r
+ //\r
+ // Is boot sector a fat sector?\r
+ // (Note that so far we only know if the sector is FAT32 or not, we don't\r
+ // know if the sector is Fat16 or Fat12 until later when we can compute\r
+ // the volume size)\r
+ //\r
+ if (FatBs.FatBsb.ReservedSectors == 0 || FatBs.FatBsb.NumFats == 0 || Sectors == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if ((FatBs.FatBsb.SectorSize & (FatBs.FatBsb.SectorSize - 1)) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ BlockAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorSize);\r
+ if (BlockAlignment > MAX_BLOCK_ALIGNMENT || BlockAlignment < MIN_BLOCK_ALIGNMENT) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if ((FatBs.FatBsb.SectorsPerCluster & (FatBs.FatBsb.SectorsPerCluster - 1)) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ SectorsPerClusterAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorsPerCluster);\r
+ if (SectorsPerClusterAlignment > MAX_SECTORS_PER_CLUSTER_ALIGNMENT) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (FatBs.FatBsb.Media <= 0xf7 &&\r
+ FatBs.FatBsb.Media != 0xf0 &&\r
+ FatBs.FatBsb.Media != 0x00 &&\r
+ FatBs.FatBsb.Media != 0x01\r
+ ) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Initialize fields the volume information for this FatType\r
+ //\r
+ if (FatType != FAT32) {\r
+ if (FatBs.FatBsb.RootEntries == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Unpack fat12, fat16 info\r
+ //\r
+ Volume->RootEntries = FatBs.FatBsb.RootEntries;\r
+ } else {\r
+ //\r
+ // If this is fat32, refuse to mount mirror-disabled volumes\r
+ //\r
+ if ((SectorsPerFat == 0 || FatBs.FatBse.Fat32Bse.FsVersion != 0) || (FatBs.FatBse.Fat32Bse.ExtendedFlags & 0x80)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ //\r
+ // Unpack fat32 info\r
+ //\r
+ Volume->RootCluster = FatBs.FatBse.Fat32Bse.RootDirFirstCluster;\r
+ }\r
+\r
+ Volume->NumFats = FatBs.FatBsb.NumFats;\r
+ //\r
+ // Compute some fat locations\r
+ //\r
+ BlockSize = FatBs.FatBsb.SectorSize;\r
+ RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (BlockSize - 1)) / BlockSize;\r
+\r
+ FatLba = FatBs.FatBsb.ReservedSectors;\r
+ RootLba = FatBs.FatBsb.NumFats * SectorsPerFat + FatLba;\r
+ FirstClusterLba = RootLba + RootDirSectors;\r
+\r
+ Volume->FatPos = FatLba * BlockSize;\r
+ Volume->FatSize = SectorsPerFat * BlockSize;\r
+\r
+ Volume->VolumeSize = LShiftU64 (Sectors, BlockAlignment);\r
+ Volume->RootPos = LShiftU64 (RootLba, BlockAlignment);\r
+ Volume->FirstClusterPos = LShiftU64 (FirstClusterLba, BlockAlignment);\r
+ Volume->MaxCluster = (Sectors - FirstClusterLba) >> SectorsPerClusterAlignment;\r
+ Volume->ClusterAlignment = (UINT8)(BlockAlignment + SectorsPerClusterAlignment);\r
+ Volume->ClusterSize = (UINTN)1 << (Volume->ClusterAlignment);\r
+\r
+ //\r
+ // If this is not a fat32, determine if it's a fat16 or fat12\r
+ //\r
+ if (FatType != FAT32) {\r
+ if (Volume->MaxCluster >= FAT_MAX_FAT16_CLUSTER) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+\r
+ FatType = Volume->MaxCluster < FAT_MAX_FAT12_CLUSTER ? FAT12 : FAT16;\r
+ //\r
+ // fat12 & fat16 fat-entries are 2 bytes\r
+ //\r
+ Volume->FatEntrySize = sizeof (UINT16);\r
+ DirtyMask = FAT16_DIRTY_MASK;\r
+ } else {\r
+ if (Volume->MaxCluster < FAT_MAX_FAT16_CLUSTER) {\r
+ return EFI_VOLUME_CORRUPTED;\r
+ }\r
+ //\r
+ // fat32 fat-entries are 4 bytes\r
+ //\r
+ Volume->FatEntrySize = sizeof (UINT32);\r
+ DirtyMask = FAT32_DIRTY_MASK;\r
+ }\r
+ //\r
+ // Get the DirtyValue and NotDirtyValue\r
+ // We should keep the initial value as the NotDirtyValue\r
+ // in case the volume is dirty already\r
+ //\r
+ if (FatType != FAT12) {\r
+ Status = FatAccessVolumeDirty (Volume, READ_DISK, &Volume->NotDirtyValue);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Volume->DirtyValue = Volume->NotDirtyValue & DirtyMask;\r
+ }\r
+ //\r
+ // If present, read the fat hint info\r
+ //\r
+ if (FatType == FAT32) {\r
+ Volume->FreeInfoPos = FatBs.FatBse.Fat32Bse.FsInfoSector * BlockSize;\r
+ if (FatBs.FatBse.Fat32Bse.FsInfoSector != 0) {\r
+ FatDiskIo (Volume, READ_DISK, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, NULL);\r
+ if (Volume->FatInfoSector.Signature == FAT_INFO_SIGNATURE &&\r
+ Volume->FatInfoSector.InfoBeginSignature == FAT_INFO_BEGIN_SIGNATURE &&\r
+ Volume->FatInfoSector.InfoEndSignature == FAT_INFO_END_SIGNATURE &&\r
+ Volume->FatInfoSector.FreeInfo.ClusterCount <= Volume->MaxCluster\r
+ ) {\r
+ Volume->FreeInfoValid = TRUE;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Just make up a FreeInfo.NextCluster for use by allocate cluster\r
+ //\r
+ if (FAT_MIN_CLUSTER > Volume->FatInfoSector.FreeInfo.NextCluster ||\r
+ Volume->FatInfoSector.FreeInfo.NextCluster > Volume->MaxCluster + 1\r
+ ) {\r
+ Volume->FatInfoSector.FreeInfo.NextCluster = FAT_MIN_CLUSTER;\r
+ }\r
+ //\r
+ // We are now defining FAT Type\r
+ //\r
+ Volume->FatType = FatType;\r
+ ASSERT (FatType != FatUndefined);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ Misc.c\r
+\r
+Abstract:\r
+\r
+ Miscellaneous functions\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+FAT_TASK *\r
+FatCreateTask (\r
+ FAT_IFILE *IFile,\r
+ EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Create the task\r
+\r
+Arguments:\r
+\r
+ IFile - The instance of the open file.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Return:\r
+ FAT_TASK * - Return the task instance.\r
+**/\r
+{\r
+ FAT_TASK *Task;\r
+\r
+ Task = AllocateZeroPool (sizeof (*Task));\r
+ if (Task != NULL) {\r
+ Task->Signature = FAT_TASK_SIGNATURE;\r
+ Task->IFile = IFile;\r
+ Task->FileIoToken = Token;\r
+ InitializeListHead (&Task->Subtasks);\r
+ InitializeListHead (&Task->Link);\r
+ }\r
+ return Task;\r
+}\r
+\r
+VOID\r
+FatDestroyTask (\r
+ FAT_TASK *Task\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Destroy the task\r
+\r
+Arguments:\r
+\r
+ Task - The task to be destroyed.\r
+**/\r
+{\r
+ LIST_ENTRY *Link;\r
+ FAT_SUBTASK *Subtask;\r
+\r
+ Link = GetFirstNode (&Task->Subtasks);\r
+ while (!IsNull (&Task->Subtasks, Link)) {\r
+ Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
+ Link = FatDestroySubtask (Subtask);\r
+ }\r
+ FreePool (Task);\r
+}\r
+\r
+VOID\r
+FatWaitNonblockingTask (\r
+ FAT_IFILE *IFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Wait all non-blocking requests complete.\r
+\r
+Arguments:\r
+\r
+ IFile - The instance of the open file.\r
+**/\r
+{\r
+ BOOLEAN TaskQueueEmpty;\r
+\r
+ do {\r
+ EfiAcquireLock (&FatTaskLock);\r
+ TaskQueueEmpty = IsListEmpty (&IFile->Tasks);\r
+ EfiReleaseLock (&FatTaskLock);\r
+ } while (!TaskQueueEmpty);\r
+}\r
+\r
+LIST_ENTRY *\r
+FatDestroySubtask (\r
+ FAT_SUBTASK *Subtask\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Remove the subtask from subtask list.\r
+\r
+Arguments:\r
+\r
+ Subtask - The subtask to be removed.\r
+\r
+Returns:\r
+\r
+ LIST_ENTRY * - The next node in the list.\r
+\r
+--*/\r
+{\r
+ LIST_ENTRY *Link;\r
+\r
+ gBS->CloseEvent (Subtask->DiskIo2Token.Event);\r
+\r
+ Link = RemoveEntryList (&Subtask->Link);\r
+ FreePool (Subtask);\r
+\r
+ return Link;\r
+}\r
+\r
+EFI_STATUS\r
+FatQueueTask (\r
+ IN FAT_IFILE *IFile,\r
+ IN FAT_TASK *Task\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Execute the task\r
+\r
+Arguments:\r
+\r
+ IFile - The instance of the open file.\r
+ Task - The task to be executed.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The task was executed sucessfully.\r
+ other - An error occurred when executing the task.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ LIST_ENTRY *Link;\r
+ FAT_SUBTASK *Subtask;\r
+\r
+ //\r
+ // Sometimes the Task doesn't contain any subtasks, signal the event directly.\r
+ //\r
+ if (IsListEmpty (&Task->Subtasks)) {\r
+ Task->FileIoToken->Status = EFI_SUCCESS;\r
+ gBS->SignalEvent (Task->FileIoToken->Event);\r
+ FreePool (Task);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ EfiAcquireLock (&FatTaskLock);\r
+ InsertTailList (&IFile->Tasks, &Task->Link);\r
+ EfiReleaseLock (&FatTaskLock);\r
+\r
+ Status = EFI_SUCCESS;\r
+ for ( Link = GetFirstNode (&Task->Subtasks)\r
+ ; !IsNull (&Task->Subtasks, Link)\r
+ ; Link = GetNextNode (&Task->Subtasks, Link)\r
+ ) {\r
+ Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
+ if (Subtask->Write) {\r
+ \r
+ Status = IFile->OFile->Volume->DiskIo2->WriteDiskEx (\r
+ IFile->OFile->Volume->DiskIo2,\r
+ IFile->OFile->Volume->MediaId,\r
+ Subtask->Offset,\r
+ &Subtask->DiskIo2Token,\r
+ Subtask->BufferSize,\r
+ Subtask->Buffer\r
+ );\r
+ } else {\r
+ Status = IFile->OFile->Volume->DiskIo2->ReadDiskEx (\r
+ IFile->OFile->Volume->DiskIo2,\r
+ IFile->OFile->Volume->MediaId,\r
+ Subtask->Offset,\r
+ &Subtask->DiskIo2Token,\r
+ Subtask->BufferSize,\r
+ Subtask->Buffer\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ EfiAcquireLock (&FatTaskLock);\r
+ //\r
+ // Remove all the remaining subtasks when failure.\r
+ // We shouldn't remove all the tasks because the non-blocking requests have\r
+ // been submitted and cannot be canceled.\r
+ //\r
+ while (!IsNull (&Task->Subtasks, Link)) {\r
+ Subtask = CR (Link, FAT_SUBTASK, Link, FAT_SUBTASK_SIGNATURE);\r
+ Link = FatDestroySubtask (Subtask);\r
+ }\r
+\r
+ if (IsListEmpty (&Task->Subtasks)) {\r
+ RemoveEntryList (&Task->Link);\r
+ FreePool (Task);\r
+ } else {\r
+ //\r
+ // If one or more subtasks have been already submitted, set FileIoToken\r
+ // to NULL so that the callback won't signal the event.\r
+ //\r
+ Task->FileIoToken = NULL;\r
+ }\r
+\r
+ EfiReleaseLock (&FatTaskLock);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatAccessVolumeDirty (\r
+ IN FAT_VOLUME *Volume,\r
+ IN IO_MODE IoMode,\r
+ IN VOID *DirtyValue\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the volume as dirty or not\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ IoMode - The access mode.\r
+ DirtyValue - Set the volume as dirty or not.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the new FAT entry value sucessfully.\r
+ other - An error occurred when operation the FAT entries.\r
+\r
+--*/\r
+{\r
+ UINTN WriteCount;\r
+\r
+ WriteCount = Volume->FatEntrySize;\r
+ return FatDiskIo (Volume, IoMode, Volume->FatPos + WriteCount, WriteCount, DirtyValue, NULL);\r
+}\r
+\r
+/**\r
+ Invoke a notification event\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context The pointer to the notification function's context,\r
+ which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FatOnAccessComplete (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Invoke a notification event\r
+ case #1. some subtasks are not completed when the FatOpenEx checks the Task->Subtasks\r
+ - sets Task->SubtaskCollected so callback to signal the event and free the task.\r
+ case #2. all subtasks are completed when the FatOpenEx checks the Task->Subtasks\r
+ - FatOpenEx signal the event and free the task.\r
+Arguments:\r
+\r
+ Event - Event whose notification function is being invoked.\r
+ Context - The pointer to the notification function's context,\r
+ which is implementation-dependent.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_SUBTASK *Subtask;\r
+ FAT_TASK *Task;\r
+\r
+ //\r
+ // Avoid someone in future breaks the below assumption.\r
+ //\r
+ ASSERT (EfiGetCurrentTpl () == FatTaskLock.Tpl);\r
+\r
+ Subtask = (FAT_SUBTASK *) Context;\r
+ Task = Subtask->Task;\r
+ Status = Subtask->DiskIo2Token.TransactionStatus;\r
+\r
+ ASSERT (Task->Signature == FAT_TASK_SIGNATURE);\r
+ ASSERT (Subtask->Signature == FAT_SUBTASK_SIGNATURE);\r
+\r
+ //\r
+ // Remove the task unconditionally\r
+ //\r
+ FatDestroySubtask (Subtask);\r
+\r
+ //\r
+ // Task->FileIoToken is NULL which means the task will be ignored (just recycle the subtask and task memory).\r
+ //\r
+ if (Task->FileIoToken != NULL) {\r
+ if (IsListEmpty (&Task->Subtasks) || EFI_ERROR (Status)) {\r
+ Task->FileIoToken->Status = Status;\r
+ gBS->SignalEvent (Task->FileIoToken->Event);\r
+ //\r
+ // Mark Task->FileIoToken to NULL so that the subtasks belonging to the task will be ignored.\r
+ //\r
+ Task->FileIoToken = NULL;\r
+ }\r
+ }\r
+\r
+ if (IsListEmpty (&Task->Subtasks)) {\r
+ RemoveEntryList (&Task->Link);\r
+ FreePool (Task);\r
+ }\r
+}\r
+\r
+EFI_STATUS\r
+FatDiskIo (\r
+ IN FAT_VOLUME *Volume,\r
+ IN IO_MODE IoMode,\r
+ IN UINT64 Offset,\r
+ IN UINTN BufferSize,\r
+ IN OUT VOID *Buffer,\r
+ IN FAT_TASK *Task\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ General disk access function\r
+\r
+Arguments:\r
+\r
+ Volume - FAT file system volume.\r
+ IoMode - The access mode (disk read/write or cache access).\r
+ Offset - The starting byte offset to read from.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing read data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The operation is performed successfully.\r
+ EFI_VOLUME_CORRUPTED - The accesss is\r
+ Others - The status of read/write the disk\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DISK_IO_PROTOCOL *DiskIo;\r
+ EFI_DISK_READ IoFunction;\r
+ FAT_SUBTASK *Subtask;\r
+\r
+ //\r
+ // Verify the IO is in devices range\r
+ //\r
+ Status = EFI_VOLUME_CORRUPTED;\r
+ if (Offset + BufferSize <= Volume->VolumeSize) {\r
+ if (CACHE_ENABLED (IoMode)) {\r
+ //\r
+ // Access cache\r
+ //\r
+ Status = FatAccessCache (Volume, CACHE_TYPE (IoMode), RAW_ACCESS (IoMode), Offset, BufferSize, Buffer, Task);\r
+ } else {\r
+ //\r
+ // Access disk directly\r
+ //\r
+ if (Task == NULL) {\r
+ //\r
+ // Blocking access\r
+ //\r
+ DiskIo = Volume->DiskIo;\r
+ IoFunction = (IoMode == READ_DISK) ? DiskIo->ReadDisk : DiskIo->WriteDisk;\r
+ Status = IoFunction (DiskIo, Volume->MediaId, Offset, BufferSize, Buffer);\r
+ } else {\r
+ //\r
+ // Non-blocking access\r
+ //\r
+ Subtask = AllocateZeroPool (sizeof (*Subtask));\r
+ if (Subtask == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ Subtask->Signature = FAT_SUBTASK_SIGNATURE;\r
+ Subtask->Task = Task;\r
+ Subtask->Write = (BOOLEAN) (IoMode == WRITE_DISK);\r
+ Subtask->Offset = Offset;\r
+ Subtask->Buffer = Buffer;\r
+ Subtask->BufferSize = BufferSize;\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ FatOnAccessComplete,\r
+ Subtask,\r
+ &Subtask->DiskIo2Token.Event\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ InsertTailList (&Task->Subtasks, &Subtask->Link);\r
+ } else {\r
+ FreePool (Subtask);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Volume->DiskError = TRUE;\r
+ DEBUG ((EFI_D_ERROR, "FatDiskIo: error %r\n", Status));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+VOID\r
+FatAcquireLock (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Lock the volume.\r
+\r
+Arguments:\r
+\r
+ None.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ EfiAcquireLock (&FatFsLock);\r
+}\r
+\r
+EFI_STATUS\r
+FatAcquireLockOrFail (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Lock the volume.\r
+ If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.\r
+ Otherwise, EFI_SUCCESS is returned.\r
+\r
+Arguments:\r
+\r
+ None.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The volume is locked.\r
+ EFI_ACCESS_DENIED - The volume could not be locked because it is already locked.\r
+\r
+--*/\r
+{\r
+ return EfiAcquireLockOrFail (&FatFsLock);\r
+}\r
+\r
+VOID\r
+FatReleaseLock (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Unlock the volume.\r
+\r
+Arguments:\r
+\r
+ Null.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ EfiReleaseLock (&FatFsLock);\r
+}\r
+\r
+VOID\r
+FatFreeDirEnt (\r
+ IN FAT_DIRENT *DirEnt\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Free directory entry.\r
+\r
+Arguments:\r
+\r
+ DirEnt - The directory entry to be freed.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ if (DirEnt->FileString != NULL) {\r
+ FreePool (DirEnt->FileString);\r
+ }\r
+\r
+ FreePool (DirEnt);\r
+}\r
+\r
+VOID\r
+FatFreeVolume (\r
+ IN FAT_VOLUME *Volume\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Free volume structure (including the contents of directory cache and disk cache).\r
+\r
+Arguments:\r
+\r
+ Volume - The volume structure to be freed.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ //\r
+ // Free disk cache\r
+ //\r
+ if (Volume->CacheBuffer != NULL) {\r
+ FreePool (Volume->CacheBuffer);\r
+ }\r
+ //\r
+ // Free directory cache\r
+ //\r
+ FatCleanupODirCache (Volume);\r
+ FreePool (Volume);\r
+}\r
+\r
+VOID\r
+FatEfiTimeToFatTime (\r
+ IN EFI_TIME *ETime,\r
+ OUT FAT_DATE_TIME *FTime\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Translate EFI time to FAT time.\r
+\r
+Arguments:\r
+\r
+ ETime - The time of EFI_TIME.\r
+ FTime - The time of FAT_DATE_TIME.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ //\r
+ // ignores timezone info in source ETime\r
+ //\r
+ if (ETime->Year > 1980) {\r
+ FTime->Date.Year = (UINT16) (ETime->Year - 1980);\r
+ }\r
+\r
+ if (ETime->Year >= 1980 + FAT_MAX_YEAR_FROM_1980) {\r
+ FTime->Date.Year = FAT_MAX_YEAR_FROM_1980;\r
+ }\r
+\r
+ FTime->Date.Month = ETime->Month;\r
+ FTime->Date.Day = ETime->Day;\r
+ FTime->Time.Hour = ETime->Hour;\r
+ FTime->Time.Minute = ETime->Minute;\r
+ FTime->Time.DoubleSecond = (UINT16) (ETime->Second / 2);\r
+}\r
+\r
+VOID\r
+FatFatTimeToEfiTime (\r
+ IN FAT_DATE_TIME *FTime,\r
+ OUT EFI_TIME *ETime\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Translate Fat time to EFI time.\r
+\r
+Arguments:\r
+\r
+ FTime - The time of FAT_DATE_TIME.\r
+ ETime - The time of EFI_TIME.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ ETime->Year = (UINT16) (FTime->Date.Year + 1980);\r
+ ETime->Month = (UINT8) FTime->Date.Month;\r
+ ETime->Day = (UINT8) FTime->Date.Day;\r
+ ETime->Hour = (UINT8) FTime->Time.Hour;\r
+ ETime->Minute = (UINT8) FTime->Time.Minute;\r
+ ETime->Second = (UINT8) (FTime->Time.DoubleSecond * 2);\r
+ ETime->Nanosecond = 0;\r
+ ETime->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
+ ETime->Daylight = 0;\r
+}\r
+\r
+VOID\r
+FatGetCurrentFatTime (\r
+ OUT FAT_DATE_TIME *FatNow\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get Current FAT time.\r
+\r
+Arguments:\r
+\r
+ FatNow - Current FAT time.\r
+\r
+Returns:\r
+\r
+ None.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_TIME Now;\r
+\r
+ Status = gRT->GetTime (&Now, NULL);\r
+ if (!EFI_ERROR (Status)) {\r
+ FatEfiTimeToFatTime (&Now, FatNow);\r
+ } else {\r
+ ZeroMem (&Now, sizeof (EFI_TIME));\r
+ Now.Year = 1980;\r
+ Now.Month = 1;\r
+ Now.Day = 1;\r
+ FatEfiTimeToFatTime (&Now, FatNow);\r
+ }\r
+}\r
+\r
+BOOLEAN\r
+FatIsValidTime (\r
+ IN EFI_TIME *Time\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Check whether a time is valid.\r
+\r
+Arguments:\r
+\r
+ Time - The time of EFI_TIME.\r
+\r
+Returns:\r
+\r
+ TRUE - The time is valid.\r
+ FALSE - The time is not valid.\r
+\r
+--*/\r
+{\r
+ static UINT8 MonthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
+ UINTN Day;\r
+ BOOLEAN ValidTime;\r
+\r
+ ValidTime = TRUE;\r
+\r
+ //\r
+ // Check the fields for range problems\r
+ // Fat can only support from 1980\r
+ //\r
+ if (Time->Year < 1980 ||\r
+ Time->Month < 1 ||\r
+ Time->Month > 12 ||\r
+ Time->Day < 1 ||\r
+ Time->Day > 31 ||\r
+ Time->Hour > 23 ||\r
+ Time->Minute > 59 ||\r
+ Time->Second > 59 ||\r
+ Time->Nanosecond > 999999999\r
+ ) {\r
+\r
+ ValidTime = FALSE;\r
+\r
+ } else {\r
+ //\r
+ // Perform a more specific check of the day of the month\r
+ //\r
+ Day = MonthDays[Time->Month - 1];\r
+ if (Time->Month == 2 && IS_LEAP_YEAR (Time->Year)) {\r
+ Day += 1;\r
+ //\r
+ // 1 extra day this month\r
+ //\r
+ }\r
+ if (Time->Day > Day) {\r
+ ValidTime = FALSE;\r
+ }\r
+ }\r
+\r
+ return ValidTime;\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ open.c\r
+\r
+Abstract:\r
+\r
+ Routines dealing with file open\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+FatAllocateIFile (\r
+ IN FAT_OFILE *OFile,\r
+ OUT FAT_IFILE **PtrIFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Create an Open instance for the existing OFile.\r
+ The IFile of the newly opened file is passed out.\r
+\r
+Arguments:\r
+\r
+ OFile - The file that serves as a starting reference point.\r
+ PtrIFile - The newly generated IFile instance.\r
+\r
+Returns:\r
+\r
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory for the IFile\r
+ EFI_SUCCESS - Create the new IFile for the OFile successfully\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+\r
+ ASSERT_VOLUME_LOCKED (OFile->Volume);\r
+\r
+ //\r
+ // Allocate a new open instance\r
+ //\r
+ IFile = AllocateZeroPool (sizeof (FAT_IFILE));\r
+ if (IFile == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ IFile->Signature = FAT_IFILE_SIGNATURE;\r
+\r
+ CopyMem (&(IFile->Handle), &FatFileInterface, sizeof (EFI_FILE_PROTOCOL));\r
+\r
+ //\r
+ // Report the correct revision number based on the DiskIo2 availability\r
+ //\r
+ if (OFile->Volume->DiskIo2 != NULL) {\r
+ IFile->Handle.Revision = EFI_FILE_PROTOCOL_REVISION2;\r
+ } else {\r
+ IFile->Handle.Revision = EFI_FILE_PROTOCOL_REVISION;\r
+ }\r
+\r
+ IFile->OFile = OFile;\r
+ InsertTailList (&OFile->Opens, &IFile->Link);\r
+ InitializeListHead (&IFile->Tasks);\r
+\r
+ *PtrIFile = IFile;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatOFileOpen (\r
+ IN FAT_OFILE *OFile,\r
+ OUT FAT_IFILE **NewIFile,\r
+ IN CHAR16 *FileName,\r
+ IN UINT64 OpenMode,\r
+ IN UINT8 Attributes\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Open a file for a file name relative to an existing OFile.\r
+ The IFile of the newly opened file is passed out.\r
+\r
+Arguments:\r
+\r
+ OFile - The file that serves as a starting reference point.\r
+ NewIFile - The newly generated IFile instance.\r
+ FileName - The file name relative to the OFile.\r
+ OpenMode - Open mode.\r
+ Attributes - Attributes to set if the file is created.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Open the file successfully.\r
+ EFI_INVALID_PARAMETER - The open mode is conflict with the attributes\r
+ or the file name is not valid.\r
+ EFI_NOT_FOUND - Conficts between dir intention and attribute.\r
+ EFI_WRITE_PROTECTED - Can't open for write if the volume is read only.\r
+ EFI_ACCESS_DENIED - If the file's attribute is read only, and the\r
+ open is for read-write fail it.\r
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory.\r
+\r
+--*/\r
+{\r
+ FAT_VOLUME *Volume;\r
+ EFI_STATUS Status;\r
+ CHAR16 NewFileName[EFI_PATH_STRING_LENGTH];\r
+ FAT_DIRENT *DirEnt;\r
+ UINT8 FileAttributes;\r
+ BOOLEAN WriteMode;\r
+\r
+ DirEnt = NULL;\r
+ Volume = OFile->Volume;\r
+ ASSERT_VOLUME_LOCKED (Volume);\r
+ WriteMode = (BOOLEAN) (OpenMode & EFI_FILE_MODE_WRITE);\r
+ if (Volume->ReadOnly && WriteMode) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+ //\r
+ // Verify the source file handle isn't in an error state\r
+ //\r
+ Status = OFile->Error;\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get new OFile for the file\r
+ //\r
+ Status = FatLocateOFile (&OFile, FileName, Attributes, NewFileName);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (*NewFileName != 0) {\r
+ //\r
+ // If there's a remaining part of the name, then we had\r
+ // better be creating the file in the directory\r
+ //\r
+ if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Status = FatCreateDirEnt (OFile, NewFileName, Attributes, &DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ASSERT (DirEnt != NULL);\r
+ Status = FatOpenDirEnt (OFile, DirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ OFile = DirEnt->OFile;\r
+ if (OFile->ODir != NULL) {\r
+ //\r
+ // If we just created a directory, we need to create "." and ".."\r
+ //\r
+ Status = FatCreateDotDirEnts (OFile);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // If the file's attribute is read only, and the open is for\r
+ // read-write, then the access is denied.\r
+ //\r
+ FileAttributes = OFile->DirEnt->Entry.Attributes;\r
+ if ((FileAttributes & EFI_FILE_READ_ONLY) != 0 && (FileAttributes & FAT_ATTRIBUTE_DIRECTORY) == 0 && WriteMode) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ //\r
+ // Create an open instance of the OFile\r
+ //\r
+ Status = FatAllocateIFile (OFile, NewIFile);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ (*NewIFile)->ReadOnly = (BOOLEAN)!WriteMode;\r
+\r
+ DEBUG ((EFI_D_INFO, "FSOpen: Open '%S' %r\n", FileName, Status));\r
+ return FatOFileFlush (OFile);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatOpenEx (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ OUT EFI_FILE_PROTOCOL **NewHandle,\r
+ IN CHAR16 *FileName,\r
+ IN UINT64 OpenMode,\r
+ IN UINT64 Attributes,\r
+ IN OUT EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ Implements OpenEx() of Simple File System Protocol.\r
+\r
+Arguments:\r
+\r
+ FHand - File handle of the file serves as a starting reference point.\r
+ NewHandle - Handle of the file that is newly opened.\r
+ FileName - File name relative to FHand.\r
+ OpenMode - Open mode.\r
+ Attributes - Attributes to set if the file is created.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.\r
+ The OpenMode is not supported.\r
+ The Attributes is not the valid attributes.\r
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string.\r
+ EFI_SUCCESS - Open the file successfully.\r
+ Others - The status of open file.\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+ FAT_IFILE *NewIFile;\r
+ FAT_OFILE *OFile;\r
+ EFI_STATUS Status;\r
+ FAT_TASK *Task;\r
+\r
+ //\r
+ // Perform some parameter checking\r
+ //\r
+ if (FileName == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ //\r
+ // Check for a valid mode\r
+ //\r
+ switch (OpenMode) {\r
+ case EFI_FILE_MODE_READ:\r
+ case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:\r
+ case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:\r
+ break;\r
+\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check for valid Attributes for file creation case. \r
+ //\r
+ if (((OpenMode & EFI_FILE_MODE_CREATE) != 0) && (Attributes & (EFI_FILE_READ_ONLY | (~EFI_FILE_VALID_ATTR))) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+ Task = NULL;\r
+\r
+ if (Token == NULL) {\r
+ FatWaitNonblockingTask (IFile);\r
+ } else {\r
+ //\r
+ // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.\r
+ // But if it calls, the below check can avoid crash.\r
+ //\r
+ if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Task = FatCreateTask (IFile, Token);\r
+ if (Task == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Lock\r
+ //\r
+ FatAcquireLock ();\r
+\r
+ //\r
+ // Open the file\r
+ //\r
+ Status = FatOFileOpen (OFile, &NewIFile, FileName, OpenMode, (UINT8) Attributes);\r
+\r
+ //\r
+ // If the file was opened, return the handle to the caller\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ *NewHandle = &NewIFile->Handle;\r
+ }\r
+ //\r
+ // Unlock\r
+ //\r
+ Status = FatCleanupVolume (OFile->Volume, NULL, Status, Task);\r
+ FatReleaseLock ();\r
+\r
+ if (Token != NULL) {\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = FatQueueTask (IFile, Task);\r
+ } else {\r
+ FatDestroyTask (Task);\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatOpen (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ OUT EFI_FILE_PROTOCOL **NewHandle,\r
+ IN CHAR16 *FileName,\r
+ IN UINT64 OpenMode,\r
+ IN UINT64 Attributes\r
+ )\r
+/*++\r
+Routine Description:\r
+\r
+ Implements Open() of Simple File System Protocol.\r
+\r
+Arguments:\r
+\r
+ FHand - File handle of the file serves as a starting reference point.\r
+ NewHandle - Handle of the file that is newly opened.\r
+ FileName - File name relative to FHand.\r
+ OpenMode - Open mode.\r
+ Attributes - Attributes to set if the file is created.\r
+\r
+Returns:\r
+\r
+ EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.\r
+ The OpenMode is not supported.\r
+ The Attributes is not the valid attributes.\r
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string.\r
+ EFI_SUCCESS - Open the file successfully.\r
+ Others - The status of open file.\r
+\r
+--*/\r
+{\r
+ return FatOpenEx (FHand, NewHandle, FileName, OpenMode, Attributes, NULL);\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ OpenVolume.c\r
+\r
+Abstract:\r
+\r
+ OpenVolume() function of Simple File System Protocol\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatOpenVolume (\r
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
+ OUT EFI_FILE_PROTOCOL **File\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Implements Simple File System Protocol interface function OpenVolume().\r
+\r
+Arguments:\r
+\r
+ This - Calling context.\r
+ File - the Root Directory of the volume.\r
+\r
+Returns:\r
+\r
+ EFI_OUT_OF_RESOURCES - Can not allocate the memory.\r
+ EFI_VOLUME_CORRUPTED - The FAT type is error.\r
+ EFI_SUCCESS - Open the volume successfully.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_VOLUME *Volume;\r
+ FAT_IFILE *IFile;\r
+\r
+ Volume = VOLUME_FROM_VOL_INTERFACE (This);\r
+ FatAcquireLock ();\r
+\r
+ //\r
+ // Open Root file\r
+ //\r
+ Status = FatOpenDirEnt (NULL, &Volume->RootDirEnt);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Open a new instance to the root\r
+ //\r
+ Status = FatAllocateIFile (Volume->Root, &IFile);\r
+ if (!EFI_ERROR (Status)) {\r
+ *File = &IFile->Handle;\r
+ }\r
+\r
+Done:\r
+\r
+ Status = FatCleanupVolume (Volume, Volume->Root, Status, NULL);\r
+ FatReleaseLock ();\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/*++\r
+\r
+Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ ReadWrite.c\r
+\r
+Abstract:\r
+\r
+ Functions that perform file read/write\r
+\r
+Revision History\r
+\r
+--*/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatGetPosition (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ OUT UINT64 *Position\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file's position of the file.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file.\r
+ Position - The file's position of the file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_UNSUPPORTED - The open file is not a file.\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+\r
+ if (OFile->Error == EFI_NOT_FOUND) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (OFile->ODir != NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ *Position = IFile->Position;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatSetPosition (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN UINT64 Position\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Set the file's position of the file.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of file.\r
+ Position - The file's position of the file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_UNSUPPORTED - Set a directory with a not-zero position.\r
+\r
+--*/\r
+{\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+\r
+ if (OFile->Error == EFI_NOT_FOUND) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ FatWaitNonblockingTask (IFile);\r
+\r
+ //\r
+ // If this is a directory, we can only set back to position 0\r
+ //\r
+ if (OFile->ODir != NULL) {\r
+ if (Position != 0) {\r
+ //\r
+ // Reset current directory cursor;\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ FatResetODirCursor (OFile);\r
+ }\r
+ //\r
+ // Set the position\r
+ //\r
+ if (Position == (UINT64)-1) {\r
+ Position = OFile->FileSize;\r
+ }\r
+ //\r
+ // Set the position\r
+ //\r
+ IFile->Position = Position;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+FatIFileReadDir (\r
+ IN FAT_IFILE *IFile,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info from the open file of the IFile into Buffer.\r
+\r
+Arguments:\r
+\r
+ IFile - The instance of the open file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing read data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_OFILE *OFile;\r
+ FAT_ODIR *ODir;\r
+ FAT_DIRENT *DirEnt;\r
+ UINT32 CurrentPos;\r
+\r
+ OFile = IFile->OFile;\r
+ ODir = OFile->ODir;\r
+ CurrentPos = ((UINT32) IFile->Position) / sizeof (FAT_DIRECTORY_ENTRY);\r
+\r
+ //\r
+ // We need to relocate the directory\r
+ //\r
+ if (CurrentPos < ODir->CurrentPos) {\r
+ //\r
+ // The directory cursor has been modified by another IFile, we reset the cursor\r
+ //\r
+ FatResetODirCursor (OFile);\r
+ }\r
+ //\r
+ // We seek the next directory entry's position\r
+ //\r
+ do {\r
+ Status = FatGetNextDirEnt (OFile, &DirEnt);\r
+ if (EFI_ERROR (Status) || DirEnt == NULL) {\r
+ //\r
+ // Something error occurred or reach the end of directory,\r
+ // return 0 buffersize\r
+ //\r
+ *BufferSize = 0;\r
+ goto Done;\r
+ }\r
+ } while (ODir->CurrentPos <= CurrentPos);\r
+ Status = FatGetDirEntInfo (OFile->Volume, DirEnt, BufferSize, Buffer);\r
+\r
+Done:\r
+ //\r
+ // Update IFile's Position\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Update IFile->Position, if everything is all right\r
+ //\r
+ CurrentPos = ODir->CurrentPos;\r
+ IFile->Position = (UINT64) (CurrentPos * sizeof (FAT_DIRECTORY_ENTRY));\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatIFileAccess (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN IO_MODE IoMode,\r
+ IN OUT UINTN *BufferSize,\r
+ IN OUT VOID *Buffer,\r
+ IN EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info from the open file of the IFile into Buffer.\r
+\r
+Arguments:\r
+\r
+ FHand - The file handle to access.\r
+ IoMode - Indicate whether the access mode is reading or writing.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing read data.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.\r
+ EFI_WRITE_PROTECTED - The disk is write protect.\r
+ EFI_ACCESS_DENIED - The file is read-only.\r
+ other - An error occurred when operating on the disk.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_IFILE *IFile;\r
+ FAT_OFILE *OFile;\r
+ FAT_VOLUME *Volume;\r
+ UINT64 EndPosition;\r
+ FAT_TASK *Task;\r
+\r
+ IFile = IFILE_FROM_FHAND (FHand);\r
+ OFile = IFile->OFile;\r
+ Volume = OFile->Volume;\r
+ Task = NULL;\r
+\r
+ //\r
+ // Write to a directory is unsupported\r
+ //\r
+ if ((OFile->ODir != NULL) && (IoMode == WRITE_DATA)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if (OFile->Error == EFI_NOT_FOUND) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (IoMode == READ_DATA) {\r
+ //\r
+ // If position is at EOF, then return device error\r
+ //\r
+ if (IFile->Position > OFile->FileSize) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ } else {\r
+ //\r
+ // Check if the we can write data\r
+ //\r
+ if (Volume->ReadOnly) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ if (IFile->ReadOnly) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+ }\r
+\r
+ if (Token == NULL) {\r
+ FatWaitNonblockingTask (IFile);\r
+ } else {\r
+ //\r
+ // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.\r
+ // But if it calls, the below check can avoid crash.\r
+ //\r
+ if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Task = FatCreateTask (IFile, Token);\r
+ if (Task == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ FatAcquireLock ();\r
+\r
+ Status = OFile->Error;\r
+ if (!EFI_ERROR (Status)) {\r
+ if (OFile->ODir != NULL) {\r
+ //\r
+ // Read a directory is supported\r
+ //\r
+ ASSERT (IoMode == READ_DATA);\r
+ Status = FatIFileReadDir (IFile, BufferSize, Buffer);\r
+ OFile = NULL;\r
+ } else {\r
+ //\r
+ // Access a file\r
+ //\r
+ EndPosition = IFile->Position + *BufferSize;\r
+ if (EndPosition > OFile->FileSize) {\r
+ //\r
+ // The position goes beyond the end of file\r
+ //\r
+ if (IoMode == READ_DATA) {\r
+ //\r
+ // Adjust the actual size read\r
+ //\r
+ *BufferSize -= (UINTN) EndPosition - OFile->FileSize;\r
+ } else {\r
+ //\r
+ // We expand the file size of OFile\r
+ //\r
+ Status = FatGrowEof (OFile, EndPosition);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Must update the file's info into the file's Directory Entry\r
+ // and then flush the dirty cache info into disk.\r
+ //\r
+ *BufferSize = 0;\r
+ FatOFileFlush (OFile);\r
+ OFile = NULL;\r
+ goto Done;\r
+ }\r
+\r
+ FatUpdateDirEntClusterSizeInfo (OFile);\r
+ }\r
+ }\r
+\r
+ Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer, Task);\r
+ IFile->Position += *BufferSize;\r
+ }\r
+ }\r
+\r
+ if (Token != NULL) {\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = FatQueueTask (IFile, Task);\r
+ } else {\r
+ FatDestroyTask (Task);\r
+ }\r
+ }\r
+\r
+Done:\r
+ //\r
+ // On EFI_SUCCESS case, not calling FatCleanupVolume():\r
+ // 1) The Cache flush operation is avoided to enhance\r
+ // performance. Caller is responsible to call Flush() when necessary.\r
+ // 2) The volume dirty bit is probably set already, and is expected to be\r
+ // cleaned in subsequent Flush() or other operations.\r
+ // 3) Write operation doesn't affect OFile/IFile structure, so\r
+ // Reference checking is not necessary.\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ Status = FatCleanupVolume (Volume, OFile, Status, NULL);\r
+ }\r
+\r
+ FatReleaseLock ();\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatRead (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing read data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ return FatIFileAccess (FHand, READ_DATA, BufferSize, Buffer, NULL);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatReadEx (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN OUT EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ return FatIFileAccess (FHand, READ_DATA, &Token->BufferSize, Token->Buffer, Token);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatWrite (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN OUT UINTN *BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Write the content of buffer into files.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ BufferSize - Size of Buffer.\r
+ Buffer - Buffer containing write data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Set the file info successfully.\r
+ EFI_WRITE_PROTECTED - The disk is write protect.\r
+ EFI_ACCESS_DENIED - The file is read-only.\r
+ EFI_DEVICE_ERROR - The OFile is not valid.\r
+ EFI_UNSUPPORTED - The open file is not a file.\r
+ - The writing file size is larger than 4GB.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ return FatIFileAccess (FHand, WRITE_DATA, BufferSize, Buffer, NULL);\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FatWriteEx (\r
+ IN EFI_FILE_PROTOCOL *FHand,\r
+ IN OUT EFI_FILE_IO_TOKEN *Token\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Get the file info.\r
+\r
+Arguments:\r
+\r
+ FHand - The handle of the file.\r
+ Token - A pointer to the token associated with the transaction.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Get the file info successfully.\r
+ EFI_DEVICE_ERROR - Can not find the OFile for the file.\r
+ EFI_VOLUME_CORRUPTED - The file type of open file is error.\r
+ other - An error occurred when operation the disk.\r
+\r
+--*/\r
+{\r
+ return FatIFileAccess (FHand, WRITE_DATA, &Token->BufferSize, Token->Buffer, Token);\r
+}\r
+\r
+EFI_STATUS\r
+FatAccessOFile (\r
+ IN FAT_OFILE *OFile,\r
+ IN IO_MODE IoMode,\r
+ IN UINTN Position,\r
+ IN OUT UINTN *DataBufferSize,\r
+ IN OUT UINT8 *UserBuffer,\r
+ IN FAT_TASK *Task\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function reads data from a file or writes data to a file.\r
+ It uses OFile->PosRem to determine how much data can be accessed in one time.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+ IoMode - Indicate whether the access mode is reading or writing.\r
+ Position - The position where data will be accessed.\r
+ DataBufferSize - Size of Buffer.\r
+ UserBuffer - Buffer containing data.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Access the data successfully.\r
+ other - An error occurred when operating on the disk.\r
+\r
+--*/\r
+{\r
+ FAT_VOLUME *Volume;\r
+ UINTN Len;\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+\r
+ BufferSize = *DataBufferSize;\r
+ Volume = OFile->Volume;\r
+ ASSERT_VOLUME_LOCKED (Volume);\r
+\r
+ Status = EFI_SUCCESS;\r
+ while (BufferSize > 0) {\r
+ //\r
+ // Seek the OFile to the file position\r
+ //\r
+ Status = FatOFilePosition (OFile, Position, BufferSize);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ //\r
+ // Clip length to block run\r
+ //\r
+ Len = BufferSize > OFile->PosRem ? OFile->PosRem : BufferSize;\r
+\r
+ //\r
+ // Write the data\r
+ //\r
+ Status = FatDiskIo (Volume, IoMode, OFile->PosDisk, Len, UserBuffer, Task);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ //\r
+ // Data was successfully accessed\r
+ //\r
+ Position += Len;\r
+ UserBuffer += Len;\r
+ BufferSize -= Len;\r
+ if (IoMode == WRITE_DATA) {\r
+ OFile->Dirty = TRUE;\r
+ OFile->Archive = TRUE;\r
+ }\r
+ //\r
+ // Make sure no outbound occurred\r
+ //\r
+ ASSERT (Position <= OFile->FileSize);\r
+ }\r
+ //\r
+ // Update the number of bytes accessed\r
+ //\r
+ *DataBufferSize -= BufferSize;\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatExpandOFile (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINT64 ExpandedSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Expand OFile by appending zero bytes at the end of OFile.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+ ExpandedSize - The number of zero bytes appended at the end of the file.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The file is expanded successfully.\r
+ other - An error occurred when expanding file.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN WritePos;\r
+\r
+ WritePos = OFile->FileSize;\r
+ Status = FatGrowEof (OFile, ExpandedSize);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = FatWriteZeroPool (OFile, WritePos);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatWriteZeroPool (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINTN WritePos\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Write zero pool from the WritePos to the end of OFile.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file to write zero pool.\r
+ WritePos - The number of zero bytes written.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - Write the zero pool successfully.\r
+ EFI_OUT_OF_RESOURCES - Not enough memory to perform the operation.\r
+ other - An error occurred when writing disk.\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *ZeroBuffer;\r
+ UINTN AppendedSize;\r
+ UINTN BufferSize;\r
+ UINTN WriteSize;\r
+\r
+ AppendedSize = OFile->FileSize - WritePos;\r
+ BufferSize = AppendedSize;\r
+ if (AppendedSize > FAT_MAX_ALLOCATE_SIZE) {\r
+ //\r
+ // If the appended size is larger, maybe we can not allocate the whole\r
+ // memory once. So if the growed size is larger than 10M, we just\r
+ // allocate 10M memory (one healthy system should have 10M available\r
+ // memory), and then write the zerobuffer to the file several times.\r
+ //\r
+ BufferSize = FAT_MAX_ALLOCATE_SIZE;\r
+ }\r
+\r
+ ZeroBuffer = AllocateZeroPool (BufferSize);\r
+ if (ZeroBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ do {\r
+ WriteSize = AppendedSize > BufferSize ? BufferSize : (UINTN) AppendedSize;\r
+ AppendedSize -= WriteSize;\r
+ Status = FatAccessOFile (OFile, WRITE_DATA, WritePos, &WriteSize, ZeroBuffer, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ WritePos += WriteSize;\r
+ } while (AppendedSize > 0);\r
+\r
+ FreePool (ZeroBuffer);\r
+ return Status;\r
+}\r
+\r
+EFI_STATUS\r
+FatTruncateOFile (\r
+ IN FAT_OFILE *OFile,\r
+ IN UINTN TruncatedSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Truncate the OFile to smaller file size.\r
+\r
+Arguments:\r
+\r
+ OFile - The open file.\r
+ TruncatedSize - The new file size.\r
+\r
+Returns:\r
+\r
+ EFI_SUCCESS - The file is truncated successfully.\r
+ other - An error occurred when truncating file.\r
+\r
+--*/\r
+{\r
+ OFile->FileSize = TruncatedSize;\r
+ return FatShrinkEof (OFile);\r
+}\r
--- /dev/null
+/** @file\r
+ Unicode Collation Support component that hides the trivial difference of Unicode Collation\r
+ and Unicode collation 2 Protocol.\r
+\r
+ Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Fat.h"\r
+\r
+EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollationInterface = NULL;\r
+\r
+/**\r
+ Worker function to initialize Unicode Collation support.\r
+\r
+ It tries to locate Unicode Collation (2) protocol and matches it with current\r
+ platform language code.\r
+\r
+ @param AgentHandle The handle used to open Unicode Collation (2) protocol.\r
+ @param ProtocolGuid The pointer to Unicode Collation (2) protocol GUID.\r
+ @param VariableName The name of the RFC 4646 or ISO 639-2 language variable.\r
+ @param DefaultLanguage The default language in case the RFC 4646 or ISO 639-2 language is absent.\r
+\r
+ @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.\r
+ @retval Others The Unicode Collation (2) protocol has not been located.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUnicodeCollationSupportWorker (\r
+ IN EFI_HANDLE AgentHandle,\r
+ IN EFI_GUID *ProtocolGuid,\r
+ IN CONST CHAR16 *VariableName,\r
+ IN CONST CHAR8 *DefaultLanguage\r
+ )\r
+{\r
+ EFI_STATUS ReturnStatus;\r
+ EFI_STATUS Status;\r
+ UINTN NumHandles;\r
+ UINTN Index;\r
+ EFI_HANDLE *Handles;\r
+ EFI_UNICODE_COLLATION_PROTOCOL *Uci;\r
+ BOOLEAN Iso639Language;\r
+ CHAR8 *Language;\r
+ CHAR8 *BestLanguage;\r
+\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ ProtocolGuid,\r
+ NULL,\r
+ &NumHandles,\r
+ &Handles\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Iso639Language = (BOOLEAN) (ProtocolGuid == &gEfiUnicodeCollationProtocolGuid);\r
+ GetEfiGlobalVariable2 (VariableName, (VOID**) &Language, NULL);\r
+\r
+ ReturnStatus = EFI_UNSUPPORTED;\r
+ for (Index = 0; Index < NumHandles; Index++) {\r
+ //\r
+ // Open Unicode Collation Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Handles[Index],\r
+ ProtocolGuid,\r
+ (VOID **) &Uci,\r
+ AgentHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Find the best matching matching language from the supported languages\r
+ // of Unicode Collation (2) protocol. \r
+ //\r
+ BestLanguage = GetBestLanguage (\r
+ Uci->SupportedLanguages,\r
+ Iso639Language,\r
+ (Language == NULL) ? "" : Language,\r
+ DefaultLanguage,\r
+ NULL\r
+ );\r
+ if (BestLanguage != NULL) {\r
+ FreePool (BestLanguage);\r
+ mUnicodeCollationInterface = Uci;\r
+ ReturnStatus = EFI_SUCCESS;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Language != NULL) {\r
+ FreePool (Language);\r
+ }\r
+\r
+ FreePool (Handles);\r
+\r
+ return ReturnStatus;\r
+}\r
+\r
+/**\r
+ Initialize Unicode Collation support.\r
+\r
+ It tries to locate Unicode Collation 2 protocol and matches it with current\r
+ platform language code. If for any reason the first attempt fails, it then tries to\r
+ use Unicode Collation Protocol.\r
+\r
+ @param AgentHandle The handle used to open Unicode Collation (2) protocol.\r
+\r
+ @retval EFI_SUCCESS The Unicode Collation (2) protocol has been successfully located.\r
+ @retval Others The Unicode Collation (2) protocol has not been located.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeUnicodeCollationSupport (\r
+ IN EFI_HANDLE AgentHandle\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+\r
+ //\r
+ // First try to use RFC 4646 Unicode Collation 2 Protocol.\r
+ //\r
+ Status = InitializeUnicodeCollationSupportWorker (\r
+ AgentHandle,\r
+ &gEfiUnicodeCollation2ProtocolGuid,\r
+ L"PlatformLang",\r
+ (CONST CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang)\r
+ );\r
+ //\r
+ // If the attempt to use Unicode Collation 2 Protocol fails, then we fall back\r
+ // on the ISO 639-2 Unicode Collation Protocol.\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ Status = InitializeUnicodeCollationSupportWorker (\r
+ AgentHandle,\r
+ &gEfiUnicodeCollationProtocolGuid,\r
+ L"Lang",\r
+ (CONST CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultLang)\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Performs a case-insensitive comparison of two Null-terminated Unicode strings.\r
+\r
+ @param S1 A pointer to a Null-terminated Unicode string.\r
+ @param S2 A pointer to a Null-terminated Unicode string.\r
+\r
+ @retval 0 S1 is equivalent to S2.\r
+ @retval >0 S1 is lexically greater than S2.\r
+ @retval <0 S1 is lexically less than S2.\r
+**/\r
+INTN\r
+FatStriCmp (\r
+ IN CHAR16 *S1,\r
+ IN CHAR16 *S2\r
+ )\r
+{\r
+ ASSERT (StrSize (S1) != 0);\r
+ ASSERT (StrSize (S2) != 0);\r
+ ASSERT (mUnicodeCollationInterface != NULL);\r
+\r
+ return mUnicodeCollationInterface->StriColl (\r
+ mUnicodeCollationInterface,\r
+ S1,\r
+ S2\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ Uppercase a string.\r
+\r
+ @param Str The string which will be upper-cased.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+FatStrUpr (\r
+ IN OUT CHAR16 *String\r
+ )\r
+{\r
+ ASSERT (StrSize (String) != 0);\r
+ ASSERT (mUnicodeCollationInterface != NULL);\r
+\r
+ mUnicodeCollationInterface->StrUpr (mUnicodeCollationInterface, String);\r
+}\r
+\r
+\r
+/**\r
+ Lowercase a string\r
+\r
+ @param Str The string which will be lower-cased.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+FatStrLwr (\r
+ IN OUT CHAR16 *String\r
+ )\r
+{\r
+ ASSERT (StrSize (String) != 0);\r
+ ASSERT (mUnicodeCollationInterface != NULL);\r
+\r
+ mUnicodeCollationInterface->StrLwr (mUnicodeCollationInterface, String);\r
+}\r
+\r
+\r
+/**\r
+ Convert FAT string to unicode string.\r
+\r
+ @param FatSize The size of FAT string.\r
+ @param Fat The FAT string.\r
+ @param String The unicode string.\r
+\r
+ @return None.\r
+\r
+**/\r
+VOID\r
+FatFatToStr (\r
+ IN UINTN FatSize,\r
+ IN CHAR8 *Fat,\r
+ OUT CHAR16 *String\r
+ )\r
+{\r
+ ASSERT (Fat != NULL);\r
+ ASSERT (String != NULL);\r
+ ASSERT (((UINTN) String & 0x01) == 0);\r
+ ASSERT (mUnicodeCollationInterface != NULL);\r
+\r
+ mUnicodeCollationInterface->FatToStr (mUnicodeCollationInterface, FatSize, Fat, String);\r
+}\r
+\r
+\r
+/**\r
+ Convert unicode string to Fat string.\r
+\r
+ @param String The unicode string.\r
+ @param FatSize The size of the FAT string.\r
+ @param Fat The FAT string.\r
+\r
+ @retval TRUE Convert successfully.\r
+ @retval FALSE Convert error.\r
+\r
+**/\r
+BOOLEAN\r
+FatStrToFat (\r
+ IN CHAR16 *String,\r
+ IN UINTN FatSize,\r
+ OUT CHAR8 *Fat\r
+ )\r
+{\r
+ ASSERT (Fat != NULL);\r
+ ASSERT (StrSize (String) != 0);\r
+ ASSERT (mUnicodeCollationInterface != NULL);\r
+\r
+ return mUnicodeCollationInterface->StrToFat (\r
+ mUnicodeCollationInterface,\r
+ String,\r
+ FatSize,\r
+ Fat\r
+ );\r
+}\r
--- /dev/null
+/** @file\r
+ FAT file system access routines for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+\r
+/**\r
+ Check if there is a valid FAT in the corresponding Block device\r
+ of the volume and if yes, fill in the relevant fields for the\r
+ volume structure. Note there should be a valid Block device number\r
+ already set.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+ @param Volume On input, the BlockDeviceNumber field of the \r
+ Volume should be a valid value. On successful \r
+ output, all fields except the VolumeNumber \r
+ field is initialized. \r
+\r
+ @retval EFI_SUCCESS A FAT is found and the volume structure is \r
+ initialized. \r
+ @retval EFI_NOT_FOUND There is no FAT on the corresponding device. \r
+ @retval EFI_DEVICE_ERROR There is something error while accessing device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetBpbInfo (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN OUT PEI_FAT_VOLUME *Volume\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_BOOT_SECTOR Bpb;\r
+ PEI_FAT_BOOT_SECTOR_EX BpbEx;\r
+ UINT32 Sectors;\r
+ UINT32 SectorsPerFat;\r
+ UINT32 RootDirSectors;\r
+ UINT64 FatLba;\r
+ UINT64 RootLba;\r
+ UINT64 FirstClusterLba;\r
+\r
+ //\r
+ // Read in the BPB\r
+ //\r
+ Status = FatReadDisk (\r
+ PrivateData,\r
+ Volume->BlockDeviceNo,\r
+ 0,\r
+ sizeof (PEI_FAT_BOOT_SECTOR_EX),\r
+ &BpbEx\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CopyMem (\r
+ (UINT8 *) (&Bpb),\r
+ (UINT8 *) (&BpbEx),\r
+ sizeof (PEI_FAT_BOOT_SECTOR)\r
+ );\r
+\r
+ Volume->FatType = FatUnknown;\r
+\r
+ Sectors = Bpb.Sectors;\r
+ if (Sectors == 0) {\r
+ Sectors = Bpb.LargeSectors;\r
+ }\r
+\r
+ SectorsPerFat = Bpb.SectorsPerFat;\r
+ if (SectorsPerFat == 0) {\r
+ SectorsPerFat = BpbEx.LargeSectorsPerFat;\r
+ Volume->FatType = Fat32;\r
+ }\r
+ //\r
+ // Filter out those not a FAT\r
+ //\r
+ if (Bpb.Ia32Jump[0] != 0xe9 && Bpb.Ia32Jump[0] != 0xeb && Bpb.Ia32Jump[0] != 0x49) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Bpb.ReservedSectors == 0 || Bpb.NoFats == 0 || Sectors == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Bpb.SectorsPerCluster != 1 &&\r
+ Bpb.SectorsPerCluster != 2 &&\r
+ Bpb.SectorsPerCluster != 4 &&\r
+ Bpb.SectorsPerCluster != 8 &&\r
+ Bpb.SectorsPerCluster != 16 &&\r
+ Bpb.SectorsPerCluster != 32 &&\r
+ Bpb.SectorsPerCluster != 64 &&\r
+ Bpb.SectorsPerCluster != 128\r
+ ) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Volume->FatType == Fat32 && (SectorsPerFat == 0 || BpbEx.FsVersion != 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Bpb.Media != 0xf0 &&\r
+ Bpb.Media != 0xf8 &&\r
+ Bpb.Media != 0xf9 &&\r
+ Bpb.Media != 0xfb &&\r
+ Bpb.Media != 0xfc &&\r
+ Bpb.Media != 0xfd &&\r
+ Bpb.Media != 0xfe &&\r
+ Bpb.Media != 0xff &&\r
+ //\r
+ // FujitsuFMR\r
+ //\r
+ Bpb.Media != 0x00 &&\r
+ Bpb.Media != 0x01 &&\r
+ Bpb.Media != 0xfa\r
+ ) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Volume->FatType != Fat32 && Bpb.RootEntries == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // If this is fat32, refuse to mount mirror-disabled volumes\r
+ //\r
+ if (Volume->FatType == Fat32 && ((BpbEx.ExtendedFlags & 0x80) != 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Fill in the volume structure fields\r
+ // (Sectors & SectorsPerFat is computed earlier already)\r
+ //\r
+ Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster;\r
+ Volume->RootEntries = Bpb.RootEntries;\r
+ Volume->SectorSize = Bpb.SectorSize;\r
+\r
+ RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize;\r
+\r
+ FatLba = Bpb.ReservedSectors;\r
+ RootLba = Bpb.NoFats * SectorsPerFat + FatLba;\r
+ FirstClusterLba = RootLba + RootDirSectors;\r
+\r
+ Volume->VolumeSize = MultU64x32 (Sectors, Volume->SectorSize);\r
+ Volume->FatPos = MultU64x32 (FatLba, Volume->SectorSize);\r
+ Volume->RootDirPos = MultU64x32 (RootLba, Volume->SectorSize);\r
+ Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize);\r
+ Volume->MaxCluster = (UINT32) (Sectors - FirstClusterLba) / Bpb.SectorsPerCluster;\r
+ Volume->RootDirCluster = BpbEx.RootDirFirstCluster;\r
+\r
+ //\r
+ // If this is not a fat32, determine if it's a fat16 or fat12\r
+ //\r
+ if (Volume->FatType != Fat32) {\r
+\r
+ if (Volume->MaxCluster >= 65525) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Gets the next cluster in the cluster chain\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param Volume The volume \r
+ @param Cluster The cluster \r
+ @param NextCluster The cluster number of the next cluster \r
+\r
+ @retval EFI_SUCCESS The address is got \r
+ @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume. \r
+ @retval EFI_DEVICE_ERROR Read disk error\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetNextCluster (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_VOLUME *Volume,\r
+ IN UINT32 Cluster,\r
+ OUT UINT32 *NextCluster\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 FatEntryPos;\r
+ UINT32 Dummy;\r
+\r
+ *NextCluster = 0;\r
+\r
+ if (Volume->FatType == Fat32) {\r
+ FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster);\r
+\r
+ Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster);\r
+ *NextCluster &= 0x0fffffff;\r
+\r
+ //\r
+ // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
+ //\r
+ if ((*NextCluster) >= 0x0ffffff7) {\r
+ *NextCluster |= (-1 &~0xf);\r
+ }\r
+\r
+ } else if (Volume->FatType == Fat16) {\r
+ FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster);\r
+\r
+ Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);\r
+\r
+ //\r
+ // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
+ //\r
+ if ((*NextCluster) >= 0xfff7) {\r
+ *NextCluster |= (-1 &~0xf);\r
+ }\r
+\r
+ } else {\r
+ FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy);\r
+\r
+ Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);\r
+\r
+ if ((Cluster & 0x01) != 0) {\r
+ *NextCluster = (*NextCluster) >> 4;\r
+ } else {\r
+ *NextCluster = (*NextCluster) & 0x0fff;\r
+ }\r
+ //\r
+ // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
+ //\r
+ if ((*NextCluster) >= 0x0ff7) {\r
+ *NextCluster |= (-1 &~0xf);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+/**\r
+ Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.\r
+\r
+ @param PrivateData the global memory map \r
+ @param File the file \r
+ @param Pos the Position which is offset from the file's \r
+ CurrentPos \r
+\r
+ @retval EFI_SUCCESS Success. \r
+ @retval EFI_INVALID_PARAMETER Pos is beyond file's size. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatSetFilePos (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *File,\r
+ IN UINT32 Pos\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 AlignedPos;\r
+ UINT32 Offset;\r
+ UINT32 Cluster;\r
+ UINT32 PrevCluster;\r
+\r
+ if (File->IsFixedRootDir) {\r
+\r
+ if (Pos >= MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ File->CurrentPos += Pos;\r
+ File->StraightReadAmount = (UINT32) (MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos);\r
+\r
+ } else {\r
+\r
+ DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
+ AlignedPos = (UINT32) File->CurrentPos - (UINT32) Offset;\r
+\r
+ while\r
+ (\r
+ !FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster) &&\r
+ AlignedPos + File->Volume->ClusterSize <= File->CurrentPos + Pos\r
+ ) {\r
+ AlignedPos += File->Volume->ClusterSize;\r
+ Status = FatGetNextCluster (\r
+ PrivateData,\r
+ File->Volume,\r
+ File->CurrentCluster,\r
+ &File->CurrentCluster\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ File->CurrentPos += Pos;\r
+ //\r
+ // Calculate the amount of consecutive cluster occupied by the file.\r
+ // FatReadFile() will use it to read these blocks once.\r
+ //\r
+ File->StraightReadAmount = 0;\r
+ Cluster = File->CurrentCluster;\r
+ while (!FAT_CLUSTER_FUNCTIONAL (Cluster)) {\r
+ File->StraightReadAmount += File->Volume->ClusterSize;\r
+ PrevCluster = Cluster;\r
+ Status = FatGetNextCluster (PrivateData, File->Volume, Cluster, &Cluster);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (Cluster != PrevCluster + 1) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
+ File->StraightReadAmount -= (UINT32) Offset;\r
+\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Reads file data. Updates the file's CurrentPos.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param File The file. \r
+ @param Size The amount of data to read. \r
+ @param Buffer The buffer storing the data. \r
+\r
+ @retval EFI_SUCCESS The data is read. \r
+ @retval EFI_INVALID_PARAMETER File is invalid. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadFile (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *File,\r
+ IN UINTN Size,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR8 *BufferPtr;\r
+ UINT32 Offset;\r
+ UINT64 PhysicalAddr;\r
+ UINTN Amount;\r
+\r
+ BufferPtr = Buffer;\r
+\r
+ if (File->IsFixedRootDir) {\r
+ //\r
+ // This is the fixed root dir in FAT12 and FAT16\r
+ //\r
+ if (File->CurrentPos + Size > File->Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = FatReadDisk (\r
+ PrivateData,\r
+ File->Volume->BlockDeviceNo,\r
+ File->Volume->RootDirPos + File->CurrentPos,\r
+ Size,\r
+ Buffer\r
+ );\r
+ File->CurrentPos += (UINT32) Size;\r
+ return Status;\r
+\r
+ } else {\r
+\r
+ if ((File->Attributes & FAT_ATTR_DIRECTORY) == 0) {\r
+ Size = Size < (File->FileSize - File->CurrentPos) ? Size : (UINTN) (File->FileSize - File->CurrentPos);\r
+ }\r
+ //\r
+ // This is a normal cluster based file\r
+ //\r
+ while (Size != 0) {\r
+ DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
+ PhysicalAddr = File->Volume->FirstClusterPos + MultU64x32 (File->Volume->ClusterSize, File->CurrentCluster - 2);\r
+\r
+ Amount = File->StraightReadAmount;\r
+ Amount = Size > Amount ? Amount : Size;\r
+ Status = FatReadDisk (\r
+ PrivateData,\r
+ File->Volume->BlockDeviceNo,\r
+ PhysicalAddr + Offset,\r
+ Amount,\r
+ BufferPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Advance the file's current pos and current cluster\r
+ //\r
+ FatSetFilePos (PrivateData, File, (UINT32) Amount);\r
+\r
+ BufferPtr += Amount;\r
+ Size -= Amount;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function reads the next item in the parent directory and\r
+ initializes the output parameter SubFile (CurrentPos is initialized to 0).\r
+ The function updates the CurrentPos of the parent dir to after the item read.\r
+ If no more items were found, the function returns EFI_NOT_FOUND.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param ParentDir The parent directory. \r
+ @param SubFile The File structure containing the sub file that \r
+ is caught. \r
+\r
+ @retval EFI_SUCCESS The next sub file is obtained. \r
+ @retval EFI_INVALID_PARAMETER The ParentDir is not a directory. \r
+ @retval EFI_NOT_FOUND No more sub file exists. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadNextDirectoryEntry (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *ParentDir,\r
+ OUT PEI_FAT_FILE *SubFile\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_DIRECTORY_ENTRY DirEntry;\r
+ CHAR16 *Pos;\r
+ CHAR16 BaseName[9];\r
+ CHAR16 Ext[4];\r
+\r
+ ZeroMem ((UINT8 *) SubFile, sizeof (PEI_FAT_FILE));\r
+\r
+ //\r
+ // Pick a valid directory entry\r
+ //\r
+ while (1) {\r
+ //\r
+ // Read one entry\r
+ //\r
+ Status = FatReadFile (PrivateData, ParentDir, 32, &DirEntry);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // We only search for *FILE* in root directory\r
+ // Long file name entry is *NOT* supported\r
+ //\r
+ if (((DirEntry.Attributes & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) || (DirEntry.Attributes == FAT_ATTR_LFN)) {\r
+ continue;\r
+ }\r
+ //\r
+ // if this is a terminator dir entry, just return EFI_NOT_FOUND\r
+ //\r
+ if (DirEntry.FileName[0] == EMPTY_ENTRY_MARK) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // If this not an invalid entry neither an empty entry, this is what we want.\r
+ // otherwise we will start a new loop to continue to find something meaningful\r
+ //\r
+ if ((UINT8) DirEntry.FileName[0] != DELETE_ENTRY_MARK) {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // fill in the output parameter\r
+ //\r
+ EngFatToStr (8, DirEntry.FileName, BaseName);\r
+ EngFatToStr (3, DirEntry.FileName + 8, Ext);\r
+\r
+ Pos = (UINT16 *) SubFile->FileName;\r
+ SetMem ((UINT8 *) Pos, FAT_MAX_FILE_NAME_LENGTH, 0);\r
+ CopyMem ((UINT8 *) Pos, (UINT8 *) BaseName, 2 * (StrLen (BaseName) + 1));\r
+\r
+ if (Ext[0] != 0) {\r
+ Pos += StrLen (BaseName);\r
+ *Pos = '.';\r
+ Pos++;\r
+ CopyMem ((UINT8 *) Pos, (UINT8 *) Ext, 2 * (StrLen (Ext) + 1));\r
+ }\r
+\r
+ SubFile->Attributes = DirEntry.Attributes;\r
+ SubFile->CurrentCluster = DirEntry.FileCluster;\r
+ if (ParentDir->Volume->FatType == Fat32) {\r
+ SubFile->CurrentCluster |= DirEntry.FileClusterHigh << 16;\r
+ }\r
+\r
+ SubFile->CurrentPos = 0;\r
+ SubFile->FileSize = DirEntry.FileSize;\r
+ SubFile->StartingCluster = SubFile->CurrentCluster;\r
+ SubFile->Volume = ParentDir->Volume;\r
+\r
+ //\r
+ // in Pei phase, time parameters do not need to be filled for minimum use.\r
+ //\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.\r
+\r
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+PEI_FAT_PRIVATE_DATA *mPrivateData = NULL;\r
+\r
+/**\r
+ BlockIo installation nofication function. Find out all the current BlockIO\r
+ PPIs in the system and add them into private data. Assume there is\r
+\r
+ @param PeiServices General purpose services available to every \r
+ PEIM. \r
+ @param NotifyDescriptor The typedef structure of the notification \r
+ descriptor. Not used in this function. \r
+ @param Ppi The typedef structure of the PPI descriptor. \r
+ Not used in this function. \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BlockIoNotifyEntry (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ );\r
+\r
+\r
+/**\r
+ Discover all the block I/O devices to find the FAT volume.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+ @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo\r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateBlocksAndVolumes (\r
+ IN OUT PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN BOOLEAN BlockIo2\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;\r
+ UINTN BlockIoPpiInstance;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;\r
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;\r
+ UINTN NumberBlockDevices;\r
+ UINTN Index;\r
+ EFI_PEI_BLOCK_IO_MEDIA Media;\r
+ EFI_PEI_BLOCK_IO2_MEDIA Media2;\r
+ PEI_FAT_VOLUME Volume;\r
+ EFI_PEI_SERVICES **PeiServices;\r
+\r
+ PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();\r
+ BlockIo2Ppi = NULL;\r
+ BlockIoPpi = NULL;\r
+ //\r
+ // Clean up caches\r
+ //\r
+ for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+ PrivateData->CacheBuffer[Index].Valid = FALSE;\r
+ }\r
+\r
+ PrivateData->BlockDeviceCount = 0;\r
+\r
+ //\r
+ // Find out all Block Io Ppi instances within the system\r
+ // Assuming all device Block Io Peims are dispatched already\r
+ //\r
+ for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {\r
+ if (BlockIo2) {\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiVirtualBlockIo2PpiGuid,\r
+ BlockIoPpiInstance,\r
+ &TempPpiDescriptor,\r
+ (VOID **) &BlockIo2Ppi\r
+ );\r
+ } else {\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiVirtualBlockIoPpiGuid,\r
+ BlockIoPpiInstance,\r
+ &TempPpiDescriptor,\r
+ (VOID **) &BlockIoPpi\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Done with all Block Io Ppis\r
+ //\r
+ break;\r
+ }\r
+\r
+ if (BlockIo2) {\r
+ Status = BlockIo2Ppi->GetNumberOfBlockDevices (\r
+ PeiServices,\r
+ BlockIo2Ppi,\r
+ &NumberBlockDevices\r
+ );\r
+ } else {\r
+ Status = BlockIoPpi->GetNumberOfBlockDevices (\r
+ PeiServices,\r
+ BlockIoPpi,\r
+ &NumberBlockDevices\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) {\r
+\r
+ if (BlockIo2) {\r
+ Status = BlockIo2Ppi->GetBlockDeviceMediaInfo (\r
+ PeiServices,\r
+ BlockIo2Ppi,\r
+ Index,\r
+ &Media2\r
+ );\r
+ if (EFI_ERROR (Status) || !Media2.MediaPresent) {\r
+ continue;\r
+ }\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo2 = BlockIo2Ppi;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].InterfaceType = Media2.InterfaceType;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media2.LastBlock;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = Media2.BlockSize;\r
+ } else {\r
+ Status = BlockIoPpi->GetBlockDeviceMediaInfo (\r
+ PeiServices,\r
+ BlockIoPpi,\r
+ Index,\r
+ &Media\r
+ );\r
+ if (EFI_ERROR (Status) || !Media.MediaPresent) {\r
+ continue;\r
+ }\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize;\r
+ }\r
+\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0;\r
+ //\r
+ // Not used here\r
+ //\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical = FALSE;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked = FALSE;\r
+\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8) Index;\r
+ PrivateData->BlockDeviceCount++;\r
+ }\r
+ }\r
+ //\r
+ // Find out all logical devices\r
+ //\r
+ FatFindPartitions (PrivateData);\r
+\r
+ //\r
+ // Build up file system volume array\r
+ //\r
+ PrivateData->VolumeCount = 0;\r
+ for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {\r
+ Volume.BlockDeviceNo = Index;\r
+ Status = FatGetBpbInfo (PrivateData, &Volume);\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // Add the detected volume to the volume array\r
+ //\r
+ CopyMem (\r
+ (UINT8 *) &(PrivateData->Volume[PrivateData->VolumeCount]),\r
+ (UINT8 *) &Volume,\r
+ sizeof (PEI_FAT_VOLUME)\r
+ );\r
+ PrivateData->VolumeCount += 1;\r
+ if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ BlockIo installation notification function. Find out all the current BlockIO\r
+ PPIs in the system and add them into private data. Assume there is\r
+\r
+ @param PeiServices General purpose services available to every \r
+ PEIM. \r
+ @param NotifyDescriptor The typedef structure of the notification \r
+ descriptor. Not used in this function. \r
+ @param Ppi The typedef structure of the PPI descriptor. \r
+ Not used in this function. \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BlockIoNotifyEntry (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ )\r
+{\r
+ if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) {\r
+ UpdateBlocksAndVolumes (mPrivateData, TRUE);\r
+ } else {\r
+ UpdateBlocksAndVolumes (mPrivateData, FALSE);\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Installs the Device Recovery Module PPI, Initialize BlockIo Ppi\r
+ installation notification\r
+\r
+ @param FileHandle Handle of the file being invoked. Type \r
+ EFI_PEI_FILE_HANDLE is defined in \r
+ FfsFindNextFile(). \r
+ @param PeiServices Describes the list of possible PEI Services. \r
+\r
+ @retval EFI_SUCCESS The entry point was executed successfully. \r
+ @retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the \r
+ operations.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FatPeimEntry (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ PEI_FAT_PRIVATE_DATA *PrivateData;\r
+\r
+ Status = PeiServicesRegisterForShadow (FileHandle);\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ (sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE + 1,\r
+ &Address\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ PrivateData = (PEI_FAT_PRIVATE_DATA *) (UINTN) Address;\r
+\r
+ //\r
+ // Initialize Private Data (to zero, as is required by subsequent operations)\r
+ //\r
+ ZeroMem ((UINT8 *) PrivateData, sizeof (PEI_FAT_PRIVATE_DATA));\r
+\r
+ PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE;\r
+\r
+ //\r
+ // Installs Ppi\r
+ //\r
+ PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules;\r
+ PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo;\r
+ PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule;\r
+\r
+ PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;\r
+ PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;\r
+\r
+ Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Other initializations\r
+ //\r
+ PrivateData->BlockDeviceCount = 0;\r
+\r
+ UpdateBlocksAndVolumes (PrivateData, TRUE);\r
+ UpdateBlocksAndVolumes (PrivateData, FALSE);\r
+\r
+ //\r
+ // PrivateData is allocated now, set it to the module variable\r
+ //\r
+ mPrivateData = PrivateData;\r
+\r
+ //\r
+ // Installs Block Io Ppi notification function\r
+ //\r
+ PrivateData->NotifyDescriptor[0].Flags =\r
+ (\r
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK\r
+ );\r
+ PrivateData->NotifyDescriptor[0].Guid = &gEfiPeiVirtualBlockIoPpiGuid;\r
+ PrivateData->NotifyDescriptor[0].Notify = BlockIoNotifyEntry;\r
+ PrivateData->NotifyDescriptor[1].Flags =\r
+ (\r
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |\r
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST\r
+ );\r
+ PrivateData->NotifyDescriptor[1].Guid = &gEfiPeiVirtualBlockIo2PpiGuid;\r
+ PrivateData->NotifyDescriptor[1].Notify = BlockIoNotifyEntry;\r
+ return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor[0]);\r
+}\r
+\r
+\r
+/**\r
+ Returns the number of DXE capsules residing on the device.\r
+\r
+ This function searches for DXE capsules from the associated device and returns\r
+ the number and maximum size in bytes of the capsules discovered. Entry 1 is \r
+ assumed to be the highest load priority and entry N is assumed to be the lowest \r
+ priority.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On \r
+ output, *NumberRecoveryCapsules contains \r
+ the number of recovery capsule images \r
+ available for retrieval from this PEIM \r
+ instance.\r
+\r
+ @retval EFI_SUCCESS One or more capsules were discovered.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberRecoveryCapsules (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ OUT UINTN *NumberRecoveryCapsules\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_PRIVATE_DATA *PrivateData;\r
+ UINTN Index;\r
+ UINTN RecoveryCapsuleCount;\r
+ PEI_FILE_HANDLE Handle;\r
+\r
+ PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Search each volume in the root directory for the Recovery capsule\r
+ //\r
+ RecoveryCapsuleCount = 0;\r
+ for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
+ Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ RecoveryCapsuleCount++;\r
+ }\r
+\r
+ *NumberRecoveryCapsules = RecoveryCapsuleCount;\r
+\r
+ if (*NumberRecoveryCapsules == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Returns the size and type of the requested recovery capsule.\r
+\r
+ This function gets the size and type of the capsule specified by CapsuleInstance.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI \r
+ instance.\r
+ @param[in] CapsuleInstance Specifies for which capsule instance to retrieve \r
+ the information. This parameter must be between \r
+ one and the value returned by GetNumberRecoveryCapsules() \r
+ in NumberRecoveryCapsules.\r
+ @param[out] Size A pointer to a caller-allocated UINTN in which \r
+ the size of the requested recovery module is \r
+ returned.\r
+ @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which \r
+ the type of the requested recovery capsule is \r
+ returned. The semantic meaning of the value \r
+ returned is defined by the implementation.\r
+\r
+ @retval EFI_SUCCESS One or more capsules were discovered.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetRecoveryCapsuleInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT UINTN *Size,\r
+ OUT EFI_GUID *CapsuleType\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_PRIVATE_DATA *PrivateData;\r
+ UINTN Index;\r
+ UINTN BlockDeviceNo;\r
+ UINTN RecoveryCapsuleCount;\r
+ PEI_FILE_HANDLE Handle;\r
+ UINTN NumberRecoveryCapsules;\r
+\r
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+ CapsuleInstance = CapsuleInstance + 1;\r
+ }\r
+\r
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Search each volume in the root directory for the Recovery capsule\r
+ //\r
+ RecoveryCapsuleCount = 0;\r
+ for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
+ Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (CapsuleInstance - 1 == RecoveryCapsuleCount) {\r
+ //\r
+ // Get file size\r
+ //\r
+ *Size = (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize);\r
+\r
+ //\r
+ // Find corresponding physical block device\r
+ //\r
+ BlockDeviceNo = PrivateData->Volume[Index].BlockDeviceNo;\r
+ while (PrivateData->BlockDevice[BlockDeviceNo].Logical && BlockDeviceNo < PrivateData->BlockDeviceCount) {\r
+ BlockDeviceNo = PrivateData->BlockDevice[BlockDeviceNo].ParentDevNo;\r
+ }\r
+ //\r
+ // Fill in the Capsule Type GUID according to the block device type\r
+ //\r
+ if (BlockDeviceNo < PrivateData->BlockDeviceCount) {\r
+ if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo2 != NULL) {\r
+ switch (PrivateData->BlockDevice[BlockDeviceNo].InterfaceType) {\r
+ case MSG_ATAPI_DP:\r
+ CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);\r
+ break;\r
+\r
+ case MSG_USB_DP:\r
+ CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo != NULL) {\r
+ switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) {\r
+ case LegacyFloppy:\r
+ CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid);\r
+ break;\r
+\r
+ case IdeCDROM:\r
+ case IdeLS120:\r
+ CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);\r
+ break;\r
+\r
+ case UsbMassStorage:\r
+ CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ RecoveryCapsuleCount++;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Loads a DXE capsule from some media into memory.\r
+\r
+ This function, by whatever mechanism, retrieves a DXE capsule from some device\r
+ and loads it into memory. Note that the published interface is device neutral.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.\r
+ @param[out] Buffer Specifies a caller-allocated buffer in which \r
+ the requested recovery capsule will be returned.\r
+\r
+ @retval EFI_SUCCESS The capsule was loaded correctly.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadRecoveryCapsule (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_PRIVATE_DATA *PrivateData;\r
+ UINTN Index;\r
+ UINTN RecoveryCapsuleCount;\r
+ PEI_FILE_HANDLE Handle;\r
+ UINTN NumberRecoveryCapsules;\r
+\r
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+ CapsuleInstance = CapsuleInstance + 1;\r
+ }\r
+\r
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Search each volume in the root directory for the Recovery capsule\r
+ //\r
+ RecoveryCapsuleCount = 0;\r
+ for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
+ Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (CapsuleInstance - 1 == RecoveryCapsuleCount) {\r
+\r
+ Status = FatReadFile (\r
+ PrivateData,\r
+ Handle,\r
+ (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize),\r
+ Buffer\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ RecoveryCapsuleCount++;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Finds the recovery file on a FAT volume.\r
+ This function finds the the recovery file named FileName on a specified FAT volume and returns\r
+ its FileHandle pointer.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+ @param VolumeIndex The index of the volume. \r
+ @param FileName The recovery file name to find. \r
+ @param Handle The output file handle. \r
+\r
+ @retval EFI_DEVICE_ERROR Some error occured when operating the FAT \r
+ volume. \r
+ @retval EFI_NOT_FOUND The recovery file was not found. \r
+ @retval EFI_SUCCESS The recovery file was successfully found on the \r
+ FAT volume.\r
+\r
+**/\r
+EFI_STATUS\r
+FindRecoveryFile (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN VolumeIndex,\r
+ IN CHAR16 *FileName,\r
+ OUT PEI_FILE_HANDLE *Handle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_FILE Parent;\r
+ PEI_FAT_FILE *File;\r
+\r
+ File = &PrivateData->File;\r
+\r
+ //\r
+ // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount\r
+ // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.\r
+ //\r
+ ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME);\r
+\r
+ //\r
+ // Construct root directory file\r
+ //\r
+ ZeroMem (&Parent, sizeof (PEI_FAT_FILE));\r
+ Parent.IsFixedRootDir = (BOOLEAN) ((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE);\r
+ Parent.Attributes = FAT_ATTR_DIRECTORY;\r
+ Parent.CurrentPos = 0;\r
+ Parent.CurrentCluster = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster;\r
+ Parent.StartingCluster = Parent.CurrentCluster;\r
+ Parent.Volume = &PrivateData->Volume[VolumeIndex];\r
+\r
+ Status = FatSetFilePos (PrivateData, &Parent, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Search for recovery capsule in root directory\r
+ //\r
+ Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);\r
+ while (Status == EFI_SUCCESS) {\r
+ //\r
+ // Compare whether the file name is recovery file name.\r
+ //\r
+ if (EngStriColl (PrivateData, FileName, File->FileName)) {\r
+ break;\r
+ }\r
+\r
+ Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Get the recovery file, set its file position to 0.\r
+ //\r
+ if (File->StartingCluster != 0) {\r
+ Status = FatSetFilePos (PrivateData, File, 0);\r
+ }\r
+\r
+ *Handle = File;\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
--- /dev/null
+/** @file\r
+ Definitions for FAT recovery PEIM API functions\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FAT_API_H_\r
+#define _FAT_API_H_\r
+\r
+//\r
+// API data structures\r
+//\r
+typedef VOID *PEI_FILE_HANDLE;\r
+\r
+typedef enum {\r
+ Fat12,\r
+ Fat16,\r
+ Fat32,\r
+ FatUnknown\r
+} PEI_FAT_TYPE;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ FAT format data structures\r
+\r
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FAT_FMT_H_\r
+#define _FAT_FMT_H_\r
+\r
+//\r
+// Definitions\r
+//\r
+#define FAT_ATTR_READ_ONLY 0x01\r
+#define FAT_ATTR_HIDDEN 0x02\r
+#define FAT_ATTR_SYSTEM 0x04\r
+#define FAT_ATTR_VOLUME_ID 0x08\r
+#define FAT_ATTR_DIRECTORY 0x10\r
+#define FAT_ATTR_ARCHIVE 0x20\r
+#define FAT_ATTR_LFN (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)\r
+\r
+#define FAT_CLUSTER_SPECIAL ((-1 &~0xF) | 0x7)\r
+#define FAT_CLUSTER_FREE 0\r
+#define FAT_CLUSTER_RESERVED (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_BAD (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_LAST (-1)\r
+\r
+#define DELETE_ENTRY_MARK 0xE5\r
+#define EMPTY_ENTRY_MARK 0x00\r
+\r
+#define FAT_CLUSTER_FUNCTIONAL(Cluster) (((Cluster) == 0) || ((Cluster) >= FAT_CLUSTER_SPECIAL))\r
+#define FAT_CLUSTER_END_OF_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL))\r
+\r
+//\r
+// Directory Entry\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ UINT16 Day : 5;\r
+ UINT16 Month : 4;\r
+ UINT16 Year : 7; // From 1980\r
+} FAT_DATE;\r
+\r
+typedef struct {\r
+ UINT16 DoubleSecond : 5;\r
+ UINT16 Minute : 6;\r
+ UINT16 Hour : 5;\r
+} FAT_TIME;\r
+\r
+typedef struct {\r
+ FAT_TIME Time;\r
+ FAT_DATE Date;\r
+} FAT_DATE_TIME;\r
+\r
+typedef struct {\r
+ CHAR8 FileName[11]; // 8.3 filename\r
+ UINT8 Attributes;\r
+ UINT8 CaseFlag;\r
+ UINT8 CreateMillisecond; // (creation milliseconds - ignored)\r
+ FAT_DATE_TIME FileCreateTime;\r
+ FAT_DATE FileLastAccess;\r
+ UINT16 FileClusterHigh; // >= FAT32\r
+ FAT_DATE_TIME FileModificationTime;\r
+ UINT16 FileCluster;\r
+ UINT32 FileSize;\r
+} FAT_DIRECTORY_ENTRY;\r
+\r
+#pragma pack()\r
+//\r
+// Boot Sector\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+\r
+ UINT8 Ia32Jump[3];\r
+ CHAR8 OemId[8];\r
+\r
+ UINT16 SectorSize;\r
+ UINT8 SectorsPerCluster;\r
+ UINT16 ReservedSectors;\r
+ UINT8 NoFats;\r
+ UINT16 RootEntries; // < FAT32, root dir is fixed size\r
+ UINT16 Sectors;\r
+ UINT8 Media; // (ignored)\r
+ UINT16 SectorsPerFat; // < FAT32\r
+ UINT16 SectorsPerTrack; // (ignored)\r
+ UINT16 Heads; // (ignored)\r
+ UINT32 HiddenSectors; // (ignored)\r
+ UINT32 LargeSectors; // => FAT32\r
+ UINT8 PhysicalDriveNumber; // (ignored)\r
+ UINT8 CurrentHead; // holds boot_sector_dirty bit\r
+ UINT8 Signature; // (ignored)\r
+ CHAR8 Id[4];\r
+ CHAR8 FatLabel[11];\r
+ CHAR8 SystemId[8];\r
+\r
+} PEI_FAT_BOOT_SECTOR;\r
+\r
+typedef struct {\r
+\r
+ UINT8 Ia32Jump[3];\r
+ CHAR8 OemId[8];\r
+\r
+ UINT16 SectorSize;\r
+ UINT8 SectorsPerCluster;\r
+ UINT16 ReservedSectors;\r
+ UINT8 NoFats;\r
+ UINT16 RootEntries; // < FAT32, root dir is fixed size\r
+ UINT16 Sectors;\r
+ UINT8 Media; // (ignored)\r
+ UINT16 SectorsPerFat; // < FAT32\r
+ UINT16 SectorsPerTrack; // (ignored)\r
+ UINT16 Heads; // (ignored)\r
+ UINT32 HiddenSectors; // (ignored)\r
+ UINT32 LargeSectors; // Used if Sectors==0\r
+ UINT32 LargeSectorsPerFat; // FAT32\r
+ UINT16 ExtendedFlags; // FAT32 (ignored)\r
+ UINT16 FsVersion; // FAT32 (ignored)\r
+ UINT32 RootDirFirstCluster; // FAT32\r
+ UINT16 FsInfoSector; // FAT32\r
+ UINT16 BackupBootSector; // FAT32\r
+ UINT8 Reserved[12]; // FAT32 (ignored)\r
+ UINT8 PhysicalDriveNumber; // (ignored)\r
+ UINT8 CurrentHead; // holds boot_sector_dirty bit\r
+ UINT8 Signature; // (ignored)\r
+ CHAR8 Id[4];\r
+ CHAR8 FatLabel[11];\r
+ CHAR8 SystemId[8];\r
+\r
+} PEI_FAT_BOOT_SECTOR_EX;\r
+\r
+#pragma pack()\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ General purpose supporting routines for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+\r
+#define CHAR_FAT_VALID 0x01\r
+\r
+\r
+/**\r
+ Converts a union code character to upper case.\r
+ This functions converts a unicode character to upper case.\r
+ If the input Letter is not a lower-cased letter,\r
+ the original value is returned.\r
+\r
+ @param Letter The input unicode character. \r
+\r
+ @return The upper cased letter.\r
+\r
+**/\r
+CHAR16\r
+ToUpper (\r
+ IN CHAR16 Letter\r
+ )\r
+{\r
+ if ('a' <= Letter && Letter <= 'z') {\r
+ Letter = (CHAR16) (Letter - 0x20);\r
+ }\r
+\r
+ return Letter;\r
+}\r
+\r
+\r
+/**\r
+ Reads a block of data from the block device by calling\r
+ underlying Block I/O service.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param BlockDeviceNo The index for the block device number. \r
+ @param Lba The logic block address to read data from. \r
+ @param BufferSize The size of data in byte to read. \r
+ @param Buffer The buffer of the \r
+\r
+ @retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum \r
+ device number. \r
+ @retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address \r
+ of the block device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadBlock (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN EFI_PEI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_BLOCK_DEVICE *BlockDev;\r
+\r
+ if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ BlockDev = &(PrivateData->BlockDevice[BlockDeviceNo]);\r
+\r
+ if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (!BlockDev->Logical) {\r
+ //\r
+ // Status = BlockDev->ReadFunc\r
+ // (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer);\r
+ //\r
+ if (BlockDev->BlockIo2 != NULL) {\r
+ Status = BlockDev->BlockIo2->ReadBlocks (\r
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),\r
+ BlockDev->BlockIo2,\r
+ BlockDev->PhysicalDevNo,\r
+ Lba,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+ } else {\r
+ Status = BlockDev->BlockIo->ReadBlocks (\r
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),\r
+ BlockDev->BlockIo,\r
+ BlockDev->PhysicalDevNo,\r
+ Lba,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+ }\r
+\r
+ } else {\r
+ Status = FatReadDisk (\r
+ PrivateData,\r
+ BlockDev->ParentDevNo,\r
+ BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize),\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Find a cache block designated to specific Block device and Lba.\r
+ If not found, invalidate an oldest one and use it. (LRU cache)\r
+\r
+ @param PrivateData the global memory map. \r
+ @param BlockDeviceNo the Block device. \r
+ @param Lba the Logical Block Address \r
+ @param CachePtr Ptr to the starting address of the memory holding the \r
+ data; \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetCacheBlock (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN UINT64 Lba,\r
+ OUT CHAR8 **CachePtr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_CACHE_BUFFER *CacheBuffer;\r
+ INTN Index;\r
+ STATIC UINT8 Seed;\r
+\r
+ Status = EFI_SUCCESS;\r
+ CacheBuffer = NULL;\r
+\r
+ //\r
+ // go through existing cache buffers\r
+ //\r
+ for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+ CacheBuffer = &(PrivateData->CacheBuffer[Index]);\r
+ if (CacheBuffer->Valid && CacheBuffer->BlockDeviceNo == BlockDeviceNo && CacheBuffer->Lba == Lba) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index < PEI_FAT_CACHE_SIZE) {\r
+ *CachePtr = (CHAR8 *) CacheBuffer->Buffer;\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // We have to find an invalid cache buffer\r
+ //\r
+ for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+ if (!PrivateData->CacheBuffer[Index].Valid) {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Use the cache buffer\r
+ //\r
+ if (Index == PEI_FAT_CACHE_SIZE) {\r
+ Index = (Seed++) % PEI_FAT_CACHE_SIZE;\r
+ }\r
+ \r
+ //\r
+ // Current device ID should be less than maximum device ID. \r
+ //\r
+ if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CacheBuffer = &(PrivateData->CacheBuffer[Index]);\r
+\r
+ CacheBuffer->BlockDeviceNo = BlockDeviceNo;\r
+ CacheBuffer->Lba = Lba;\r
+ CacheBuffer->Size = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
+\r
+ //\r
+ // Read in the data\r
+ //\r
+ Status = FatReadBlock (\r
+ PrivateData,\r
+ BlockDeviceNo,\r
+ Lba,\r
+ CacheBuffer->Size,\r
+ CacheBuffer->Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CacheBuffer->Valid = TRUE;\r
+ *CachePtr = (CHAR8 *) CacheBuffer->Buffer;\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Disk reading.\r
+\r
+ @param PrivateData the global memory map; \r
+ @param BlockDeviceNo the block device to read; \r
+ @param StartingAddress the starting address. \r
+ @param Size the amount of data to read. \r
+ @param Buffer the buffer holding the data \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_DEVICE_ERROR Something error.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadDisk (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN UINT64 StartingAddress,\r
+ IN UINTN Size,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ CHAR8 *BufferPtr;\r
+ CHAR8 *CachePtr;\r
+ UINT32 Offset;\r
+ UINT64 Lba;\r
+ UINT64 OverRunLba;\r
+ UINTN Amount;\r
+\r
+ Status = EFI_SUCCESS;\r
+ BufferPtr = Buffer;\r
+ BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
+\r
+ //\r
+ // Read underrun\r
+ //\r
+ Lba = DivU64x32Remainder (StartingAddress, BlockSize, &Offset);\r
+ Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset);\r
+ CopyMem (BufferPtr, CachePtr + Offset, Amount);\r
+\r
+ if (Size == Amount) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Size -= Amount;\r
+ BufferPtr += Amount;\r
+ StartingAddress += Amount;\r
+ Lba += 1;\r
+\r
+ //\r
+ // Read aligned parts\r
+ //\r
+ OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset);\r
+\r
+ Size -= Offset;\r
+ Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ BufferPtr += Size;\r
+\r
+ //\r
+ // Read overrun\r
+ //\r
+ if (Offset != 0) {\r
+ Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CopyMem (BufferPtr, CachePtr, Offset);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This version is different from the version in Unicode collation\r
+ protocol in that this version strips off trailing blanks.\r
+ Converts an 8.3 FAT file name using an OEM character set\r
+ to a Null-terminated Unicode string.\r
+ Here does not expand DBCS FAT chars.\r
+\r
+ @param FatSize The size of the string Fat in bytes. \r
+ @param Fat A pointer to a Null-terminated string that contains \r
+ an 8.3 file name using an OEM character set. \r
+ @param Str A pointer to a Null-terminated Unicode string. The \r
+ string must be allocated in advance to hold FatSize \r
+ Unicode characters\r
+\r
+**/\r
+VOID\r
+EngFatToStr (\r
+ IN UINTN FatSize,\r
+ IN CHAR8 *Fat,\r
+ OUT CHAR16 *Str\r
+ )\r
+{\r
+ CHAR16 *String;\r
+\r
+ String = Str;\r
+ //\r
+ // No DBCS issues, just expand and add null terminate to end of string\r
+ //\r
+ while (*Fat != 0 && FatSize != 0) {\r
+ if (*Fat == ' ') {\r
+ break;\r
+ }\r
+ *String = *Fat;\r
+ String += 1;\r
+ Fat += 1;\r
+ FatSize -= 1;\r
+ }\r
+\r
+ *String = 0;\r
+}\r
+\r
+\r
+/**\r
+ Performs a case-insensitive comparison of two Null-terminated Unicode strings.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param Str1 First string to perform case insensitive comparison. \r
+ @param Str2 Second string to perform case insensitive comparison.\r
+\r
+**/\r
+BOOLEAN\r
+EngStriColl (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN CHAR16 *Str1,\r
+ IN CHAR16 *Str2\r
+ )\r
+{\r
+ CHAR16 UpperS1;\r
+ CHAR16 UpperS2;\r
+\r
+ UpperS1 = ToUpper (*Str1);\r
+ UpperS2 = ToUpper (*Str2);\r
+ while (*Str1 != 0) {\r
+ if (UpperS1 != UpperS2) {\r
+ return FALSE;\r
+ }\r
+\r
+ Str1++;\r
+ Str2++;\r
+ UpperS1 = ToUpper (*Str1);\r
+ UpperS2 = ToUpper (*Str2);\r
+ }\r
+\r
+ return (BOOLEAN) ((*Str2 != 0) ? FALSE : TRUE);\r
+}\r
--- /dev/null
+/** @file\r
+ Data structures for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FAT_PEIM_H_\r
+#define _FAT_PEIM_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Guid/RecoveryDevice.h>\r
+#include <Ppi/BlockIo.h>\r
+#include <Ppi/BlockIo2.h>\r
+#include <Ppi/DeviceRecoveryModule.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PeiServicesTablePointerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include "FatLiteApi.h"\r
+#include "FatLiteFmt.h"\r
+\r
+//\r
+// Definitions\r
+//\r
+#define PEI_FAT_RECOVERY_CAPSULE_WITH_NT_EMULATOR L"fv0001.fv"\r
+#define PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR L"fvmain.fv"\r
+\r
+#define PEI_FAT_CACHE_SIZE 4\r
+#define PEI_FAT_MAX_BLOCK_SIZE 8192\r
+#define FAT_MAX_FILE_NAME_LENGTH 128\r
+#define PEI_FAT_MAX_BLOCK_DEVICE 64\r
+#define PEI_FAT_MAX_BLOCK_IO_PPI 32\r
+#define PEI_FAT_MAX_VOLUME 64\r
+\r
+#define PEI_FAT_MEMMORY_PAGE_SIZE 0x1000\r
+\r
+//\r
+// Data Structures\r
+//\r
+//\r
+// The block device\r
+//\r
+typedef struct {\r
+\r
+ UINT32 BlockSize;\r
+ UINT64 LastBlock;\r
+ UINT32 IoAlign;\r
+ BOOLEAN Logical;\r
+ BOOLEAN PartitionChecked;\r
+\r
+ //\r
+ // Following fields only valid for logical device\r
+ //\r
+ CHAR8 PartitionFlag[8];\r
+ UINT64 StartingPos;\r
+ UINTN ParentDevNo;\r
+\r
+ //\r
+ // Following fields only valid for physical device\r
+ //\r
+ EFI_PEI_BLOCK_DEVICE_TYPE DevType;\r
+ UINT8 InterfaceType;\r
+ //\r
+ // EFI_PEI_READ_BLOCKS ReadFunc;\r
+ //\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo;\r
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2;\r
+ UINT8 PhysicalDevNo;\r
+} PEI_FAT_BLOCK_DEVICE;\r
+\r
+//\r
+// the Volume structure\r
+//\r
+typedef struct {\r
+\r
+ UINTN BlockDeviceNo;\r
+ UINTN VolumeNo;\r
+ UINT64 VolumeSize;\r
+ UINTN MaxCluster;\r
+ CHAR16 VolumeLabel[FAT_MAX_FILE_NAME_LENGTH];\r
+ PEI_FAT_TYPE FatType;\r
+ UINT64 FatPos;\r
+ UINT32 SectorSize;\r
+ UINT32 ClusterSize;\r
+ UINT64 FirstClusterPos;\r
+ UINT64 RootDirPos;\r
+ UINT32 RootEntries;\r
+ UINT32 RootDirCluster;\r
+\r
+} PEI_FAT_VOLUME;\r
+\r
+//\r
+// File instance\r
+//\r
+typedef struct {\r
+\r
+ PEI_FAT_VOLUME *Volume;\r
+ CHAR16 FileName[FAT_MAX_FILE_NAME_LENGTH];\r
+\r
+ BOOLEAN IsFixedRootDir;\r
+\r
+ UINT32 StartingCluster;\r
+ UINT32 CurrentPos;\r
+ UINT32 StraightReadAmount;\r
+ UINT32 CurrentCluster;\r
+\r
+ UINT8 Attributes;\r
+ UINT32 FileSize;\r
+\r
+} PEI_FAT_FILE;\r
+\r
+//\r
+// Cache Buffer\r
+//\r
+typedef struct {\r
+\r
+ BOOLEAN Valid;\r
+ UINTN BlockDeviceNo;\r
+ UINT64 Lba;\r
+ UINT32 Lru;\r
+ UINT64 Buffer[PEI_FAT_MAX_BLOCK_SIZE / 8];\r
+ UINTN Size;\r
+\r
+} PEI_FAT_CACHE_BUFFER;\r
+\r
+//\r
+// Private Data.\r
+// This structure abstracts the whole memory usage in FAT PEIM.\r
+// The entry point routine will get a chunk of memory (by whatever\r
+// means) whose size is sizeof(PEI_FAT_PRIVATE_DATA), which is clean\r
+// in both 32 and 64 bit environment. The boundary of the memory chunk\r
+// should be 64bit aligned.\r
+//\r
+#define PEI_FAT_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('p', 'f', 'a', 't')\r
+\r
+typedef struct {\r
+\r
+ UINTN Signature;\r
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI DeviceRecoveryPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;\r
+ EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor[2];\r
+\r
+ UINT8 UnicodeCaseMap[0x300];\r
+ CHAR8 *EngUpperMap;\r
+ CHAR8 *EngLowerMap;\r
+ CHAR8 *EngInfoMap;\r
+\r
+ UINT64 BlockData[PEI_FAT_MAX_BLOCK_SIZE / 8];\r
+ UINTN BlockDeviceCount;\r
+ PEI_FAT_BLOCK_DEVICE BlockDevice[PEI_FAT_MAX_BLOCK_DEVICE];\r
+ UINTN VolumeCount;\r
+ PEI_FAT_VOLUME Volume[PEI_FAT_MAX_VOLUME];\r
+ PEI_FAT_FILE File;\r
+ PEI_FAT_CACHE_BUFFER CacheBuffer[PEI_FAT_CACHE_SIZE];\r
+\r
+} PEI_FAT_PRIVATE_DATA;\r
+\r
+#define PEI_FAT_PRIVATE_DATA_FROM_THIS(a) \\r
+ CR (a, PEI_FAT_PRIVATE_DATA, DeviceRecoveryPpi, PEI_FAT_PRIVATE_DATA_SIGNATURE)\r
+\r
+//\r
+// Extract INT32 from char array\r
+//\r
+#define UNPACK_INT32(a) \\r
+ (INT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))\r
+\r
+//\r
+// Extract UINT32 from char array\r
+//\r
+#define UNPACK_UINT32(a) \\r
+ (UINT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))\r
+\r
+\r
+//\r
+// API functions\r
+//\r
+\r
+/**\r
+ Finds the recovery file on a FAT volume.\r
+ This function finds the the recovery file named FileName on a specified FAT volume and returns\r
+ its FileHandle pointer.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+ @param VolumeIndex The index of the volume. \r
+ @param FileName The recovery file name to find. \r
+ @param Handle The output file handle. \r
+\r
+ @retval EFI_DEVICE_ERROR Some error occured when operating the FAT \r
+ volume. \r
+ @retval EFI_NOT_FOUND The recovery file was not found. \r
+ @retval EFI_SUCCESS The recovery file was successfully found on the \r
+ FAT volume.\r
+\r
+**/\r
+EFI_STATUS\r
+FindRecoveryFile (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN VolumeIndex,\r
+ IN CHAR16 *FileName,\r
+ OUT PEI_FILE_HANDLE *Handle\r
+ );\r
+\r
+\r
+/**\r
+ Returns the number of DXE capsules residing on the device.\r
+ This function, by whatever mechanism, searches for DXE capsules from the associated device and\r
+ returns the number and maximum size in bytes of the capsules discovered.Entry 1 is assumed to be\r
+ the highest load priority and entry N is assumed to be the lowest priority.\r
+\r
+ @param PeiServices General-purpose services that are available to \r
+ every PEIM. \r
+ @param This Indicates the \r
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance. \r
+ @param NumberRecoveryCapsules Pointer to a caller-allocated UINTN.On output, \r
+ *NumberRecoveryCapsules contains the number of \r
+ recovery capsule images available for retrieval \r
+ from this PEIM instance. \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberRecoveryCapsules (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ OUT UINTN *NumberRecoveryCapsules\r
+ );\r
+\r
+\r
+/**\r
+ Returns the size and type of the requested recovery capsule.\r
+ This function returns the size and type of the capsule specified by CapsuleInstance.\r
+\r
+ @param PeiServices General-purpose services that are available to \r
+ every PEIM. \r
+ @param This Indicates the \r
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance. \r
+ @param CapsuleInstance Specifies for which capsule instance to \r
+ retrieve the information.T his parameter must \r
+ be between one and the value returned by \r
+ GetNumberRecoveryCapsules() in \r
+ NumberRecoveryCapsules. \r
+ @param Size A pointer to a caller-allocated UINTN in which \r
+ the size of the requested recovery module is \r
+ returned. \r
+ @param CapsuleType A pointer to a caller-allocated EFI_GUID in \r
+ which the type of the requested recovery \r
+ capsule is returned.T he semantic meaning of \r
+ the value returned is defined by the \r
+ implementation. \r
+\r
+ @retval EFI_SUCCESS The capsule type and size were retrieved. \r
+ @retval EFI_INVALID_PARAMETER The input CapsuleInstance does not match any \r
+ discovered recovery capsule.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetRecoveryCapsuleInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT UINTN *Size,\r
+ OUT EFI_GUID *CapsuleType\r
+ );\r
+\r
+\r
+/**\r
+ Loads a DXE capsule from some media into memory.\r
+\r
+ This function, by whatever mechanism, retrieves a DXE capsule from some device\r
+ and loads it into memory. Note that the published interface is device neutral.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.\r
+ @param[out] Buffer Specifies a caller-allocated buffer in which \r
+ the requested recovery capsule will be returned.\r
+\r
+ @retval EFI_SUCCESS The capsule was loaded correctly.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadRecoveryCapsule (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+ This version is different from the version in Unicode collation\r
+ protocol in that this version strips off trailing blanks.\r
+ Converts an 8.3 FAT file name using an OEM character set\r
+ to a Null-terminated Unicode string.\r
+ Here does not expand DBCS FAT chars.\r
+\r
+ @param FatSize The size of the string Fat in bytes. \r
+ @param Fat A pointer to a Null-terminated string that contains \r
+ an 8.3 file name using an OEM character set. \r
+ @param Str A pointer to a Null-terminated Unicode string. The \r
+ string must be allocated in advance to hold FatSize \r
+ Unicode characters\r
+\r
+**/\r
+VOID\r
+EngFatToStr (\r
+ IN UINTN FatSize,\r
+ IN CHAR8 *Fat,\r
+ OUT CHAR16 *Str\r
+ );\r
+\r
+\r
+/**\r
+ Performs a case-insensitive comparison of two Null-terminated Unicode strings.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param Str1 First string to perform case insensitive comparison. \r
+ @param Str2 Second string to perform case insensitive comparison.\r
+\r
+**/\r
+BOOLEAN\r
+EngStriColl (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN CHAR16 *Str1,\r
+ IN CHAR16 *Str2\r
+ );\r
+\r
+\r
+/**\r
+ Reads a block of data from the block device by calling\r
+ underlying Block I/O service.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param BlockDeviceNo The index for the block device number. \r
+ @param Lba The logic block address to read data from. \r
+ @param BufferSize The size of data in byte to read. \r
+ @param Buffer The buffer of the \r
+\r
+ @retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum \r
+ device number. \r
+ @retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address \r
+ of the block device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadBlock (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN EFI_PEI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+ Check if there is a valid FAT in the corresponding Block device\r
+ of the volume and if yes, fill in the relevant fields for the\r
+ volume structure. Note there should be a valid Block device number\r
+ already set.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+ @param Volume On input, the BlockDeviceNumber field of the \r
+ Volume should be a valid value. On successful \r
+ output, all fields except the VolumeNumber \r
+ field is initialized. \r
+\r
+ @retval EFI_SUCCESS A FAT is found and the volume structure is \r
+ initialized. \r
+ @retval EFI_NOT_FOUND There is no FAT on the corresponding device. \r
+ @retval EFI_DEVICE_ERROR There is something error while accessing device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetBpbInfo (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN OUT PEI_FAT_VOLUME *Volume\r
+ );\r
+\r
+\r
+/**\r
+ Gets the next cluster in the cluster chain.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param Volume The volume \r
+ @param Cluster The cluster \r
+ @param NextCluster The cluster number of the next cluster \r
+\r
+ @retval EFI_SUCCESS The address is got \r
+ @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume. \r
+ @retval EFI_DEVICE_ERROR Read disk error\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetNextCluster (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_VOLUME *Volume,\r
+ IN UINT32 Cluster,\r
+ OUT UINT32 *NextCluster\r
+ );\r
+\r
+\r
+/**\r
+ Disk reading.\r
+\r
+ @param PrivateData the global memory map; \r
+ @param BlockDeviceNo the block device to read; \r
+ @param StartingAddress the starting address. \r
+ @param Size the amount of data to read. \r
+ @param Buffer the buffer holding the data \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_DEVICE_ERROR Something error.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadDisk (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN UINT64 StartingAddress,\r
+ IN UINTN Size,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+ Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.\r
+\r
+ @param PrivateData the global memory map \r
+ @param File the file \r
+ @param Pos the Position which is offset from the file's \r
+ CurrentPos \r
+\r
+ @retval EFI_SUCCESS Success. \r
+ @retval EFI_INVALID_PARAMETER Pos is beyond file's size. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatSetFilePos (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *File,\r
+ IN UINT32 Pos\r
+ );\r
+\r
+\r
+/**\r
+ Reads file data. Updates the file's CurrentPos.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param File The file. \r
+ @param Size The amount of data to read. \r
+ @param Buffer The buffer storing the data. \r
+\r
+ @retval EFI_SUCCESS The data is read. \r
+ @retval EFI_INVALID_PARAMETER File is invalid. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadFile (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *File,\r
+ IN UINTN Size,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+ This function reads the next item in the parent directory and\r
+ initializes the output parameter SubFile (CurrentPos is initialized to 0).\r
+ The function updates the CurrentPos of the parent dir to after the item read.\r
+ If no more items were found, the function returns EFI_NOT_FOUND.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param ParentDir The parent directory. \r
+ @param SubFile The File structure containing the sub file that \r
+ is caught. \r
+\r
+ @retval EFI_SUCCESS The next sub file is obtained. \r
+ @retval EFI_INVALID_PARAMETER The ParentDir is not a directory. \r
+ @retval EFI_NOT_FOUND No more sub file exists. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadNextDirectoryEntry (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *ParentDir,\r
+ OUT PEI_FAT_FILE *SubFile\r
+ );\r
+\r
+\r
+/**\r
+ This function finds partitions (logical devices) in physical block devices.\r
+\r
+ @param PrivateData Global memory map for accessing global variables.\r
+\r
+**/\r
+VOID\r
+FatFindPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData\r
+ );\r
+\r
+#endif // _FAT_PEIM_H_\r
--- /dev/null
+## @file\r
+# Lite Fat driver only used in Pei Phase.\r
+#\r
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are licensed and made available\r
+# under the terms and conditions of the BSD License which accompanies this\r
+# distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = FatPei\r
+ MODULE_UNI_FILE = FatPei.uni\r
+ FILE_GUID = 5B60CCFD-1011-4BCF-B7D1-BB99CA96A603\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = FatPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ Part.c\r
+ FatLiteApi.c\r
+ FatLiteLib.c\r
+ FatLiteAccess.c\r
+ FatLiteApi.h\r
+ FatLitePeim.h\r
+ FatLiteFmt.h\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ PcdLib\r
+ BaseMemoryLib\r
+ PeimEntryPoint\r
+ BaseLib\r
+ DebugLib\r
+ PeiServicesTablePointerLib\r
+ PeiServicesLib\r
+\r
+\r
+[Guids]\r
+ gRecoveryOnFatUsbDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED\r
+ gRecoveryOnFatIdeDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED\r
+ gRecoveryOnFatFloppyDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED\r
+\r
+\r
+[Ppis]\r
+ gEfiPeiVirtualBlockIoPpiGuid # PPI_NOTIFY SOMETIMES_CONSUMED\r
+ gEfiPeiVirtualBlockIo2PpiGuid # PPI_NOTIFY SOMETIMES_CONSUMED\r
+ gEfiPeiDeviceRecoveryModulePpiGuid # SOMETIMES_PRODUCED\r
+\r
+\r
+[FeaturePcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES\r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ FatPeiExtra.uni\r
--- /dev/null
+// /** @file\r
+// Lite Fat driver only used in Pei Phase.\r
+//\r
+// Lite Fat driver only used in Pei Phase.\r
+//\r
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials are licensed and made available\r
+// under the terms and conditions of the BSD License which accompanies this\r
+// distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT #language en-US "Lite Fat driver only used in Pei Phase."\r
+\r
+#string STR_MODULE_DESCRIPTION #language en-US "Lite Fat driver only used in Pei Phase."\r
+\r
--- /dev/null
+// /** @file\r
+// FatPei Localized Strings and Content\r
+//\r
+// Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials are licensed and made available\r
+// under the terms and conditions of the BSD License which accompanies this\r
+// distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME \r
+#language en-US \r
+"FAT File System Lite PEI Module"\r
+\r
+\r
--- /dev/null
+/** @file\r
+ Routines supporting partition discovery and \r
+ logical device reading\r
+\r
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Mbr.h>\r
+#include <IndustryStandard/ElTorito.h>\r
+#include "FatLitePeim.h"\r
+\r
+/**\r
+ This function finds Eltorito partitions. Main algorithm\r
+ is ported from DXE partition driver.\r
+\r
+ @param PrivateData The global memory map \r
+ @param ParentBlockDevNo The parent block device \r
+\r
+ @retval TRUE New partitions are detected and logical block devices \r
+ are added to block device array \r
+ @retval FALSE No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindEltoritoPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN ParentBlockDevNo\r
+ );\r
+\r
+/**\r
+ This function finds Mbr partitions. Main algorithm\r
+ is ported from DXE partition driver.\r
+\r
+ @param PrivateData The global memory map \r
+ @param ParentBlockDevNo The parent block device \r
+\r
+ @retval TRUE New partitions are detected and logical block devices \r
+ are added to block device array \r
+ @retval FALSE No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindMbrPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN ParentBlockDevNo\r
+ );\r
+\r
+\r
+/**\r
+ This function finds partitions (logical devices) in physical block devices.\r
+\r
+ @param PrivateData Global memory map for accessing global variables.\r
+\r
+**/\r
+VOID\r
+FatFindPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData\r
+ )\r
+{\r
+ BOOLEAN Found;\r
+ UINTN Index;\r
+\r
+ do {\r
+ Found = FALSE;\r
+\r
+ for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {\r
+ if (!PrivateData->BlockDevice[Index].PartitionChecked) {\r
+ Found = FatFindMbrPartitions (PrivateData, Index);\r
+ if (!Found) {\r
+ Found = FatFindEltoritoPartitions (PrivateData, Index);\r
+ }\r
+ }\r
+ }\r
+ } while (Found && PrivateData->BlockDeviceCount <= PEI_FAT_MAX_BLOCK_DEVICE);\r
+}\r
+\r
+\r
+/**\r
+ This function finds Eltorito partitions. Main algorithm\r
+ is ported from DXE partition driver.\r
+\r
+ @param PrivateData The global memory map \r
+ @param ParentBlockDevNo The parent block device \r
+\r
+ @retval TRUE New partitions are detected and logical block devices \r
+ are added to block device array \r
+ @retval FALSE No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindEltoritoPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN ParentBlockDevNo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN Found;\r
+ PEI_FAT_BLOCK_DEVICE *BlockDev;\r
+ PEI_FAT_BLOCK_DEVICE *ParentBlockDev;\r
+ UINT32 VolDescriptorLba;\r
+ UINT32 Lba;\r
+ CDROM_VOLUME_DESCRIPTOR *VolDescriptor;\r
+ ELTORITO_CATALOG *Catalog;\r
+ UINTN Check;\r
+ UINTN Index;\r
+ UINTN MaxIndex;\r
+ UINT16 *CheckBuffer;\r
+ UINT32 SubBlockSize;\r
+ UINT32 SectorCount;\r
+ UINT32 VolSpaceSize;\r
+\r
+ if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+ return FALSE;\r
+ }\r
+\r
+ Found = FALSE;\r
+ ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+ VolSpaceSize = 0;\r
+\r
+ //\r
+ // CD_ROM has the fixed block size as 2048 bytes\r
+ //\r
+ if (ParentBlockDev->BlockSize != 2048) {\r
+ return FALSE;\r
+ }\r
+\r
+ VolDescriptor = (CDROM_VOLUME_DESCRIPTOR *) PrivateData->BlockData;\r
+ Catalog = (ELTORITO_CATALOG *) VolDescriptor;\r
+\r
+ //\r
+ // the ISO-9660 volume descriptor starts at 32k on the media\r
+ // and CD_ROM has the fixed block size as 2048 bytes, so...\r
+ //\r
+ VolDescriptorLba = 15;\r
+ //\r
+ // ((16*2048) / Media->BlockSize) - 1;\r
+ //\r
+ // Loop: handle one volume descriptor per time\r
+ //\r
+ while (TRUE) {\r
+\r
+ VolDescriptorLba += 1;\r
+ if (VolDescriptorLba > ParentBlockDev->LastBlock) {\r
+ //\r
+ // We are pointing past the end of the device so exit\r
+ //\r
+ break;\r
+ }\r
+\r
+ Status = FatReadBlock (\r
+ PrivateData,\r
+ ParentBlockDevNo,\r
+ VolDescriptorLba,\r
+ ParentBlockDev->BlockSize,\r
+ VolDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ //\r
+ // Check for valid volume descriptor signature\r
+ //\r
+ if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||\r
+ CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0\r
+ ) {\r
+ //\r
+ // end of Volume descriptor list\r
+ //\r
+ break;\r
+ }\r
+ //\r
+ // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte\r
+ //\r
+ if (VolDescriptor->Unknown.Type == CDVOL_TYPE_CODED) {\r
+ VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[1];\r
+ }\r
+ //\r
+ // Is it an El Torito volume descriptor?\r
+ //\r
+ if (CompareMem (\r
+ VolDescriptor->BootRecordVolume.SystemId,\r
+ CDVOL_ELTORITO_ID,\r
+ sizeof (CDVOL_ELTORITO_ID) - 1\r
+ ) != 0) {\r
+ continue;\r
+ }\r
+ //\r
+ // Read in the boot El Torito boot catalog\r
+ //\r
+ Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);\r
+ if (Lba > ParentBlockDev->LastBlock) {\r
+ continue;\r
+ }\r
+\r
+ Status = FatReadBlock (\r
+ PrivateData,\r
+ ParentBlockDevNo,\r
+ Lba,\r
+ ParentBlockDev->BlockSize,\r
+ Catalog\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ //\r
+ // We don't care too much about the Catalog header's contents, but we do want\r
+ // to make sure it looks like a Catalog header\r
+ //\r
+ if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {\r
+ continue;\r
+ }\r
+\r
+ Check = 0;\r
+ CheckBuffer = (UINT16 *) Catalog;\r
+ for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {\r
+ Check += CheckBuffer[Index];\r
+ }\r
+\r
+ if ((Check & 0xFFFF) != 0) {\r
+ continue;\r
+ }\r
+\r
+ MaxIndex = ParentBlockDev->BlockSize / sizeof (ELTORITO_CATALOG);\r
+ for (Index = 1; Index < MaxIndex; Index += 1) {\r
+ //\r
+ // Next entry\r
+ //\r
+ Catalog += 1;\r
+\r
+ //\r
+ // Check this entry\r
+ //\r
+ if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {\r
+ continue;\r
+ }\r
+\r
+ SubBlockSize = 512;\r
+ SectorCount = Catalog->Boot.SectorCount;\r
+\r
+ switch (Catalog->Boot.MediaType) {\r
+\r
+ case ELTORITO_NO_EMULATION:\r
+ SubBlockSize = ParentBlockDev->BlockSize;\r
+ SectorCount = Catalog->Boot.SectorCount;\r
+ break;\r
+\r
+ case ELTORITO_HARD_DISK:\r
+ break;\r
+\r
+ case ELTORITO_12_DISKETTE:\r
+ SectorCount = 0x50 * 0x02 * 0x0F;\r
+ break;\r
+\r
+ case ELTORITO_14_DISKETTE:\r
+ SectorCount = 0x50 * 0x02 * 0x12;\r
+ break;\r
+\r
+ case ELTORITO_28_DISKETTE:\r
+ SectorCount = 0x50 * 0x02 * 0x24;\r
+ break;\r
+\r
+ default:\r
+ SectorCount = 0;\r
+ SubBlockSize = ParentBlockDev->BlockSize;\r
+ break;\r
+ }\r
+\r
+ if (SectorCount < 2) {\r
+ SectorCount = (VolSpaceSize > ParentBlockDev->LastBlock + 1) ? (UINT32) (ParentBlockDev->LastBlock - Catalog->Boot.Lba + 1) : (UINT32) (VolSpaceSize - Catalog->Boot.Lba);\r
+ }\r
+ //\r
+ // Register this partition\r
+ //\r
+ if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {\r
+\r
+ Found = TRUE;\r
+\r
+ BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);\r
+\r
+ BlockDev->BlockSize = SubBlockSize;\r
+ BlockDev->LastBlock = SectorCount - 1;\r
+ BlockDev->IoAlign = ParentBlockDev->IoAlign;\r
+ BlockDev->Logical = TRUE;\r
+ BlockDev->PartitionChecked = FALSE;\r
+ BlockDev->StartingPos = MultU64x32 (Catalog->Boot.Lba, ParentBlockDev->BlockSize);\r
+ BlockDev->ParentDevNo = ParentBlockDevNo;\r
+\r
+ PrivateData->BlockDeviceCount++;\r
+ }\r
+ }\r
+ }\r
+\r
+ ParentBlockDev->PartitionChecked = TRUE;\r
+\r
+ return Found;\r
+\r
+}\r
+\r
+\r
+/**\r
+ Test to see if the Mbr buffer is a valid MBR\r
+\r
+ @param Mbr Parent Handle \r
+ @param LastLba Last Lba address on the device. \r
+\r
+ @retval TRUE Mbr is a Valid MBR \r
+ @retval FALSE Mbr is not a Valid MBR\r
+\r
+**/\r
+BOOLEAN\r
+PartitionValidMbr (\r
+ IN MASTER_BOOT_RECORD *Mbr,\r
+ IN EFI_PEI_LBA LastLba\r
+ )\r
+{\r
+ UINT32 StartingLBA;\r
+ UINT32 EndingLBA;\r
+ UINT32 NewEndingLBA;\r
+ INTN Index1;\r
+ INTN Index2;\r
+ BOOLEAN MbrValid;\r
+\r
+ if (Mbr->Signature != MBR_SIGNATURE) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // The BPB also has this signature, so it can not be used alone.\r
+ //\r
+ MbrValid = FALSE;\r
+ for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {\r
+ if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {\r
+ continue;\r
+ }\r
+\r
+ MbrValid = TRUE;\r
+ StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);\r
+ EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;\r
+ if (EndingLBA > LastLba) {\r
+ //\r
+ // Compatability Errata:\r
+ // Some systems try to hide drive space with thier INT 13h driver\r
+ // This does not hide space from the OS driver. This means the MBR\r
+ // that gets created from DOS is smaller than the MBR created from\r
+ // a real OS (NT & Win98). This leads to BlockIo->LastBlock being\r
+ // wrong on some systems FDISKed by the OS.\r
+ //\r
+ // return FALSE Because no block devices on a system are implemented\r
+ // with INT 13h\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {\r
+ if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {\r
+ continue;\r
+ }\r
+\r
+ NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;\r
+ if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {\r
+ //\r
+ // This region overlaps with the Index1'th region\r
+ //\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Non of the regions overlapped so MBR is O.K.\r
+ //\r
+ return MbrValid;\r
+}\r
+\r
+\r
+/**\r
+ This function finds Mbr partitions. Main algorithm\r
+ is ported from DXE partition driver.\r
+\r
+ @param PrivateData The global memory map \r
+ @param ParentBlockDevNo The parent block device \r
+\r
+ @retval TRUE New partitions are detected and logical block devices \r
+ are added to block device array \r
+ @retval FALSE No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindMbrPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN ParentBlockDevNo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MASTER_BOOT_RECORD *Mbr;\r
+ UINTN Index;\r
+ BOOLEAN Found;\r
+ PEI_FAT_BLOCK_DEVICE *ParentBlockDev;\r
+ PEI_FAT_BLOCK_DEVICE *BlockDev;\r
+\r
+ if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+ return FALSE;\r
+ }\r
+\r
+ ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+\r
+ Found = FALSE;\r
+ Mbr = (MASTER_BOOT_RECORD *) PrivateData->BlockData;\r
+\r
+ Status = FatReadBlock (\r
+ PrivateData,\r
+ ParentBlockDevNo,\r
+ 0,\r
+ ParentBlockDev->BlockSize,\r
+ Mbr\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, ParentBlockDev->LastBlock)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // We have a valid mbr - add each partition\r
+ //\r
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {\r
+ if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) == 0) {\r
+ //\r
+ // Don't use null MBR entries\r
+ //\r
+ continue;\r
+ }\r
+ //\r
+ // Register this partition\r
+ //\r
+ if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {\r
+\r
+ Found = TRUE;\r
+\r
+ BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);\r
+\r
+ BlockDev->BlockSize = MBR_SIZE;\r
+ BlockDev->LastBlock = UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) - 1;\r
+ BlockDev->IoAlign = ParentBlockDev->IoAlign;\r
+ BlockDev->Logical = TRUE;\r
+ BlockDev->PartitionChecked = FALSE;\r
+ BlockDev->StartingPos = MultU64x32 (\r
+ UNPACK_INT32 (Mbr->Partition[Index].StartingLBA),\r
+ ParentBlockDev->BlockSize\r
+ );\r
+ BlockDev->ParentDevNo = ParentBlockDevNo;\r
+\r
+ PrivateData->BlockDeviceCount++;\r
+ }\r
+ }\r
+\r
+Done:\r
+\r
+ ParentBlockDev->PartitionChecked = TRUE;\r
+ return Found;\r
+}\r
--- /dev/null
+## @file\r
+#\r
+# FAT Package\r
+#\r
+# FAT 32 Driver\r
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are licensed and made available\r
+# under the terms and conditions of the BSD License which accompanies this\r
+# distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ DEC_SPECIFICATION = 0x00010005\r
+ PACKAGE_NAME = FatPkg\r
+ PACKAGE_UNI_FILE = FatPkg.uni\r
+ PACKAGE_GUID = 8EA68A2C-99CB-4332-85C6-DD5864EAA674\r
+ PACKAGE_VERSION = 0.3\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+ FatPkgExtra.uni\r
--- /dev/null
+## @file\r
+#\r
+# Build Binary Enhanced Fat Driver Modules\r
+#\r
+# This Platform file is used to generate the Binary Fat Drivers\r
+# for EDK II Prime release.\r
+# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are licensed and made available\r
+# under the terms and conditions of the BSD License which accompanies this\r
+# distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ PLATFORM_NAME = Fat\r
+ PLATFORM_GUID = 25b55dbc-9d0b-4a32-80da-46e1273d622c\r
+ PLATFORM_VERSION = 0.3\r
+ DSC_SPECIFICATION = 0x00010005\r
+ SUPPORTED_ARCHITECTURES = IA32|X64|IPF|EBC|ARM|AARCH64\r
+ OUTPUT_DIRECTORY = Build/Fat\r
+ BUILD_TARGETS = DEBUG|RELEASE|NOOPT\r
+ SKUID_IDENTIFIER = DEFAULT\r
+\r
+[BuildOptions]\r
+ GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG\r
+ INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG\r
+ MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG\r
+ RVCT:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG\r
+\r
+[LibraryClasses]\r
+ #\r
+ # Entry Point Libraries\r
+ #\r
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf\r
+ #\r
+ # Common Libraries\r
+ #\r
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf\r
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf\r
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf\r
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf\r
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf\r
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf\r
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf\r
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf\r
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf\r
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf \r
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf\r
+\r
+[LibraryClasses.common.PEIM]\r
+ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf\r
+ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf\r
+ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf\r
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf\r
+\r
+[LibraryClasses.ARM, LibraryClasses.AARCH64]\r
+ NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf\r
+ NULL|MdePkg/Library/BaseStackCheckLib/BaseStackCheckLib.inf\r
+\r
+###################################################################################################\r
+#\r
+# Components Section - list of the modules and components that will be processed by compilation\r
+# tools and the EDK II tools to generate PE32/PE32+/Coff image files.\r
+#\r
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed\r
+# into firmware volume images. This section is just a list of modules to compile from\r
+# source into UEFI-compliant binaries.\r
+# It is the FDF file that contains information on combining binary files into firmware\r
+# volume images, whose concept is beyond UEFI and is described in PI specification.\r
+# Binary modules do not need to be listed in this section, as they should be\r
+# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),\r
+# Logo (Logo.bmp), and etc.\r
+# There may also be modules listed in this section that are not required in the FDF file,\r
+# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be\r
+# generated for it, but the binary will not be put into any firmware volume.\r
+#\r
+###################################################################################################\r
+\r
+[Components]\r
+ FatPkg/FatPei/FatPei.inf\r
+ FatPkg/EnhancedFatDxe/Fat.inf\r
--- /dev/null
+// /** @file\r
+// Module implementations for FAT file system, FAT 32 UEFI Driver and FAT PEI Module\r
+//\r
+// FAT Package\r
+// \r
+// FAT 32 Driver\r
+//\r
+// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials are licensed and made available\r
+// under the terms and conditions of the BSD License which accompanies this\r
+// distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_PACKAGE_ABSTRACT #language en-US "Module implementations for FAT file system, FAT 32 UEFI Driver and FAT PEI Module"\r
+\r
+#string STR_PACKAGE_DESCRIPTION #language en-US "This Package contains module implementation about FAT file system, FAT 32 UEFI Driver and FAT PEI Module."\r
+\r
+\r
+\r
--- /dev/null
+// /** @file\r
+// Fat Package Localized Strings and Content.\r
+//\r
+// Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials are licensed and made available\r
+// under the terms and conditions of the BSD License which accompanies this\r
+// distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_PACKAGE_NAME \r
+#language en-US \r
+"Fat package"\r
+\r
+\r
--- /dev/null
+Copyright (c) 2006, Intel Corporation. All rights reserved.\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r