summaryrefslogtreecommitdiff
path: root/Core/EM/FileSystem
diff options
context:
space:
mode:
authorraywu <raywu0301@gmail.com>2018-06-15 00:00:50 +0800
committerraywu <raywu0301@gmail.com>2018-06-15 00:00:50 +0800
commitb7c51c9cf4864df6aabb99a1ae843becd577237c (patch)
treeeebe9b0d0ca03062955223097e57da84dd618b9a /Core/EM/FileSystem
downloadzprj-b7c51c9cf4864df6aabb99a1ae843becd577237c.tar.xz
init. 1AQQW051HEADmaster
Diffstat (limited to 'Core/EM/FileSystem')
-rw-r--r--Core/EM/FileSystem/DirectoryHandler.c454
-rw-r--r--Core/EM/FileSystem/FileFatHandler.c898
-rw-r--r--Core/EM/FileSystem/FileSYstem.mak75
-rw-r--r--Core/EM/FileSystem/FileSystem.c948
-rw-r--r--Core/EM/FileSystem/FileSystem.chmbin0 -> 118223 bytes
-rw-r--r--Core/EM/FileSystem/FileSystem.cif19
-rw-r--r--Core/EM/FileSystem/FileSystem.h1480
-rw-r--r--Core/EM/FileSystem/FileSystem.sdl49
-rw-r--r--Core/EM/FileSystem/FileSystemComponentName.c271
-rw-r--r--Core/EM/FileSystem/Info.c1313
-rw-r--r--Core/EM/FileSystem/MediaAccess.c1479
-rw-r--r--Core/EM/FileSystem/Open.c2601
-rw-r--r--Core/EM/FileSystem/VolFatHandler.c1419
13 files changed, 11006 insertions, 0 deletions
diff --git a/Core/EM/FileSystem/DirectoryHandler.c b/Core/EM/FileSystem/DirectoryHandler.c
new file mode 100644
index 0000000..9acd1d2
--- /dev/null
+++ b/Core/EM/FileSystem/DirectoryHandler.c
@@ -0,0 +1,454 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Core/Modules/FileSystem/DirectoryHandler.c 6 7/07/10 2:54p Pats $
+//
+// $Revision: 6 $
+//
+// $Date: 7/07/10 2:54p $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Core/Modules/FileSystem/DirectoryHandler.c $
+//
+// 6 7/07/10 2:54p Pats
+// EIP 38291: Fails Klocwork test.
+// Problem: No error return if short name is null in GenUniqueShortName()
+// Solution: Added error return.
+//
+// 5 7/02/09 5:47p Pats
+// Updated to latest coding standard. No code changes.
+//
+// 4 4/13/07 7:07p Pats
+// Edited to conform with coding standards. No code changes.
+//
+// 3 11/03/05 2:16p Srinin
+// Fixed VC7.1 warning msg.
+//
+// 2 9/08/05 4:41p Pats
+// Fixed problem of short filename having exactly 8 characters in mame and
+// 3 in ext being handled as long file name (and ~ name generated).
+//
+// 1 4/26/05 6:05p Srinin
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: DirectoryHandler.c
+//
+// Description: Fat File System driver -- Directory Functions
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+//----------------------------------------------------------------------
+
+#include "FileSystem.h"
+
+//----------------------------------------------------------------------
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetNameComponent
+//
+// Description: Gets the name component from a path
+//
+// Parameters: CHAR16 *Path - Pointer to input path
+// CHAR16 *Name - Pointer to output name
+//
+// Return value: CHAR16 * path truncated to name
+//
+// Modified: None
+//
+// Referral(s): None
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+CHAR16 *
+GetNameComponent (
+ IN CHAR16 *Path,
+ OUT CHAR16 *Name
+)
+{
+ UINTN Len = 0;
+
+ while (*Path && *Path != '\\') {
+ if (Len < 259) {
+ Name[Len] = *Path;
+ Len += 1;
+ }
+
+ Path += 1;
+ }
+
+ Name[Len] = 0;
+
+// Remove trailing '\'
+ while (*Path == '\\') {
+ Path += 1;
+ }
+
+ return Path;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GenShortFilename
+//
+// Description: Generates a DOS 8.3 name component from a path
+//
+// Parameters: VOLUME_INFO *Vol - Pointer to volume information structure
+// CHAR16 *InPath - Pointer to input path
+// CHAR8 *ShortName - Pointer to generated DOS 8.3 name
+//
+// Return value: EFI_STATUS - Status of operation (EFI_SUCCESS)
+//
+// Modified: None
+//
+// Referral(s): None
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GenShortFilename (
+ IN VOLUME_INFO *Vol,
+ IN CHAR16 *InPath,
+ OUT CHAR8 *ShortName
+)
+{
+ CHAR16 *Ext;
+ CHAR16 *p;
+ CHAR16 CharC;
+
+ MemSet(ShortName, 11, 0x20); // Fill short name with spaces
+
+ // If this is a '.' or '..' name then it's a special form
+ if (InPath[0] == '.' && InPath[1] == 0) {
+ ShortName[0] = '.';
+ goto Done;
+ }
+
+ if (InPath[0] == '.' && InPath[1] == '.' && InPath[2] == 0) {
+ ShortName[0] = '.';
+ ShortName[1] = '.';
+ goto Done;
+ }
+
+// Find the last '.'
+ Ext = NULL;
+
+ for (p = InPath; *p; p++) {
+ if (*p == '.') {
+ Ext = p;
+ }
+ }
+
+ if (!Ext) {
+ Ext = p;
+ }
+
+ // Create 8.3 name. Convert chars to fat values. Skip any '.' or ' '.
+ CharC = *Ext; // Save first char of ext.
+ *Ext = 0; // Zero-terminate name
+ Vol->UnicodeCollationInterface->StrToFat (Vol->UnicodeCollationInterface,
+ InPath,
+ 8,
+ ShortName);
+ *Ext = CharC; // Restore first char of ext.
+ Vol->UnicodeCollationInterface->StrToFat (Vol->UnicodeCollationInterface,
+ Ext,
+ 3,
+ ShortName+8);
+
+Done:
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GenUniqueShortFname
+//
+// Description: Generates a unique DOS 8.3 name from a possible long name
+//
+// Parameters: FILE_HANDLE *fh - Pointer to the file handle structure
+// CHAR16 *LongName - Pointer to the possible long name
+// CHAR8 *ShortName - Pointer to generated DOS 8.3 name
+// BOOLEAN *LfnNeeded - Indicates a long name entry is
+// needed for this input name
+//
+// Return value: EFI_STATUS - EFI_SUCCESS - Unique name generated
+// EFI_ACCESS_DENIED - this name already exists
+// on the volume
+//
+// Modified: None
+//
+// Referral(s): None
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GenUniqueShortFname (
+ IN FILE_HANDLE *fh,
+ IN CHAR16 *LongName,
+ OUT CHAR8 *ShortName,
+ OUT BOOLEAN *LfnNeeded
+)
+{
+
+ EFI_STATUS Status;
+ VOLUME_INFO *Vol = fh->VolumeInterface;
+ DIR_ENTRY_LIST *Del;
+ CHAR8 Temp[12];
+ CHAR16 Temp2[13];
+ CHAR16 Temp3[13];
+ CHAR8 CounterString[6];
+ UINTN Counter, CounterStringLen;
+ UINTN k;
+ CHAR8 *s;
+
+ Status = GenShortFilename(Vol, LongName, ShortName);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ // Check for dot or dotdot entries
+ if ((LongName[0] == '.' && LongName[1] == 0) ||
+ (LongName[0] == '.' && LongName[1] == '.' && LongName[2] == 0)) {
+ *LfnNeeded = FALSE;
+ return EFI_SUCCESS;
+ }
+
+ if (!fh->DirList.pHead) {
+ ReadAllDirectoryEntries (fh);
+ }
+
+ // Find out if the input name is already a valid short name -- i.e., no
+ // ~Counter is needed.
+ k = Wcslen(LongName) * sizeof(CHAR16) + 2; // Include Null character
+
+ if (k <= 26) { // If it could be a legal short name...
+ // (13 * 2 including '.' + 2 for NULL)
+ ExtractShortFileName(Vol, Temp2, ShortName);
+ pBS->CopyMem(Temp3, LongName, k);
+ // Make an upper case copy of the input
+ Vol->UnicodeCollationInterface->StrUpr(Vol->UnicodeCollationInterface, Temp3);
+
+ if ( !Wcscmp(Temp2, Temp3 )) {
+ // If the extracted name is same as upper case copy of input...
+ // If the extracted name doesn't equal the non-upper case original,
+ // it must have some lower case letters in it,
+ // so therefore a long name entry is needed.
+ if (!Wcscmp(Temp2, LongName)) *LfnNeeded = FALSE;
+
+ else *LfnNeeded = TRUE;
+
+ if (FindMatchingDirEntry (fh, LongName, &Del)) {
+ return EFI_ACCESS_DENIED; // Name already exists, can't create
+
+ } else {
+ return EFI_SUCCESS; // Name is ok, return
+ }
+ }
+ }
+
+ // Now append "~Counter" to the short name, incrementing "Counter"
+ // until the file name is unique in that Path
+ Zeromemory (CounterString, sizeof(CounterString));
+
+ for (Counter = 1; Counter < 65536; Counter++) {
+ pBS->CopyMem(Temp, ShortName, 11);
+ if (Temp[0] == ' ') return EFI_INVALID_PARAMETER;
+ ItoaEx(Counter, CounterString, 10, FALSE);
+ CounterStringLen = Strlen(CounterString);
+
+ // Right-justify the "~Counter"
+ for (k = 0; k < 7 - CounterStringLen; k += 1) {
+ if (Temp[k] == ' ') {
+ k--; // In case the name is short
+ break;
+ }
+ }
+
+ // Append the "~Counter" to the name
+ Temp[k++] = '~';
+
+ for (s = CounterString; *s; Temp[k++] = *s++) ;
+
+ // Search for the generated name
+ Temp[11] = 0;
+
+ if (!FindMatchingSFNDirEntry (fh, Temp, &Del)) {
+ pBS->CopyMem(ShortName, Temp, 11);
+ *LfnNeeded = TRUE;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_ACCESS_DENIED;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: CopyCharsToLfnSlot
+//
+// Description: Copies a character to the appropriate slot of a long name
+// directory structure
+//
+// Parameters: DIR_ENTRY_LFN *Slot - Pointer to long name directory
+// structure
+// UINT32 *SlotPos - Pointer to slot position to fill
+// UINT16 Ch - The character to be placed in the slot
+//
+// Return value: None
+//
+// Modified: None
+//
+// Referral(s): None
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+static VOID
+CopyCharsToLfnSlot (
+ DIR_ENTRY_LFN *Slot,
+ UINT32 SlotPos,
+ UINT16 Ch
+)
+{
+ if ((SlotPos >= 0) && (SlotPos <= 4)) Slot->Dir_Name0_4[SlotPos] = Ch;
+
+ else if ((SlotPos >= 5) && (SlotPos <= 10)) Slot->Dir_Name5_10 [SlotPos-5] = Ch;
+
+ else if ((SlotPos >= 11) && (SlotPos <= 12)) Slot->Dir_Name11_12[SlotPos-11] = Ch;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SplitLFN
+//
+// Description: Splits a long file name into long name directory enties.
+//
+// Parameters: CHAR16 *LongName - Pointer to a long file name
+// DIR_ENTRY_32 *ShortEntry - Pointer to the corresponding
+// short directory entry
+// DIR_ENTRY_LFN *Slot - The structure of the long directory
+// entries to be filled
+//
+// Return value: EFI_STATUS - Status of the operation (EFI_SUCCESS)
+//
+// Modified: None
+//
+// Referral(s): None
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SplitLFN (
+ IN CHAR16 *LongName,
+ IN DIR_ENTRY_32 *ShortEntry,
+ OUT DIR_ENTRY_LFN *Slot,
+ OUT UINT32 *NumSlots
+)
+{
+ UINT32 NamePos;
+ UINT32 SlotPos;
+ UINT8 Order;
+ UINT8 Checksum = LfnChecksum((UINT8 *)ShortEntry);
+ UINT32 CharCnt;
+ UINT32 Position;
+ INTN i;
+
+ CharCnt = (UINT32) Wcslen(LongName);
+ *NumSlots = CharCnt / 13;
+
+ if (CharCnt % 13) *NumSlots += 1; // Name not evenly divisible by 13
+
+ Order = *NumSlots;
+ Position = 13 * (Order - 1); // Starting position for extracting characters.
+
+ for (i=0; Order; i++, Order--) {
+ // Fill in the non-name stuff
+ Slot[i].Dir_Order = Order; // 1-based numeration
+ Slot[i].Dir_Attr = (ATTR_LONG_NAME);
+ Slot[i].Dir_Reserved = 0;
+ Slot[i].Dir_Checksum = Checksum;
+ Slot[i].Dir_FstClus = 0;
+ Slot[i].Dir_FstClus = 0;
+ // Fill in the name
+ NamePos = Position;
+ SlotPos = 0;
+
+ while (LongName[NamePos] && SlotPos < 13) {
+ CopyCharsToLfnSlot(&Slot[i], SlotPos++, LongName[NamePos]);
+
+ if (++NamePos == MAX_LFN_LENGTH) return EFI_INVALID_PARAMETER;
+ }
+
+ if (i == 0) { // If last slot
+ // Mark the slot as last
+ Slot[i].Dir_Order |= 0x40;
+ // Insert a Unicode NULL terminator, only if it fits into the slots
+ CopyCharsToLfnSlot(&Slot[i], SlotPos++, 0x0000);
+
+ // Pad the remaining characters of the slot with FFFFh
+ while (SlotPos < 13) CopyCharsToLfnSlot(&Slot[i], SlotPos++, 0xFFFF);
+ }
+
+ Position -= 13; // Back up to next section to process
+ }
+
+ return EFI_SUCCESS;
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
diff --git a/Core/EM/FileSystem/FileFatHandler.c b/Core/EM/FileSystem/FileFatHandler.c
new file mode 100644
index 0000000..1447f62
--- /dev/null
+++ b/Core/EM/FileSystem/FileFatHandler.c
@@ -0,0 +1,898 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/FileSystem/FileFatHandler.c 1 10/25/12 8:53a Wesleychen $
+//
+// $Revision: 1 $
+//
+// $Date: 10/25/12 8:53a $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/FileSystem/FileFatHandler.c $
+//
+// 1 10/25/12 8:53a Wesleychen
+// Update it for EIP#104620.
+//
+// 7 10/05/12 5:50p Pats
+// [TAG] EIP99324
+// [Category] Bug Fix
+// [Symptom] Image files used in GUI Version of AMIDiag getting renamed
+// [RootCause] If the long name component of a directory was in a separate
+// cluster from the short name component, it was being over-written.
+// [Solution] Added new function FindLongNamePiece() to FileFatHandler.c.
+// It is called from GetSpaceforDirEntry().
+// [Files] FileFatHandler.c
+//
+// 6 6/11/10 5:40p Pats
+// EIP 39171: Long name sometimes not displayed, only short name.
+// FetchLongName() in Open.c did not handle case where long name spilt
+// over 2 clusters. Function modified to handle the case.
+// Call to FetchLongName() changed here because parameters changed.
+//
+// 5 7/02/09 5:47p Pats
+// Updated to latest coding standard. No code changes.
+//
+// 4 4/13/07 7:07p Pats
+// Edited to conform with coding standards. No code changes.
+//
+// 3 6/21/05 4:00p Pats
+// Modified to call MarkVolumeDirty when EFI_VOLUME_CORRUPTED error
+// occurs. Removed commented-out debug code.
+//
+// 2 6/16/05 4:14p Pats
+// Modified to return error if reading file with premature EOF in fat
+// chain.
+//
+// 1 4/26/05 6:05p Srinin
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: FileFatHndlr.c
+//
+// Description: Fat File System driver -- File Level Fat Handler
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+#include "FileSystem.h"
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: LocateFreeDirEntry
+//
+// Description: Locates a free entry in a directory
+//
+// Parameters: FILE_HANDLE *fh - Handle of file requireing entry
+// UINT32 FreeBytesRequired - No. of bytes required for
+// the new entry
+// UINT32 *FreeDirCluster - Returned Cluster of free entry
+// UINT32 *FreeDirClusterOffset - Offset of free entry
+//
+// Returned value: EFI_STATUS - Status of the operation
+//
+// Modified: None
+//
+// Referral(s): None
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+LocateFreeDirEntry(
+ IN FILE_HANDLE *fh,
+ IN UINT32 FreeBytesRequired,
+ OUT UINT32 *FreeDirCluster,
+ OUT UINT32 *FreeDirClusterOffset,
+ OUT BOOLEAN *LastDirEntry
+)
+{
+
+ EFI_STATUS Status;
+ VOLUME_INFO *Vi = fh->VolumeInterface;
+
+ // If free Dir Entry not found earlier, use the long method
+ if (fh->FreeDirEntryCluster == 0 && fh->FreeDirEntryOffset == 0)
+ return GetSpaceforDirEntry(fh, FreeBytesRequired, FreeDirCluster, FreeDirClusterOffset, LastDirEntry);
+
+ // Use the existing data to speed up the search
+ Status = CheckforValidDirSpace (Vi, fh->ROOTDIR, fh->FreeDirEntryCluster, fh->FreeDirEntryOffset,
+ FreeBytesRequired, FreeDirCluster, FreeDirClusterOffset);
+
+ if (Status == EFI_SUCCESS) *LastDirEntry = TRUE;
+
+ // Above Routine failed. For FAT12/16, limited ROOT directory entries are
+ // available. So go through the entire list.
+ if (EFI_ERROR(Status) && fh->ROOTDIR && (Vi->FatType != FAT32))
+ return GetSpaceforDirEntry(fh, FreeBytesRequired, FreeDirCluster, FreeDirClusterOffset, LastDirEntry);
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FindLongNamePiece
+//
+// Description: Returns TRUE if there is a valid long name part of a
+// directory entry at Offset position in Buffer.
+//
+// Parameters:
+// UINT8 *Buffer - Buffer to search in
+// UINT32 *Offset - Offset in buffer where entry found
+//
+// Return Value:
+// BOOLEAN - True = Long name piece found
+//
+// Modified:
+//
+// Referrals: GetSpaceforDirEntry
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+BOOLEAN
+FindLongNamePiece (
+ UINT8 *Buffer,
+ UINT32 *Offset
+)
+{
+ DIR_ENTRY_32 *Entry = (DIR_ENTRY_32 *)(Buffer + *Offset);
+
+ if ((Entry->Dir_Name[0] == 0) || (Entry->Dir_Name[0] == 0xE5)) {
+ return FALSE; // not an existing entry.
+ }
+
+ if ( ((Entry->Dir_Attr & ATTR_LONG_NAME_MASK) == (ATTR_LONG_NAME)) &&
+ ((Entry->Dir_Name[0] >> 4) == 0) ||
+ ((Entry->Dir_Name[0] >> 4) >= 4) ) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetSpaceforDirEntry
+//
+// Description: Enlarges directory to make space for a new entry
+//
+// Parameters: FILE_HANDLE *fh - Handle of file requireing entry
+// UINT32 FreeBytesRequired - No. of bytes required for
+// the new entry
+// UINT32 *FreeDirCluster - Returned Cluster of free entry
+// UINT32 *FreeDirClusterOffset - Offset of free entry
+// BOOLEAN *LastDirEntry - True if new entry is the last one
+// in the directory
+//
+// Return Value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referrals:
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetSpaceforDirEntry(
+ IN FILE_HANDLE *fh,
+ IN UINT32 FreeBytesRequired,
+ OUT UINT32 *FreeDirCluster,
+ OUT UINT32 *FreeDirClusterOffset,
+ BOOLEAN *LastDirEntry
+)
+{
+
+ EFI_STATUS Status;
+ UINT32 Offset, BufferSize, OrgBufferSize;
+ UINT32 BytesReadPerLoop;
+ UINT8 *Buffer;
+ VOLUME_INFO *Vi = fh->VolumeInterface;
+ UINT32 ClusterNumber, Cluster, LastValidCluster;
+ UINT32 CurrentOffset, Slots;
+ UINT16 lfn[256];
+
+
+ // Allocate space for a temp buffer.
+ BytesReadPerLoop = Vi->BytesPerCluster;
+
+ if (fh->ROOTDIR && (Vi->FatType != FAT32))
+ BytesReadPerLoop = Vi->RootDirSectorCount << Vi->BytesPerSecPowerof2;
+
+
+ GetTempBuffer (Vi, &Buffer);
+//###DEBUG
+// Status = fsAllocateMemory (Vi, BytesReadPerLoop, &Buffer, FALSE);
+// Status = fsAllocateMemory (Vi, 256, (VOID**)&lfn, FALSE);
+// if(EFI_ERROR(Status)) return EFI_NOT_FOUND;
+//###DEBUG END
+ LastValidCluster = FIRSTCLUSTER(fh->DirectoryEntry);
+
+ for (ClusterNumber = 0; ClusterNumber < Vi->CountOfDataClusters ; ClusterNumber++) {
+ Cluster = 0;
+ Status = ReadClusterOfDirectoryEntries(fh, ClusterNumber, &Cluster, Buffer, &BytesReadPerLoop);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (Status == EFI_SUCCESS && BytesReadPerLoop == 0) {
+
+ if (fh->ROOTDIR && (Vi->FatType != FAT32)) return EFI_ACCESS_DENIED; // Dir. entry cannot be created
+
+//###DEBUG
+ /*
+ #ifdef Debug_AllocateClusters
+ EfiDebugPrint(-1,"DirName %s Clusters ", fh->FileNameLFN);
+ #endif
+ Status = AllocateAndLinkClusters (Vi, LastValidCluster, Vi->BytesPerCluster, &Cluster, &ClusterCount);
+ #ifdef Debug_AllocateClusters
+ EfiDebugPrint(-1,"\n");
+ #endif
+ *FreeDirClusterOffset = 0;
+ *FreeDirCluster = Cluster;
+
+ // Zero out the New cluster allocated.
+ Status = ZeroOutdisk(Vi, Cluster, *FreeDirClusterOffset, Vi->BytesPerCluster);
+ */
+//###DEBUG END
+ Status = CheckforValidDirSpace (Vi, fh->ROOTDIR, LastValidCluster, Vi->BytesPerCluster,
+ FreeBytesRequired, FreeDirCluster, FreeDirClusterOffset);
+ *LastDirEntry = TRUE;
+ break;
+ }
+
+ LastValidCluster = Cluster;
+ OrgBufferSize = BytesReadPerLoop;
+ BufferSize = BytesReadPerLoop;
+ CurrentOffset = Offset = 0;
+ *FreeDirCluster = Cluster;
+ Status = EFI_NOT_FOUND;
+
+ for ( ; CurrentOffset < OrgBufferSize; Offset = CurrentOffset, BufferSize = OrgBufferSize - CurrentOffset) {
+
+ if (Buffer[Offset] == 0) {
+ Status = CheckforValidDirSpace (Vi, fh->ROOTDIR, Cluster, Offset,
+ FreeBytesRequired, FreeDirCluster, FreeDirClusterOffset);
+ *LastDirEntry = TRUE;
+ break;
+ }
+
+
+ if (FindShortName (Buffer, &Offset, BufferSize)) {
+ Slots = FetchLongName(fh, (DIR_ENTRY_32 *)(Buffer), Offset, lfn, ClusterNumber, BytesReadPerLoop);
+
+ if (Offset && ((Offset - Slots * sizeof(DIR_ENTRY_32) - CurrentOffset) >= FreeBytesRequired)) {
+ *FreeDirClusterOffset = CurrentOffset;
+ *LastDirEntry = FALSE;
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ CurrentOffset = Offset + sizeof(DIR_ENTRY_32);
+ continue;
+
+ } else {
+
+ if (BufferSize > 0) {
+ while (FindLongNamePiece (Buffer, &CurrentOffset)) {
+ CurrentOffset += sizeof(DIR_ENTRY_32);
+ BufferSize -= sizeof(DIR_ENTRY_32);
+ if (BufferSize == 0) break;
+ }
+ }
+
+ if (BufferSize >= FreeBytesRequired) {
+ *FreeDirClusterOffset = CurrentOffset;
+ *LastDirEntry = FALSE;
+ Status = EFI_SUCCESS;
+ }
+
+ break;
+ }
+ }
+
+ if (Status == EFI_SUCCESS) break;
+
+ }
+
+//###DEBUG
+// fsDeAllocateMemory (Vi, Buffer);
+// fsDeAllocateMemory (Vi, lfn);
+//###DEBUG END
+ ReleaseTempBuffer (Vi);
+ return Status;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: CheckforValidDirSpace
+//
+// Description: Cluster and Offset should point after the last valid directory entry.
+//
+// Parameters:
+// IN VOLUME_INFO *Vi - Volume info structure
+// IN BOOLEAN ROOTDIR - true if root directory
+// IN UINT32 Cluster - Starting cluster
+// IN UINT32 Offset - Offset in cluster
+// IN UINT32 FreeBytesRequired
+// IN UINT32 *FreeDirCluster
+// IN UINT32 *FreeDirClusterOffset
+//
+// Return Value: EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: No Directory Entry Will be created which crosses CLUSTER BOUNDRY
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+CheckforValidDirSpace (
+ IN VOLUME_INFO *Vi,
+ IN BOOLEAN ROOTDIR,
+ IN UINT32 Cluster,
+ IN UINT32 Offset,
+ IN UINT32 FreeBytesRequired,
+ IN UINT32 *FreeDirCluster,
+ IN UINT32 *FreeDirClusterOffset
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT32 ByteToCompare = Vi->BytesPerCluster;
+ UINT32 Sector, SectorOffset, ClusterCount;
+ UINT8 BData;
+
+
+ if (ROOTDIR && (Vi->FatType != FAT32)) ByteToCompare = Vi->RootDirSectorCount << Vi->BytesPerSecPowerof2;
+
+ if (ByteToCompare - Offset >= FreeBytesRequired) {
+// Free Entry Found with in the cluster
+ *FreeDirCluster = Cluster;
+ *FreeDirClusterOffset = Offset;
+ return Status;
+ }
+
+// For ROOT and FAT12/16, new clusters cannot be added.
+ if (ROOTDIR && (Vi->FatType != FAT32)) return EFI_ACCESS_DENIED;
+
+// From Cluster/offset to end of Cluster make sure there are no '0' in the first Byte Position of the directory Entry.
+ for ( ; ByteToCompare - Offset; ) {
+ GetAbsSectorInfo(Vi, Cluster, Offset, &Sector, &SectorOffset);
+ Status = FsReadMedia (Vi, &BData, Sector, SectorOffset, 1, DIRECTORY_REGION);
+
+ if (BData == 0) {
+ BData = DIR_ENTRY_ERASE;
+ Status = FsWriteMedia (Vi, &BData, Sector, SectorOffset, 1, DIRECTORY_REGION);
+ }
+
+ Offset += sizeof (DIR_ENTRY_32);
+ }
+
+#ifdef Debug_AllocateClusters
+ EfiDebugPrint(-1,"Dir Name Not found");
+#endif
+// Allocate a New Cluster
+// Status = AllocateAndLinkNewCluster (Vi, Cluster, FreeDirCluster);
+ Status = AllocateAndLinkClusters (Vi, Cluster, Vi->BytesPerCluster, FreeDirCluster, &ClusterCount);
+#ifdef Debug_AllocateClusters
+ EfiDebugPrint(-1,"\n");
+#endif
+ *FreeDirClusterOffset = 0;
+
+// Zero out the New cluster allocated.
+ Status = ZeroOutdisk(Vi, *FreeDirCluster, *FreeDirClusterOffset, Vi->BytesPerCluster);
+ return Status;
+
+}
+
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: ZeroOutdisk
+//
+// Description: Zeros out directory region of disk
+//
+// Parameters:
+// IN VOLUME_INFO *Vi - Volume info structure
+// IN UINT32 Cluster - Cluster in directory region to zero
+// IN UINT32 ClusterOffset - Offset in cluster
+// IN UINT32 Size - Size to zero
+//
+// Return value: EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+ZeroOutdisk (
+ IN VOLUME_INFO *Vi,
+ IN UINT32 Cluster,
+ IN UINT32 ClusterOffset,
+ IN UINT32 Size
+)
+{
+ UINT32 Sector, SectorOffset;
+ UINT8 *Buffer;
+ EFI_STATUS Status;
+
+// fsAllocateMemory (Vi, Size, (void **)&Buffer, TRUE);
+ GetTempBuffer (Vi, &Buffer);
+ Zeromemory (Buffer, Size);
+ GetAbsSectorInfo(Vi, Cluster, ClusterOffset, &Sector, &SectorOffset);
+ Status = FsWriteMedia (Vi, Buffer, Sector, SectorOffset, Size, DIRECTORY_REGION);
+// fsDeAllocateMemory(Vi, Buffer);
+ ReleaseTempBuffer (Vi);
+
+ if (EFI_ERROR(Status)) {
+ HandleDiskIoError (Vi, Status);
+ return Status;
+ }
+
+ return Status;
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: ExtendFile
+//
+// Description: Extends a file on the disk (it is written to)
+//
+// Parameters:
+// IN FILE_HANDLE_INSTANCE *fhi - File handle instance
+// IN UINT32 Length - Length to extend
+//
+// Return value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+ExtendFile (
+ IN FILE_HANDLE_INSTANCE *fhi,
+ IN UINT32 Length
+)
+{
+
+ UINT64 OrgPosition;
+ FILE_HANDLE *fh = fhi->pFH;
+ VOLUME_INFO *vi = fhi->pFH->VolumeInterface;
+ EFI_STATUS Status;
+ UINT32 FirstCluster, NewClusterCount, RemainingClusterLength = 0;
+
+#ifdef Debug_WriteFile
+ EfiDebugPrint(-1,"File to be Extended by Length %x \n", Length);
+#endif
+
+// Save the Current Position
+ OrgPosition = fhi->Position;
+
+// Set the Position to the End of the File
+ SetPositionFileHandle (fhi, -1);
+
+// Check if there is remaming space in the current cluster
+ if (fhi->CurrentCluster)
+ RemainingClusterLength = vi->BytesPerCluster - fhi->CurrentClusterOffset;
+
+ if (Length > RemainingClusterLength) {
+ Length = Length - RemainingClusterLength;
+#ifdef Debug_AllocateClusters
+ EfiDebugPrint(-1,"FileName %s Clusters ", fh->FileNameLFN);
+#endif
+ Status = AllocateAndLinkClusters(vi, fhi->CurrentCluster, Length, &FirstCluster, &NewClusterCount);
+#ifdef Debug_AllocateClusters
+ EfiDebugPrint(-1,"\n");
+#endif
+
+ if (EFI_ERROR(Status)) return Status;
+ }
+
+ if (fhi->CurrentCluster == 0 && fhi->CurrentClusterOffset == 0) {
+ fh->DirectoryEntry.Dir_FstClusLO = (UINT16) FirstCluster;
+ fh->DirectoryEntry.Dir_FstClusHI = FirstCluster >> 16;
+ }
+
+// Restore File Position
+ SetPositionFileHandle (fhi, OrgPosition);
+
+ fh->DirectoryEntry.Dir_Attr |= ATTR_ARCHIVE;
+ fh->DirEntryChanged = TRUE;
+ return EFI_SUCCESS;
+
+}
+
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: ReadWriteExistingBlock
+//
+// Description: Reads or writes an existing file. If writing, writes
+// only an existing block, with no new allocation.
+//
+// Parameters:
+// IN FILE_HANDLE_INSTANCE *File - File handle instance
+// IN OUT VOID *Buffer - Output biffer
+// IN OUT UINT32 *Size - Size written or read
+// IN REGIONS DataRegion - Region of disk used (dir, fat, normal)
+// IN ACCESS_METHOD Method - Method (read or write)
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+ReadWriteExistingBlock (
+ IN FILE_HANDLE_INSTANCE *File,
+ IN OUT VOID *Buffer,
+ IN OUT UINT32 *Size,
+ IN REGIONS DataRegion,
+ IN ACCESS_METHOD Method
+)
+{
+ EFI_STATUS Status;
+ VOLUME_INFO *Vol = File->pFH->VolumeInterface;
+ UINT32 TotalContigousBytes;
+ UINT32 TotalBytesRead = 0;
+ UINT32 NextCluster, ClusterCount, AbsSector, AbsSectorOffset, AccessBytes;
+ UINT32 Position = (UINT32) File->Position;
+
+ do {
+
+ Status = GetContiguousClusters(Vol, *Size + File->CurrentClusterOffset, File->CurrentCluster,
+ &NextCluster, &ClusterCount); // CurrentSector and CurrentSectorOffset
+
+ if (EFI_ERROR(Status)) break;
+
+ if (!ClusterCount) break;
+
+ TotalContigousBytes = (ClusterCount * (UINT32)Vol->VolumeBPB.BPB_SecPerClus) << Vol->BytesPerSecPowerof2;
+ TotalContigousBytes -= File->CurrentClusterOffset;
+
+ if ( TotalContigousBytes > *Size) AccessBytes = *Size;
+
+ else AccessBytes = TotalContigousBytes;
+
+ GetAbsSectorInfo (Vol, File->CurrentCluster, File->CurrentClusterOffset, &AbsSector, &AbsSectorOffset);
+
+ if ((Method == READ_BLOCK) && (AccessBytes == 0)) {
+ MarkVolumeDirty (Vol);
+ return EFI_VOLUME_CORRUPTED; // Will happen if early EOF.
+ }
+
+ if (Method == READ_BLOCK) {
+ Status = FsReadMedia (Vol,
+ Buffer,
+ AbsSector,
+ AbsSectorOffset,
+ AccessBytes,
+ DATA_REGION);
+
+ } else {
+ Status = FsWriteMedia (Vol,
+ Buffer,
+ AbsSector,
+ AbsSectorOffset,
+ AccessBytes,
+ DATA_REGION);
+ }
+
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+
+ (UINT8 *)Buffer += AccessBytes;
+ TotalBytesRead +=AccessBytes;
+ *Size -= AccessBytes;
+ Position += AccessBytes;
+ File->Position = Position;
+//###DEBUG
+//TODO TODO TODO TODO
+//Can call getpositionfilehandle to save some space.
+//TODO TODO TODO TODO
+//###DEBUG END
+ File->CurrentCluster += ((AccessBytes + File->CurrentClusterOffset) / Vol->BytesPerCluster);
+ File->CurrentClusterOffset = (AccessBytes + File->CurrentClusterOffset) % Vol->BytesPerCluster;
+
+ if (!File->CurrentClusterOffset) {
+ if (NextCluster >= Vol->EOCMark) {
+ File->CurrentCluster--;
+ File->CurrentClusterOffset = Vol->BytesPerCluster;
+
+ } else File->CurrentCluster = NextCluster;
+ }
+ } while (*Size);
+
+ *Size = TotalBytesRead;
+ return Status;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: ReadFromFile
+//
+// Description: Reads a specified number of bytes from a file into a
+// specified buffer, beginning at a specified position
+// in the file. Updates Size to number of bytes read.
+// Updates Position to position after data read.
+//
+// Parameters:
+// IN FILE_HANDLE_INSTANCE *File - File handle instance
+// IN OUT VOID *Buffer - Buffer to read into
+// IN OUT UINT32 *Size - Size to read (updated with size read)
+// IN REGIONS DataRegion - Region of disk (dir, fat, normal)
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+ReadFromFile (
+ IN FILE_HANDLE_INSTANCE *File,
+ IN OUT VOID *Buffer,
+ IN OUT UINT32 *Size,
+ IN REGIONS DataRegion
+)
+{
+ EFI_STATUS Status;
+ UINT32 Position = (UINT32) File->Position;
+ ACCESS_METHOD Method = READ_BLOCK;
+
+
+// If Position (Zero Based) beyond EOF?
+ if (Position >= File->pFH->DirectoryEntry.Dir_FileSize) {
+ *Size = 0;
+
+ if (Position == File->pFH->DirectoryEntry.Dir_FileSize)
+ return EFI_SUCCESS;
+
+ else
+ return EFI_DEVICE_ERROR;
+ }
+
+// If bytes to be read exceed the file size, truncate it.
+ if ((Position + *Size) > File->pFH->DirectoryEntry.Dir_FileSize) *Size = File->pFH->DirectoryEntry.Dir_FileSize - Position;
+
+ Status = ReadWriteExistingBlock (File,
+ Buffer,
+ Size,
+ DataRegion,
+ Method);
+ return Status;
+
+}
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: WriteToFile
+//
+// Description: Writes a specified number of bytes to a file from a
+// specified buffer, beginning at a specified position
+// in the file. Updates Size to number of bytes written.
+// Updates Position to position after data written.
+//
+// Parameters:
+// IN FILE_HANDLE_INSTANCE *File - File handle instance
+// IN OUT VOID *Buffer - Buffer to write from
+// IN OUT UINT32 *Size - Size to write (updated with written)
+// IN REGIONS DataRegion - Data region (dir, fat, normal)
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+WriteToFile (
+ IN FILE_HANDLE_INSTANCE *File,
+ IN OUT VOID *Buffer,
+ IN OUT UINT32 *Size,
+ IN REGIONS DataRegion
+)
+{
+ EFI_STATUS Status;
+ VOLUME_INFO *Vol = File->pFH->VolumeInterface;
+ UINT32 Position = (UINT32) File->Position;
+ ACCESS_METHOD Method = WRITE_BLOCK;
+ UINT32 TempSize, RemainingBytes;
+
+ if (File->pFH->DirectoryEntry.Dir_Attr & ATTR_READ_ONLY) return EFI_ACCESS_DENIED;
+
+ if ((Position + *Size) <= File->pFH->DirectoryEntry.Dir_FileSize) {
+// First case -- Writing to existing portion of file (over-writing existing file).
+ Status = ReadWriteExistingBlock(File, Buffer, Size, DataRegion, Method);
+
+ if ( EFI_ERROR(Status)) return Status; // Or other error processing
+
+#ifdef Debug_WriteFile
+ EfiDebugPrint(-1,"WriteToFile: Position %lx Length %x \n", File->Position, *Size);
+#endif
+
+ } else if (File->pFH->DirectoryEntry.Dir_FileSize == 0) {
+// Second case -- Writing to new unallocated space.
+ Status = ExtendFile (File, *Size);
+
+ if (EFI_ERROR(Status)) return Status; // Or other error processing
+
+ File->pFH->DirectoryEntry.Dir_FileSize = *Size;
+ Status = ReadWriteExistingBlock(File, Buffer, Size, DataRegion, Method);
+
+ if (EFI_ERROR(Status)) return Status; // Or other error processing
+
+#ifdef Debug_WriteFile
+ EfiDebugPrint(-1,"WriteToFile: Position %lx Length %x \n", File->Position, *Size);
+#endif
+
+ } else {
+// Third case -- Overwriting existing file, and extending it to unallocated space.
+ RemainingBytes = *Size;
+
+ if (Position < File->pFH->DirectoryEntry.Dir_FileSize) {
+ TempSize = File->pFH->DirectoryEntry.Dir_FileSize - Position;
+ Status = ReadWriteExistingBlock(File, Buffer, &TempSize, DataRegion, Method);
+
+ if (EFI_ERROR(Status)) return Status; // Or other error processing
+
+#ifdef Debug_WriteFile
+ EfiDebugPrint(-1,"WriteToFile: Position %lx Length %x \n", File->Position, TempSize);
+#endif
+ Position = (UINT32) File->Position;
+ RemainingBytes = *Size - TempSize;
+ }
+
+// TODO TODO TODO TODO
+// if Position is greater than FileSize, the extended buffer should be zerod out
+// TODO TODO TODO TODO
+// Extend the File
+ if (RemainingBytes) {
+ TempSize = Position - File->pFH->DirectoryEntry.Dir_FileSize + RemainingBytes;
+ Status = ExtendFile (File, TempSize);
+
+ if (EFI_ERROR(Status)) return Status; // Or other error processing
+
+ File->pFH->DirectoryEntry.Dir_FileSize += TempSize;
+ Status = ReadWriteExistingBlock(File, Buffer, &RemainingBytes, DataRegion, Method);
+
+ if (EFI_ERROR(Status)) return Status; // Or other error processing
+
+#ifdef Debug_WriteFile
+ EfiDebugPrint(-1,"WriteToFile: Position %lx FileSize %x \n",
+ File->Position, File->pFH->DirectoryEntry.Dir_FileSize);
+#endif
+
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: CheckFileWrite
+//
+// Description: Checks if file can be written to
+//
+// Parameters:
+// FILE_HANDLE_INSTANCE *fhi - File Handle instance
+// BOOLEAN IgnoreOpenMode - If true, ignore mode file was
+// open with
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+CheckFileWrite (
+ FILE_HANDLE_INSTANCE *fhi,
+ BOOLEAN IgnoreOpenMode
+)
+{
+
+ FILE_HANDLE *Pfh = fhi->pFH;
+ VOLUME_INFO *vi = Pfh->VolumeInterface;
+
+ // Check for Write Protect
+ if (vi->ReadOnly || Pfh->DirectoryEntry.Dir_Attr & ATTR_READ_ONLY)
+ return EFI_WRITE_PROTECTED;
+
+ if (Pfh->DirectoryEntry.Dir_Attr & ATTR_DIRECTORY)
+ return EFI_UNSUPPORTED; // see sec 11-27 For Directory writes
+
+ // Check the attribute of the FILE. Is it opened in Readonly mode
+ if (!IgnoreOpenMode)
+ if (fhi->OpenMode == EFI_FILE_MODE_READ) return EFI_ACCESS_DENIED;
+
+ return EFI_SUCCESS;
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
diff --git a/Core/EM/FileSystem/FileSYstem.mak b/Core/EM/FileSystem/FileSYstem.mak
new file mode 100644
index 0000000..31872e8
--- /dev/null
+++ b/Core/EM/FileSystem/FileSYstem.mak
@@ -0,0 +1,75 @@
+#**********************************************************************
+#**********************************************************************
+#** **
+#** (C)Copyright 1985-2004, American Megatrends, Inc. **
+#** **
+#** All Rights Reserved. **
+#** **
+#** 6145-F Northbelt Pkwy, Norcross, GA 30071 **
+#** **
+#** Phone: (770)-246-8600 **
+#** **
+#**********************************************************************
+#**********************************************************************
+
+#**********************************************************************
+# $Header: /Alaska/SOURCE/Core/Modules/FileSystem/FileSYstem.mak 4 12/09/05 11:08a Felixp $
+#
+# $Revision: 4 $
+#
+# $Date: 12/09/05 11:08a $
+#**********************************************************************
+# Revision History
+# ----------------
+# $Log: /Alaska/SOURCE/Core/Modules/FileSystem/FileSYstem.mak $
+#
+# 4 12/09/05 11:08a Felixp
+#
+# 2 12/02/05 11:22a Felixp
+#
+# 1 12/01/05 9:44a Felixp
+#
+# 2 5/24/05 11:55a Felixp
+# reference to EfiDebugLib removed
+#
+# 1 4/26/05 6:05p Srinin
+#
+#
+#
+#**********************************************************************
+#<AMI_FHDR_START>
+#
+# Name: SIMPLE_FILES_SYSTEM_MAK
+#
+# Description:
+#
+#<AMI_FHDR_END>
+#**********************************************************************
+all : FILE_SYSTEM
+
+FILE_SYSTEM: $(BUILD_DIR)\FileSystem.mak FileSystemBin
+
+$(BUILD_DIR)\FileSystem.mak : $(FILESYSTEM_DIR)\$(@B).cif $(FILESYSTEM_DIR)\$(@B).mak $(BUILD_RULES)
+ $(CIF2MAK) $(FILESYSTEM_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS)
+
+FileSystemBin: $(AMIDXELIB)
+ $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\
+ /f $(BUILD_DIR)\FileSystem.mak all\
+ GUID=93022F8C-1F09-47EF-BBB2-5814FF609DF5\
+ ENTRY_POINT=SimpleFileSystemEntryPoint \
+ TYPE=BS_DRIVER \
+ COMPRESS=1\
+
+#**********************************************************************
+#** **
+#** (C)Copyright 1985-2004, American Megatrends, Inc. **
+#** **
+#** All Rights Reserved. **
+#** **
+#** 6145-F Northbelt Pkwy, Norcross, GA 30071 **
+#** **
+#** Phone: (770)-246-8600 **
+#** **
+#**********************************************************************
+#**********************************************************************
+
diff --git a/Core/EM/FileSystem/FileSystem.c b/Core/EM/FileSystem/FileSystem.c
new file mode 100644
index 0000000..760d55b
--- /dev/null
+++ b/Core/EM/FileSystem/FileSystem.c
@@ -0,0 +1,948 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Core/Modules/FileSystem/FileSystem.c 16 11/03/11 6:20a Rajeshms $
+//
+// $Revision: 16 $
+//
+// $Date: 11/03/11 6:20a $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Core/Modules/FileSystem/FileSystem.c $
+//
+// 16 11/03/11 6:20a Rajeshms
+// [TAG] EIP73261
+// [Category] Improvement
+// [Description] FileSystem Driver Follow the UEFI Driver Model as per
+// the UEFI Spec. and STOP function was Verified.
+// [Files] FileSystem.c
+//
+// 15 11/18/10 3:05p Felixp
+// Removable media detection problem(EIP 47788).
+// Symptoms: The "map -r" Shell command didn't detect removable media
+// such as floppy or CD if the media had been removed and than inserted
+// back.
+//
+// 14 8/28/09 12:28p Felixp
+// Support for both UnicodeCollation and UnicodeCollation2 protocols
+// (based on value of the EFI_SPECIFICATION_VERSION SDL token).
+//
+// 13 8/28/09 11:59a Felixp
+// Component Name protocol implementation is upadted to support both
+// ComponentName and ComponentName2 protocols
+// (based on value of the EFI_SPECIFICATION_VERSION SDL token).
+//
+// 12 7/02/09 5:47p Pats
+// Updated to latest coding standard. No code changes.
+//
+// 11 4/13/07 7:07p Pats
+// Edited to conform with coding standards. No code changes.
+//
+// 10 12/21/06 1:44p Felixp
+// Bug fix in FileSystemInitUnicodeCollation: only first language in the
+// list of UNICODE_COLLATION supported languages was checked.
+//
+// 9 9/13/06 3:42p Pats
+// Corrected validation test comparing Media ID byte to first FAT byte to
+// use Bytes Per Sector instead of Block Size in calculating FAT offset.
+// This corrects problem of it not working on El Torito CD disks.
+//
+// 8 8/16/06 12:03p Markw
+// Fixed UINTN* and UINT32* 64-bit issues.
+//
+// 7 8/15/06 6:30p Markw
+// Reverting back to version 5.
+//
+// 5 3/29/06 2:53p Srinin
+// Memory Deallocation problem fixed.
+//
+// 4 3/13/06 5:08p Pats
+// Removed validation test using BS_BootSig. Added validation test
+// comparing BPB_Media with first FAT byte.
+//
+// 3 3/13/06 2:23a Felixp
+//
+// 2 12/08/05 2:21p Pats
+// Checked in from other directory, will latest fixes.
+//
+// 8 11/29/05 6:07p Pats
+// Fixed problem of partition table being incorrectly recognized as a
+// FAT12 drive boot sector.
+//
+// 7 11/03/05 2:15p Srinin
+// Fixed VC7.1 warning msg.
+//
+// 6 8/15/05 1:16p Srinin
+// SimpleFileSystemStart changed to return proper Status code.
+//
+// 4 6/21/05 4:00p Pats
+// Removed commented-out debug code.
+//
+// 3 5/27/05 10:00a Srinin
+// Volume size and Free space calculation modified.
+//
+// 2 5/24/05 11:56a Felixp
+// reference to EfiDebugLib removed
+//
+// 1 4/26/05 6:05p Srinin
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: FileSystem.c
+//
+// Description: Installs Simple File System Protocol
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+//----------------------------------------------------------------------
+
+#include "FileSystem.h"
+
+//----------------------------------------------------------------------
+
+EFI_GUID gSimpleFileSystemBusDriverBindingProtocolGuid = EFI_DRIVER_BINDING_PROTOCOL_GUID;
+EFI_GUID guidLoadedImage = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+#ifndef EFI_COMPONENT_NAME2_PROTOCOL_GUID //old Core
+EFI_GUID gComponentNameProtocolGuid = EFI_COMPONENT_NAME_PROTOCOL_GUID;
+#else
+EFI_GUID gComponentNameProtocolGuid = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
+#endif
+EFI_GUID gEfiBlockIoProtocolGuid = EFI_BLOCK_IO_PROTOCOL_GUID;
+EFI_GUID gEfiDiskIoProtocolGuid = EFI_DISK_IO_PROTOCOL_GUID;
+EFI_GUID gEfiGlobalVariableGuid = EFI_GLOBAL_VARIABLE;
+#ifndef EFI_UNICODE_COLLATION2_PROTOCOL_GUID //old Core
+EFI_GUID gEfiUnicodeCollationProtocolGuid = EFI_UNICODE_COLLATION_PROTOCOL_GUID;
+#else
+EFI_GUID gEfiUnicodeCollationProtocolGuid = EFI_UNICODE_COLLATION2_PROTOCOL_GUID;
+#endif
+EFI_GUID gEfiFileInfoGuid = EFI_FILE_INFO_ID;
+EFI_GUID gEfiFileSystemInfoGuid = EFI_FILE_SYSTEM_INFO_ID;
+EFI_GUID gEfiFileSystemVolumeLabelGuid = EFI_FILE_SYSTEM_VOLUME_LABEL_ID;
+
+EFI_UNICODE_COLLATION_PROTOCOL *gFileSystemUnicodeCollationInterface = NULL;
+
+extern EFI_COMPONENT_NAME_PROTOCOL gSimpleFileSystemDriverName;
+extern EFI_GUID guidFS;
+
+EFI_DRIVER_BINDING_PROTOCOL gSimpleFileSystemDriverBinding = {
+ SimpleFileSystemSupported,
+ SimpleFileSystemStart,
+ SimpleFileSystemStop,
+ SIMPLE_FILE_SYSTEM_DRIVER_VERSION, // version
+ NULL, // ImageHandle
+ NULL // DriverBindingHandle
+};
+
+//----------------------------------------------------------------------
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SimpleFileSystemEntryPoint
+//
+// Description: Installs gSimpleFileSystemDriverBinding protocol
+//
+// Parameters: EFI_HANDLE ImageHandle - Image handle for this driver
+// image
+// EFI_SYSTEM_TABLE *SystemTable - pointer to the EFI
+// system table
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+// Here is the control flow of this function:
+// 1. Initialize Ami Lib.
+// 2. Install Driver Binding Protocol
+// 3. Return EFI_SUCCESS.
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS SimpleFileSystemEntryPoint(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *ThisImage;
+
+ gSimpleFileSystemDriverBinding.DriverBindingHandle=ImageHandle;
+ gSimpleFileSystemDriverBinding.ImageHandle=ImageHandle;
+
+ InitAmiLib(ImageHandle, SystemTable);
+ Status = pBS->InstallMultipleProtocolInterfaces(
+ &ImageHandle,
+ &gSimpleFileSystemBusDriverBindingProtocolGuid,&gSimpleFileSystemDriverBinding,
+ &gComponentNameProtocolGuid, &gSimpleFileSystemDriverName,
+ NULL
+ );
+
+
+#ifdef Debug_Level_1
+ EfiDebugPrint(-1," SimpleFileSystemEntryPoint Exit Status %x\n",Status);
+#endif
+
+ Status = pBS->OpenProtocol (
+ ImageHandle,
+ &guidLoadedImage,
+ (VOID **)&ThisImage,
+ ImageHandle,
+ ImageHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ if (EFI_ERROR (Status)) return Status;
+
+ ThisImage->Unload = UnloadSimpleFileSystemDriver;
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: UnloadSimpleFileSystemDriver
+//
+// Description: Unloads this driver
+//
+// Parameters: EFI_HANDLE ImageHandle - Image handle for this driver
+// image
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+UnloadSimpleFileSystemDriver (
+ IN EFI_HANDLE ImageHandle
+)
+{
+ EFI_HANDLE *Buffer;
+ UINTN NoOfHandles, i;
+ EFI_STATUS Status;
+
+ Status = pBS->LocateHandleBuffer (AllHandles, NULL, NULL, &NoOfHandles, &Buffer);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ for (i = 0; i < NoOfHandles; i++) {
+ pBS->DisconnectController(Buffer[i], ImageHandle, NULL);
+ }
+
+ if (Buffer) pBS->FreePool(Buffer);
+
+ Status = pBS->UninstallMultipleProtocolInterfaces(
+ ImageHandle,
+ &gSimpleFileSystemBusDriverBindingProtocolGuid,&gSimpleFileSystemDriverBinding,
+ &gComponentNameProtocolGuid, &gSimpleFileSystemDriverName,
+ NULL);
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SimpleFileSystemSupported
+//
+// Description: Checks whether Simple File System Protocol can be
+// installed on the controller or not.
+//
+// Parameters: EFI_DRIVER_BINDING_PROTOCOL *This - Pointer to this
+// instance of driver binding
+// protocol
+// EFI_HANDLE Controller - Handle for this controller
+// EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S): DiskIO and BlockIO should have been installed on the
+// controller.
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SimpleFileSystemSupported(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+)
+{
+
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+
+// Check if DiskIO can be opened by EFI_OPEN_PROTOCOL_BY_DRIVER
+ Status = pBS->OpenProtocol( Controller,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+// Close DiskIO Protocol
+ Status = pBS->CloseProtocol (
+ Controller,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller);
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+
+// Check if BlockIO can be opened by EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ Status = pBS->OpenProtocol( Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+
+ if( Status != (EFI_ALREADY_STARTED || EFI_ACCESS_DENIED) ) {
+ return EFI_UNSUPPORTED;
+ } else {
+ return Status;
+ }
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SimpleFileSystemStart
+//
+// Description: Installs Simple File Ssystem Protocol
+//
+// Parameters: EFI_DRIVER_BINDING_PROTOCOL *This - Pointer to this
+// instance of driver binding
+// protocol
+// EFI_HANDLE Controller - Handle for this controller
+// EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SimpleFileSystemStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+)
+{
+
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+
+// Check if DiskIO can be opened by EFI_OPEN_PROTOCOL_BY_DRIVER
+ Status = pBS->OpenProtocol( Controller,
+ &gEfiDiskIoProtocolGuid,
+ (VOID **)&DiskIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER );
+
+ if (EFI_ERROR (Status)) return EFI_DEVICE_ERROR;
+
+// Check if BlockIO can be opened by EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ Status = pBS->OpenProtocol( Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+// Get the UnicodeCollation driver
+ Status = FileSystemInitUnicodeCollation (This, &gFileSystemUnicodeCollationInterface);
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Status = DetectInstallVolume(DiskIo, BlkIo, Controller);
+
+ if (EFI_ERROR(Status)) {
+ goto Error;
+ }
+
+ return EFI_SUCCESS;
+
+Error:
+ //
+ // Close DiskIO Protocol
+ //
+ pBS->CloseProtocol (Controller,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if( Status == EFI_OUT_OF_RESOURCES ) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ return EFI_DEVICE_ERROR;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SimpleFileSystemStop
+//
+// Description: Uninstall Simple File system Protocol
+//
+// Parameters: EFI_DRIVER_BINDING_PROTOCOL *This - Pointer to this
+// instance of driver binding
+// protocol
+// EFI_HANDLE Controller - Handle for this controller
+// EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SimpleFileSystemStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+)
+{
+
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
+ VOLUME_INFO *vi;
+
+ Status = pBS->OpenProtocol ( Controller,
+ &guidFS,
+ &FileSystem,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR;
+
+ vi = (VOLUME_INFO *)FileSystem;
+
+ if (NumberOfChildren) return EFI_DEVICE_ERROR;
+
+ Status = pBS->UninstallMultipleProtocolInterfaces(
+ (vi->VolumeHandle),
+ &guidFS, &(vi->SimpleFileSystemProtocol),
+ NULL);
+
+ if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR;
+
+// Close DISK_IO Protocol
+ Status = pBS->CloseProtocol (
+ Controller,
+ &gEfiDiskIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller);
+
+ if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR;
+
+ Status = fsDeAllocateMemory(vi, vi->TempBuffer);
+ if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR;
+
+ Status = FreeUpResources (vi, EFI_NO_MEDIA);
+ if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR;
+
+ Status = pBS->FreePool(vi->CacheBuffer);
+ if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR;
+
+ Status = pBS->FreePool(vi);
+ if (EFI_ERROR(Status)) return EFI_DEVICE_ERROR;
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: DetectInstallVolume
+//
+// Description: Detects whether a valid volume is present or not
+//
+// Parameters: EFI_DISK_IO_PROTOCOL *DiskIo - Pointer to disk IO
+// structure
+// Parameters: EFI_BLOCK_IO_PROTOCOL *DiskIo - Pointer to boock IO
+// structure
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+DetectInstallVolume(
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_BLOCK_IO_PROTOCOL *BlkIo,
+ IN EFI_HANDLE Handle
+)
+{
+
+ EFI_STATUS Status;
+ VOLUME_INFO *vi;
+ UINT32 TempBufferSize, i, Fat_Cache_Blocks, Dir_Cache_Blocks, \
+ TotalCacheMemory, TotalCacheList;
+ UINTN CacheAddress, CacheListAddress;
+ CACHE_HEADER *ch;
+
+ Status = pBS->AllocatePool (EfiBootServicesData,
+ sizeof(VOLUME_INFO),
+ (VOID**)&vi);
+
+// No need to close IDE_CONTROLLER_PROTOCOL
+ if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES;
+
+ Zeromemory (vi, sizeof(VOLUME_INFO));
+
+ vi->DiskIo = DiskIo;
+ vi->BlkIo = BlkIo;
+ vi->MediaID = vi->BlkIo->Media->MediaId;
+ Status = DetectVolume(vi, FALSE);
+
+ if (EFI_ERROR(Status)) {
+ pBS->FreePool(vi);
+ return Status;
+ }
+
+ vi->UnicodeCollationInterface = gFileSystemUnicodeCollationInterface;
+
+ vi->SimpleFileSystemProtocol.OpenVolume = OpenVolume;
+ vi->SimpleFileSystemProtocol.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
+ vi->VolumeHandle = Handle;
+ DListInit(&(vi->OpenFHs));
+ DListInit(&(vi->OpenFIs));
+ DListInit(&(vi->CacheList));
+
+// Allocate TempBuffer, max. cluster size which is 32KB
+ TempBufferSize = vi->RootDirSectorCount << vi->BytesPerSecPowerof2;
+
+ if (vi->BytesPerCluster > TempBufferSize) TempBufferSize = vi->BytesPerCluster;
+
+ Status = fsAllocateMemory(vi, TempBufferSize, (VOID**)&vi->TempBuffer, FALSE);
+
+// Init the cache Buffers
+ Fat_Cache_Blocks = vi->AllowedFatCacheSize / vi->BytesPerCluster;
+ Dir_Cache_Blocks = vi->AllowedDirCacheSize / vi->BytesPerCluster;
+
+ TotalCacheMemory = Fat_Cache_Blocks * vi->BytesPerCluster +
+ Dir_Cache_Blocks * vi->BytesPerCluster;
+
+ TotalCacheList = Fat_Cache_Blocks * sizeof (CACHE_HEADER) +
+ Dir_Cache_Blocks * sizeof (CACHE_HEADER);
+
+ Status = pBS->AllocatePool (EfiBootServicesData,
+ TotalCacheMemory + TotalCacheList,
+ (VOID**)&vi->CacheBuffer);
+
+ CacheAddress = (UINTN) (vi->CacheBuffer);
+ CacheListAddress = (UINTN) (vi->CacheBuffer) + TotalCacheMemory;
+
+ for (i = 0; i < Fat_Cache_Blocks + Dir_Cache_Blocks; i++) {
+ ch = (CACHE_HEADER *)CacheListAddress;
+ ch->AbsoluteOffset = 0;
+ ch->AbsoluteOffsetEnd = 0;
+ ch->Buffer = (UINT8 *) CacheAddress;
+ ch->DIRTY_FLAG = FALSE;
+
+ if ( i < Fat_Cache_Blocks) ch->DataRegion = FAT_REGION;
+
+ else ch->DataRegion = DIRECTORY_REGION;
+
+ DListAdd(&(vi->CacheList), &(ch->CacheLink));
+ CacheAddress += vi->BytesPerCluster;
+ CacheListAddress += sizeof (CACHE_HEADER);
+ }
+
+ Status = pBS->InstallMultipleProtocolInterfaces (
+ &(vi->VolumeHandle),
+ &guidFS, &(vi->SimpleFileSystemProtocol),
+ NULL);
+
+ if (EFI_ERROR(Status)) {
+ pBS->FreePool(vi);
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: DetectVolume
+//
+// Description: Detects the presence of a valid FAT volume
+//
+// Parameters: VOLUME_INFO *vi - Pointer to the volume info structure
+// BOOLEAN StatusCheck - Only reads MBR if true
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+DetectVolume (
+ VOLUME_INFO *vi,
+ BOOLEAN StatusCheck
+)
+{
+
+ EFI_STATUS Status;
+ VOLUME_BPB *Bpb;
+ UINT8 *Buffer;
+ UINT8 *Buffer2;
+ BOOLEAN VALID_FAT = TRUE;
+ UINT64 Offset;
+
+ Status = fsAllocateMemory(vi, vi->BlkIo->Media->BlockSize, (VOID**)&Buffer, FALSE);
+// Status = pBS->AllocatePool (EfiBootServicesData,
+// vi->BlkIo->Media->BlockSize,
+// (VOID**)&Buffer);
+
+ if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES; //No need to close IDE_CONTROLLER_PROTOCOL
+
+// Read Logical Sector 0
+ Status= vi->DiskIo->ReadDisk (vi->DiskIo, vi->MediaID, 0, vi->BlkIo->Media->BlockSize, Buffer);
+
+ // Read Second time if EFI_MEDIA_CHANGED is returned for media changeable devices
+ // (like CDROM/Floppy)
+ if( Status == EFI_MEDIA_CHANGED ) {
+ vi->MediaID = vi->BlkIo->Media->MediaId;
+ Status= vi->DiskIo->ReadDisk (vi->DiskIo, vi->MediaID, 0, vi->BlkIo->Media->BlockSize, Buffer);
+ }
+ if (EFI_ERROR(Status) || StatusCheck) {
+// pBS->FreePool(Buffer);
+ fsDeAllocateMemory(vi, Buffer);
+ vi->VolumeStatus = Status;
+ return Status;
+ }
+
+ Bpb = (VOLUME_BPB *)Buffer;
+
+ vi->FatType = FAT_UNKNOWN;
+
+// Check for 0x55aa at offset 510
+ if ( *(UINT16 *) ((UINT8 *)Buffer + 510) != 0xaa55) {
+// pBS->FreePool(Buffer);
+ fsDeAllocateMemory(vi, Buffer);
+ return EFI_UNSUPPORTED;
+ }
+
+// Check for valid jmp instruction
+ if (Buffer[0] != 0xEB && Buffer[0] != 0xE9 ) VALID_FAT = FALSE;
+
+// Check for valid Bytes per Sector
+ switch (Bpb->BPB_BytePerSec) {
+ case 512:
+ vi->BytesPerSecPowerof2 = 9;
+ break;
+ case 1024:
+ vi->BytesPerSecPowerof2 = 10;
+ break;
+ case 2048:
+ vi->BytesPerSecPowerof2 = 11;
+ break;
+ case 4096:
+ vi->BytesPerSecPowerof2 = 12;
+ break;
+ default:
+ VALID_FAT = FALSE;
+ }
+
+// Check for Valid Sectors per cluster
+ if (Bpb->BPB_SecPerClus != 1 && Bpb->BPB_SecPerClus != 2 &&
+ Bpb->BPB_SecPerClus != 4 && Bpb->BPB_SecPerClus != 8 &&
+ Bpb->BPB_SecPerClus != 16 && Bpb->BPB_SecPerClus != 32 &&
+ Bpb->BPB_SecPerClus != 64 && Bpb->BPB_SecPerClus != 128) VALID_FAT = FALSE;
+
+// Check for Reserved Sector Count and Number of FATS
+ if (Bpb->BPB_RsvdSecCnt == 0 || Bpb->BPB_NumFATs == 0) VALID_FAT = FALSE;
+
+// Both TotSec16 and TotSec32 cannot be zero
+ if (Bpb->BPB_TotSec16 == 0 && Bpb->BPB_TotSec32 == 0) VALID_FAT = FALSE;
+
+// This test removed (3-13-06)
+// If it is a FAT12 or FAT16 disk, and the boot signature is not 29, reject the disk.
+// if (Bpb->BPB_FATSz16 != 0 && Bpb->BPB_FAT.BPB_FAT1216.BS_BootSig != 0x29) VALID_FAT = FALSE;
+
+// This test added (3-13-06)
+// If the media byte doesn't match the first FAT byte, reject the disk.
+ if (VALID_FAT) {
+ Status = fsAllocateMemory(vi, Bpb->BPB_BytePerSec, (VOID**)&Buffer2, FALSE);
+
+ if (EFI_ERROR(Status)) {
+ fsDeAllocateMemory(vi, Buffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Offset = Bpb->BPB_RsvdSecCnt * Bpb->BPB_BytePerSec;
+ Status= vi->DiskIo->ReadDisk (vi->DiskIo, vi->MediaID, Offset, Bpb->BPB_BytePerSec, Buffer2);
+
+ if (EFI_ERROR(Status)) {
+ fsDeAllocateMemory(vi, Buffer);
+ fsDeAllocateMemory(vi, Buffer2);
+ return Status;
+ }
+
+ if (Bpb->BPB_Media != Buffer2[0]) VALID_FAT = FALSE;
+
+ fsDeAllocateMemory(vi, Buffer2);
+ }
+
+ if (!VALID_FAT) goto error_check;
+
+ vi->RootDirSectorCount = ((Bpb->BPB_RootEntCnt << 5 ) + (Bpb->BPB_BytePerSec - 1)) / Bpb->BPB_BytePerSec;
+
+ vi->FATSz = Bpb->BPB_FATSz16;
+
+ if (Bpb->BPB_FATSz16 == 0) vi->FATSz = Bpb->BPB_FAT.BPB_FAT32.BPB_FATSz32;
+
+ vi->TotalSectors = Bpb->BPB_TotSec16;
+
+ if (Bpb->BPB_TotSec16 == 0) vi->TotalSectors = Bpb->BPB_TotSec32;
+
+ vi->DataSectors = vi->TotalSectors \
+ - Bpb->BPB_RsvdSecCnt \
+ - vi->FATSz * Bpb->BPB_NumFATs \
+ - vi->RootDirSectorCount;
+
+ vi->CountOfDataClusters = vi->DataSectors / Bpb->BPB_SecPerClus;
+
+// There could be a few sectors at the "end" of the disk that will not completely
+// fill a cluster. Make sure these are not counted in the DataSectors.
+ vi->DataSectors = vi->CountOfDataClusters * Bpb->BPB_SecPerClus;
+
+ if (vi->CountOfDataClusters < 4085) {
+ vi->FatType = FAT12;
+ vi->EOCMark = 0x0ff8;
+
+ } else if (vi->CountOfDataClusters < 65525) {
+ vi->FatType = FAT16;
+ vi->EOCMark = 0x0fff8;
+
+ } else {
+ vi->FatType = FAT32;
+ vi->EOCMark = 0x0ffffff8;
+ }
+
+// Calculate where Root Directory Entries are present
+ if (vi->FatType == FAT32)
+ vi->FirstRootDirSector = Bpb->BPB_FAT.BPB_FAT32.BPB_RootClus * Bpb->BPB_SecPerClus;
+
+ else
+ vi->FirstRootDirSector = Bpb->BPB_RsvdSecCnt + (Bpb->BPB_NumFATs * Bpb->BPB_FATSz16);
+
+// Copy Sector Zero Contends to VOLUME_BPB in vi
+ pBS->CopyMem (&(vi->VolumeBPB), Buffer, sizeof(VOLUME_BPB));
+
+ vi->BytesPerCluster = (UINT32)vi->VolumeBPB.BPB_SecPerClus << vi->BytesPerSecPowerof2;
+
+// Update CacheSize
+ vi->AllowedFatCacheSize = FAT_CACHE_SIZE;
+
+ if (FAT_CACHE_SIZE < vi->BytesPerCluster << 1) vi->AllowedFatCacheSize = vi->BytesPerCluster << 1;
+
+ vi->AllowedDirCacheSize = DIR_CACHE_SIZE;
+
+ if (DIR_CACHE_SIZE < vi->BytesPerCluster << 1) vi->AllowedDirCacheSize = vi->BytesPerCluster << 1;
+
+error_check:
+ fsDeAllocateMemory(vi, Buffer);
+
+ if (vi->FatType == FAT_UNKNOWN) {
+ vi->VolumeStatus = EFI_UNSUPPORTED;
+ return EFI_UNSUPPORTED;
+ }
+
+ vi->VolumeStatus = EFI_SUCCESS;
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FileSystemInitUnicodeCollation
+//
+// Description: Find the language Interface
+//
+// Parameters: EFI_DRIVER_BINDING_PROTOCOL *This - Pointer to this
+// instance of driver binding
+// protocol
+// UINT8 *LandCode - Pointer to the language code
+// EFI_UNICODE_COLLATION_PROTOCOL *gFileSystemUnicodeCollationInterface
+// - Pointer to pointer to unicode
+// collation interfact structure
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FileSystemInitUnicodeCollation (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN OUT EFI_UNICODE_COLLATION_PROTOCOL **gFileSystemUnicodeCollationInterface
+)
+{
+ EFI_STATUS Status;
+
+ if (*gFileSystemUnicodeCollationInterface != NULL) return EFI_SUCCESS;
+
+ // Locate all Unicode Collation Protocol
+ Status = pBS->LocateProtocol(
+ &gEfiUnicodeCollationProtocolGuid, NULL,
+ gFileSystemUnicodeCollationInterface
+ );
+ return Status;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: Zeromemory
+//
+// Description: Zeros the contents of a specified memory location
+//
+// Parameters: VOID *Buffer - location of memory to zero
+// UINT32 Size - Size in bytes to zero
+//
+// Return Value: none
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S): For testing under Aptio and Alaska,
+// This routine has been copied.
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+void
+Zeromemory (
+ void *Buffer,
+ UINT32 Size
+)
+{
+ UINT8 *Ptr;
+ Ptr = Buffer;
+
+ while (Size--) {
+ *(Ptr++) = 0;
+ }
+
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rig hts Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
diff --git a/Core/EM/FileSystem/FileSystem.chm b/Core/EM/FileSystem/FileSystem.chm
new file mode 100644
index 0000000..d45524f
--- /dev/null
+++ b/Core/EM/FileSystem/FileSystem.chm
Binary files differ
diff --git a/Core/EM/FileSystem/FileSystem.cif b/Core/EM/FileSystem/FileSystem.cif
new file mode 100644
index 0000000..ebeaf79
--- /dev/null
+++ b/Core/EM/FileSystem/FileSystem.cif
@@ -0,0 +1,19 @@
+<component>
+ name = "FileSystem"
+ category = ModulePart
+ LocalRoot = "Core\EM\FileSystem\"
+ RefName = "FileSystem"
+[files]
+"\FileSystem.sdl"
+"\FileSYstem.mak"
+"\FileSystem.h"
+"\Open.c"
+"\FileSystem.c"
+"\FileFatHandler.c"
+"\Info.c"
+"\DirectoryHandler.c"
+"\VolFatHandler.c"
+"\MediaAccess.c"
+"\FileSystemComponentName.c"
+"\FileSystem.chm"
+<endComponent>
diff --git a/Core/EM/FileSystem/FileSystem.h b/Core/EM/FileSystem/FileSystem.h
new file mode 100644
index 0000000..092eb9d
--- /dev/null
+++ b/Core/EM/FileSystem/FileSystem.h
@@ -0,0 +1,1480 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Core/Modules/FileSystem/FileSystem.h 13 10/24/11 10:56a Artems $
+//
+// $Revision: 13 $
+//
+// $Date: 10/24/11 10:56a $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Core/Modules/FileSystem/FileSystem.h $
+//
+// 13 10/24/11 10:56a Artems
+// EIP 73254: Remove "magic number" from source, added new #define macro
+//
+// 12 5/05/11 3:44p Pats
+// [TAG] - EIP 58999
+// [Category]- BUG FIX
+// [Severity]- Major
+// [Symptom] - Cannot launch Shell from USB Filesystem device in Debug
+// mode with latest Filesystem driver.
+// [RootCause] - Functions using DISKIO were raising TPL to a fixed level.
+// [Solution] - Modified above functions to check for the higher of the
+// fixed level or current level.
+// [Files] - Info.c, MediaAccess.c, Open.c, FileSystem.h
+//
+// 11 6/11/10 5:41p Pats
+// EIP 39171: Long name sometimes not displayed, only short name.
+// FetchLongName() in Open.c did not handle case where long name spilt
+// over 2 clusters. Function modified to handle the case.
+// Prototype changed here in this file.
+//
+// 10 8/28/09 11:59a Felixp
+// Component Name protocol implementation is upadted to support both
+// ComponentName and ComponentName2 protocols
+// (based on value of the EFI_SPECIFICATION_VERSION SDL token).
+//
+// 9 7/02/09 5:47p Pats
+// Updated to latest coding standard. No code changes.
+//
+// 8 4/13/07 7:07p Pats
+// Edited to conform with coding standards. No code changes.
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: FileSystem.h
+//
+// Description: Header file for Simple File System driver
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+//----------------------------------------------------------------------
+
+#ifndef _SimpleFileSystem_
+#define _SimpleFileSystem_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//----------------------------------------------------------------------
+
+#include <Efi.h>
+#include <Token.h>
+#include <Dxe.h>
+#include <AmiDxeLib.h>
+#include "Protocol\PciIo.h"
+#include "Protocol\DevicePath.h"
+#include "protocol\DriverBinding.h"
+#include "protocol\BlockIo.h"
+#include "protocol\DiskIo.h"
+#include "Protocol\PDiskInfo.h"
+#include "Protocol\SimpleFileSystem.h"
+#include "Protocol\UnicodeCollation.h"
+#include "Protocol\LoadedImage.h"
+#include <Protocol\ComponentName.h>
+
+#define SIMPLE_FILE_SYSTEM_DRIVER_VERSION 0x010000
+#define BS_OEMName_Offset 3
+#define BPB_BytePerSec_Offset 11
+#define BPB_SecPerClus_Offset 13
+#define BPB_RsvdSecCnt_Offset 14
+#define BPB_NumFATs_Offset 16
+#define BPB_RootEntCnt_Offset 17
+#define BPB_TotSec16_Offset 19
+#define BPB_Media_Offset 21
+#define BPB_FATSz16_Offset 22
+#define BPB_SecPerTrk_Offset 24
+#define BPB_NumHeads_Offset 26
+#define BPB_Hiddsec_Offset 28
+#define BPB_TotSec32_Offset 32
+
+
+#define BS_DrvNum_Offset 36
+#define BS_Reserved1_Offset 37
+#define BS_BootSig_Offset 38
+#define BS_VolID_Offset 39
+#define BS_VolLab_Offset 43
+#define BS_FilSysType_Offset 54
+
+#define BPB_FATSz32_Offset 36
+#define BPB_ExtFlags_Offset 40
+#define BPB_FSVer_Offset 42
+#define BPB_RootClus_Offset 44
+#define BPB_FSInfo_Offset 48
+#define BPB_BkBootSec_Offset 50
+#define BPB_Rserved_Offset 52
+#define BS_DrvNum_32_Offset 64
+#define BS_Reserved1_32_Offset 65
+#define BS_BootSig_32_Offset 66
+#define BS_VolID_32_Offset 67
+#define BS_VolLab_32_Offset 71
+#define BS_FilSysType_32_Offset 82
+
+#define ATTR_READ_ONLY 0x01
+#define ATTR_HIDDEN 0x02
+#define ATTR_SYSTEM 0x04
+#define ATTR_VOLUME_ID 0x08
+#define ATTR_DIRECTORY 0x10
+#define ATTR_ARCHIVE 0x20
+#define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
+#define ATTR_LONG_NAME_MASK (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID | ATTR_ARCHIVE | ATTR_DIRECTORY)
+
+#define DIR_ENTRY_ERASE 0xE5
+#define MAX_LFN_LENGTH 255
+#define MAX_TOTAL_PATH_LENGTH 260
+#define MAX_LFN_SLOTS 20
+
+#define MEMBLOCKSIZE 0x8000
+#define MEMALLOCSIZE 0x40
+#define MAX_OPEN_FHS 0x20
+#define FSI_Free_Count 488
+#define FSI_Nxt_Free 492
+
+#pragma pack(1)
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: FAT_DATE
+//
+// Description: File date structure
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct {
+ UINT16 Day : 5;
+ UINT16 Month : 4;
+ UINT16 Year : 7; // From 1980
+ } FAT_DATE;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: FAT_TIME
+//
+// Description: File time structure
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct {
+ UINT16 DoubleSecond : 5;
+ UINT16 Minute : 6;
+ UINT16 Hour : 5;
+ } FAT_TIME;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: FAT_DATE_TIME
+//
+// Description: Contains FAT_TIME and FAT_DATE
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct {
+ FAT_TIME Time;
+ FAT_DATE Date;
+ } FAT_DATE_TIME;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: FAT_TYPE
+//
+// Description: Enumeration of fat types
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef enum {
+ FAT12 = 1,
+ FAT16,
+ FAT32,
+ FAT_UNKNOWN
+ } FAT_TYPE;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: REGIONS
+//
+// Description: Enumeration of volume regions
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef enum {
+ RESERVED_REGION,
+ FAT_REGION,
+ DIRECTORY_REGION,
+ DATA_REGION
+ } REGIONS;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: ACCESS_METHOD
+//
+// Description: Enumeration of access methods (read or write)
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef enum {
+ READ_BLOCK,
+ WRITE_BLOCK
+ } ACCESS_METHOD;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: DIR_ENTRY_32
+//
+// Description: Structure of a FAT32 directory entry
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct _DIR_ENTRY_32 {
+
+ UINT8 Dir_Name[11];
+ UINT8 Dir_Attr;
+ UINT8 Dir_NTRes;
+ UINT8 Dir_CrtTimeTenth;
+ UINT16 Dir_CrtTime;
+ UINT16 Dir_CrtDate;
+ UINT16 Dir_LstAccDate;
+ UINT16 Dir_FstClusHI;
+ UINT16 Dir_WrtTime;
+ UINT16 Dir_WrtDate;
+ UINT16 Dir_FstClusLO;
+ UINT32 Dir_FileSize;
+
+ } DIR_ENTRY_32;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: DIR_ENTRY_LFN
+//
+// Description: Structure of a long file name directory entry
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct _DIR_ENTRY_LFN {
+ UINT8 Dir_Order; // Sequence number for slot
+ CHAR16 Dir_Name0_4[5]; // First 5 Unicode characters
+ UINT8 Dir_Attr; // Attributes, always 0x0F
+ UINT8 Dir_Reserved; // Reserved, always 0x00
+ UINT8 Dir_Checksum; // Checksum of 8.3 name
+ CHAR16 Dir_Name5_10[6]; // 6 more Unicode characters
+ UINT16 Dir_FstClus; // First cluster number, must be 0
+ CHAR16 Dir_Name11_12[2]; // Last 2 Unicode characters
+ } DIR_ENTRY_LFN;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: BPB_COMMON
+//
+// Description: Structure of the common part of the BIOS parameter block
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct _BPB_COMMON {
+ UINT8 BS_JmpBoot[3];
+ UINT8 BS_OEMName[8];
+ UINT16 BPB_BytePerSec;
+ UINT8 BPB_SecPerClus;
+ UINT16 BPB_RsvdSecCnt;
+ UINT8 BPB_NumFATs;
+ UINT16 BPB_RootEntCnt;
+ UINT16 BPB_TotSec16;
+ UINT8 BPB_Media;
+ UINT16 BPB_FATSz16;
+ UINT16 BPB_SecPerTrk;
+ UINT16 BPB_NumHeads;
+ UINT32 BPB_Hiddsec;
+ UINT32 BPB_TotSec32;
+ } BPB_COMMON;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: BPB_FAT_12_16
+//
+// Description: Structure of the FAT 12 or 16 unique part of the BPB
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct _BPB_FAT_12_16 {
+ UINT8 BS_DrvNum;
+ UINT8 BS_Reserved1;
+ UINT8 BS_BootSig;
+ UINT32 BS_VolID;
+ UINT8 BS_VolLab[11];
+ UINT8 BS_FilSysType[8];
+ } BPB_FAT_12_16;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: BPB_FAT_32
+//
+// Description: Structure of the FAT 32 unique part of the BPB
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct _BPB_FAT_32 {
+ UINT32 BPB_FATSz32;
+ UINT16 BPB_ExtFlags;
+ UINT16 BPB_FSVer;
+ UINT32 BPB_RootClus;
+ UINT16 BPB_FSInfo;
+ UINT16 BPB_BkBootSec;
+ UINT8 BPB_Rserved[12];
+ UINT8 BS_DrvNum_32;
+ UINT8 BS_Reserved1_32;
+ UINT8 BS_BootSig_32;
+ UINT8 BS_VolID_32[4];
+ UINT8 BS_VolLab_32[11];
+ UINT8 BS_FilSysType_32[8];
+ } BPB_FAT_32;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: VOLUME_BPB
+//
+// Description: Structure of the Volume BIOS Parameter Block. Combines common,
+// FAT 12-16, and FAT 32 parts
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct _VOLUME_BPB {
+ UINT8 BS_JmpBoot[3];
+ UINT8 BS_OEMName[8];
+ UINT16 BPB_BytePerSec;
+ UINT8 BPB_SecPerClus;
+ UINT16 BPB_RsvdSecCnt;
+ UINT8 BPB_NumFATs;
+ UINT16 BPB_RootEntCnt;
+ UINT16 BPB_TotSec16;
+ UINT8 BPB_Media;
+ UINT16 BPB_FATSz16;
+ UINT16 BPB_SecPerTrk;
+ UINT16 BPB_NumHeads;
+ UINT32 BPB_Hiddsec;
+ UINT32 BPB_TotSec32;
+ union {
+ BPB_FAT_12_16 BPB_FAT1216;
+ BPB_FAT_32 BPB_FAT32;
+ } BPB_FAT;
+ } VOLUME_BPB;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: VOLUME_INFO
+//
+// Description: Structure containing all Volume Information
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct _VOLUME_INFO {
+
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystemProtocol; // This should be the first entry in this structure
+ EFI_HANDLE VolumeHandle;
+ EFI_STATUS VolumeStatus; // Global status that can be used by any open handles
+
+ FAT_TYPE FatType;
+ UINT32 EOCMark;
+ VOLUME_BPB VolumeBPB;
+ BOOLEAN ValidVolumeID;
+ CHAR16 VolumeID[12];
+ CHAR16 *FileSystemName;
+ UINT8 BytesPerSecPowerof2;
+ UINT32 BytesPerCluster;
+ UINT32 FirstRootDirSector;
+ UINT32 RootDirSectorCount; // 0 for FAT32
+ UINT32 FATSz; // Size of 1 FAT
+ UINT32 TotalSectors;
+ UINT32 DataSectors;
+ UINT32 CountOfDataClusters;
+
+// Volume information for EFI_FILE_SYSTEM_INFO
+ UINT64 VolumeSize;
+ UINT32 FreeSpaceinClusters;
+ UINT32 FreeSpaceinSector1;
+ UINT32 BlockSize;
+ BOOLEAN ReadOnly;
+ UINT32 LastFreeCluster;
+ UINT32 FreeClusterBlocks;
+
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ UINT32 MediaID;
+ EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollationInterface;
+
+ UINT32 AllocatedMemorySize;
+ UINT32 TotalDirEntryList;
+ UINT32 AllowedFatCacheSize;
+ UINT32 AllowedDirCacheSize;
+ UINT32 FATCacheSize;
+ UINT32 DirCacheSize;
+ UINT32 *TempBuffer;
+ UINT32 *CacheBuffer;
+ BOOLEAN TempBufferInUse;
+ struct _FILE_HANDLE * RootFH;
+ DLIST OpenFHs;
+ DLIST OpenFIs;
+ DLIST CacheList;
+ DLIST MemList;
+
+ } VOLUME_INFO;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: FILE_HANDLE
+//
+// Description: Structure containing File Handle information
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct _FILE_HANDLE {
+
+ VOLUME_INFO *VolumeInterface;
+ EFI_STATUS HandleStatus;
+ BOOLEAN ROOTDIR;
+
+ CHAR16 *FileNameLFN; // Points to the long Filename if not points to 8.3
+ DIR_ENTRY_32 DirectoryEntry; // 8.3 entry
+
+ UINT32 DirCluster; // Cluster at which this entry is present. For Root directory (FAT12/16) it is the sector count.
+ UINT32 DirOffset; // Offset with in the cluster
+ UINT16 InstancesCount; // No of Instances opened so far
+ UINT32 SlotNumber; // Same as in DIR_ENTRY_LIST
+ UINT32 FreeDirEntryCluster; // For FAT12/16 and ROOT directory, not valid.
+ UINT32 FreeDirEntryOffset; //
+
+ BOOLEAN DirEntryChanged;
+ BOOLEAN DirListChanged;
+ struct _FILE_HANDLE *Parent; // Points to the parent directory
+ DLIST DirList; // List if Directory Entries
+ DLINK ViFHLink; // This link is for the DLIST OpenFHs in VOLUME_INFO
+
+ DLIST ChildList;
+ DLINK ChildLink;
+
+ } FILE_HANDLE;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: FILE_HANDLE_INSTANCE
+//
+// Description: Structure containing File Handle Instance information
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct _FILE_HANDLE_INSTANCE {
+
+ EFI_FILE_PROTOCOL FileHandle; // Should be the first entry in the structure
+ EFI_STATUS HandleInstanceStatus;
+ FILE_HANDLE *pFH;
+ UINT64 OpenMode; // Open Modes
+ UINT64 Position; //
+ UINT32 CurrentCluster; // will point to sector number where the position is pointing currently
+ UINT32 CurrentClusterOffset; // will point to sector number where the position is pointing currently
+ BOOLEAN MEDIA_NOT_VALID; // Will be true if for any reason current instances cannot use the volume Eg: Change in Media
+ DLINK ViFILink; // This link is for the DLIST OpenFIs in the VOLUME_INFO
+
+ } FILE_HANDLE_INSTANCE;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: DIR_ENTRY_LIST
+//
+// Description: Structure containing directory entry information
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct {
+
+ DIR_ENTRY_32 DirectoryEntry; // 8.3 entry
+ CHAR16 *FileNameLFN; // Points to the long Filename if not points to 8.3
+ UINT32 Cluster; // Not valid for FAT12/16 ROOT
+ UINT32 Offset; // For ROOT Fat12/16, offset is from the beginning.
+ UINT32 SlotNumber; // Used for EFI DIR
+ DLINK DirLink; //
+
+ } DIR_ENTRY_LIST;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: CACHE_HEADER
+//
+// Description: Structure containing cache header information
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct {
+
+ UINT64 AbsoluteOffset;
+ UINT64 AbsoluteOffsetEnd;
+ UINT8 *Buffer;
+ BOOLEAN DIRTY_FLAG;
+ REGIONS DataRegion;
+ DLINK CacheLink;
+
+ } CACHE_HEADER;
+
+
+//<AMI_SHDR_START>
+//----------------------------------------------------------------------------
+// Name: MEM_HEADER
+//
+// Description: Structure containing memory header information
+//
+// Referrals:
+//
+//----------------------------------------------------------------------------
+//<AMI_SHDR_END>
+
+ typedef struct {
+
+ UINTN AddresMap;
+ UINT32 AddresMapLength;
+ UINTN BufferStart;
+ UINTN BufferEnd;
+ DLINK MemLink;
+
+ } MEM_HEADER;
+
+#pragma pack()
+
+#define FIRSTCLUSTER(D) (((UINT32) D.Dir_FstClusHI << 16) + (UINT32) D.Dir_FstClusLO)
+#define CLUSTERSREQUIRED(N) (N + Vol->BytesPerCluster - 1) / Vol->BytesPerCluster
+#define FAT12_EOC(EntryValue) (EntryValue >= 0x0FF8)
+#define FAT16_EOC(EntryValue) (EntryValue >= 0xFFF8)
+#define FAT32_EOC(EntryValue) (EntryValue >= 0x0FFFFFF8)
+
+
+ EFI_STATUS
+ SimpleFileSystemSupported(
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+ EFI_STATUS
+ SimpleFileSystemStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+ EFI_STATUS
+ SimpleFileSystemStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+ EFI_STATUS
+ FileSystemInitUnicodeCollation (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN OUT EFI_UNICODE_COLLATION_PROTOCOL **gFileSystemUnicodeCollationInterface
+ );
+
+ EFI_STATUS
+ DetectInstallVolume(
+ IN EFI_DISK_IO_PROTOCOL *DiskIo,
+ IN EFI_BLOCK_IO_PROTOCOL *BlkIo,
+ IN EFI_HANDLE Handle
+ );
+
+ EFI_STATUS
+ DetectVolume (
+ VOLUME_INFO *VolumeInterface,
+ BOOLEAN StatusCheck
+ );
+
+ EFI_STATUS
+ OpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **Root
+ );
+
+ EFI_STATUS
+ OpenRoot(
+ IN VOLUME_INFO *VolumeInfo,
+ IN OUT FILE_HANDLE **Root
+ );
+
+ EFI_STATUS
+ CreateFileHandleInstance (
+ IN FILE_HANDLE *Root,
+ IN OUT FILE_HANDLE_INSTANCE **FileInstance,
+ IN UINT64 OpenMode
+ );
+
+ void
+ InitEFIFileInterface (
+ EFI_FILE_PROTOCOL *EFIFileInterface
+ );
+
+ EFI_STATUS
+ OpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **Root
+ );
+
+ EFI_STATUS
+ OpenFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ );
+
+ EFI_STATUS
+ CloseFileHandle (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+ EFI_STATUS
+ DeleteFileHandle (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+ EFI_STATUS
+ ReadFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+ EFI_STATUS
+ WriteFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+ EFI_STATUS
+ GetPositionFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 *Position
+ );
+
+ EFI_STATUS
+ SetPositionFileHandleThis (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 Position
+ );
+
+
+ EFI_STATUS
+ SetPositionFileHandle (
+ IN FILE_HANDLE_INSTANCE *fhi,
+ IN UINT64 Position
+ );
+
+ EFI_STATUS
+ GetInfoFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+
+ EFI_STATUS
+ SetInfoFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+ EFI_STATUS
+ FlushFileHandle (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+ EFI_STATUS
+ ProcessOpenFileHandle(
+ IN FILE_HANDLE_INSTANCE *ParentFi,
+ IN CHAR16 **FileName,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ );
+
+ EFI_STATUS
+ CreateDirectoryEntry (
+ IN FILE_HANDLE *fh,
+ IN CHAR16 *NextCompName,
+ OUT FILE_HANDLE **fh1,
+ IN UINT64 Attributes
+ );
+
+ EFI_STATUS
+ CreateDirEntryInDisk (
+ IN FILE_HANDLE *fh,
+ IN CHAR16 *NextCompName,
+ IN UINT64 Attributes,
+ OUT UINT32 *FreeDirCluster,
+ OUT UINT32 *FreeDirClusterOffset,
+ DIR_ENTRY_32 *Entry
+ );
+
+ BOOLEAN
+ FindMatchingFH (
+ IN VOLUME_INFO *Vi,
+ IN CHAR16 *NextCompName,
+ IN FILE_HANDLE *fh,
+ OUT FILE_HANDLE **fh1
+ );
+
+ EFI_STATUS
+ ReadAllDirectoryEntries (
+ IN FILE_HANDLE *fh
+ );
+
+ EFI_STATUS
+ CreateFHFromDirEntryList(
+ IN DIR_ENTRY_LIST *Del,
+ IN FILE_HANDLE *fh,
+ OUT FILE_HANDLE **fh1
+ );
+
+ BOOLEAN
+ FindMatchingDirEntry (
+ IN FILE_HANDLE *fh,
+ IN CHAR16 *NextCompName,
+ OUT DIR_ENTRY_LIST **Del
+ );
+
+ BOOLEAN
+ FindMatchingSFNDirEntry (
+ IN FILE_HANDLE *fh,
+ IN CHAR8 *ShortFileName,
+ OUT DIR_ENTRY_LIST **Del
+ );
+
+ EFI_STATUS
+ AddToDirList (
+ FILE_HANDLE *fh,
+ DIR_ENTRY_32 DirectoryEntry,
+ CHAR16 *lfn,
+ UINT32 Cluster,
+ UINT32 Offset,
+ UINT32 SlotNumber
+ );
+
+ EFI_STATUS
+ GetDirListAtPosition(
+ FILE_HANDLE *Pfh,
+ UINT64 Position,
+ DIR_ENTRY_LIST **Del
+ );
+
+ EFI_STATUS
+ GetNextCompName (
+ IN OUT CHAR16 **FileName,
+ IN CHAR16 *NextCompName
+ );
+
+ void
+ RemoveDirEntries (
+ IN FILE_HANDLE *Rfh,
+ IN FILE_HANDLE *fh
+ );
+
+ EFI_STATUS
+ RemoveFH (
+ FILE_HANDLE *fh
+ );
+
+ EFI_STATUS
+ FreeUpDirEntries (
+ VOLUME_INFO *vi,
+ FILE_HANDLE *pfh
+ );
+
+ EFI_STATUS
+ FreeUpFHEntries (
+ VOLUME_INFO *vi,
+ FILE_HANDLE *pfh
+ );
+
+ EFI_STATUS
+ RemoveAllDirList(
+ FILE_HANDLE *lfh
+ );
+
+
+ EFI_STATUS
+ RemoveDirList (
+ FILE_HANDLE *fh,
+ DIR_ENTRY_LIST *Del
+ );
+
+ BOOLEAN
+ FatLfnIsValid (
+ CHAR16 *Name
+ );
+
+ EFI_STATUS
+ fsAllocateMemory (
+ VOLUME_INFO *vi,
+ UINT32 Size,
+ VOID **Buffer,
+ BOOLEAN CLEAR
+ );
+
+ EFI_STATUS
+ fsDeAllocateMemory (
+ VOLUME_INFO *vi,
+ void *Buffer
+ );
+
+ EFI_STATUS
+ GetVolumeLabel (
+ VOLUME_INFO *vi,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+ EFI_STATUS
+ SetVolumeLabel (
+ VOLUME_INFO *vi,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+ EFI_STATUS
+ GetfileInfo (
+ IN FILE_HANDLE_INSTANCE *fhi,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+ EFI_STATUS
+ SetfileInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN FILE_HANDLE_INSTANCE *fhi,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+ EFI_STATUS
+ GetFileInfoFromFH (
+ FILE_HANDLE *Pfh,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+ VOID
+ FatToEfiTime (
+ EFI_TIME *EfiTime,
+ UINT16 Date,
+ UINT16 Time
+ );
+
+ VOID
+ EfiToFatTime (
+ EFI_TIME EfiTime,
+ UINT16 *Date,
+ UINT16 *Time
+ );
+
+ EFI_STATUS
+ GetSystemInfo (
+ IN VOLUME_INFO *vi,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FILE_SYSTEM_INFO *Buffer
+ );
+
+ EFI_STATUS
+ SetSystemInfo (
+ IN VOLUME_INFO *vi,
+ IN UINTN BufferSize,
+ OUT EFI_FILE_SYSTEM_INFO *Buffer
+ );
+
+ UINT32
+ ReturnFreeSpace (
+ IN VOLUME_INFO *vi
+ );
+
+ EFI_STATUS
+ GetVolumeLabel (
+ IN VOLUME_INFO *vi,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+ UINT8
+ LfnChecksum(
+ UINT8 *D
+ );
+
+ UINT8
+ FetchLongName (
+ FILE_HANDLE *fh,
+ DIR_ENTRY_32 *Buffer,
+ UINT32 BufferPos,
+ UINT16 *Name,
+ UINT32 ClusterNumber,
+ UINT32 ClusterSize
+ );
+
+ BOOLEAN
+ FindShortName (
+ UINT8 *Buffer,
+ UINT32 *Offset,
+ UINT32 BufferSize
+ );
+
+ EFI_STATUS
+ FsReadMedia (
+ VOLUME_INFO *vi,
+ UINT8 *Buffer,
+ UINT64 Sector,
+ UINT32 Offset,
+ UINT32 ByteCount,
+ REGIONS DataRegion
+ );
+
+ EFI_STATUS
+ FsWriteMedia (
+ VOLUME_INFO *vi,
+ UINT8 *Buffer,
+ UINT64 SectorCount,
+ UINT32 Offset,
+ UINT32 ByteCount,
+ REGIONS DataRegion
+ );
+
+ void
+ HandleDiskIoError (
+ VOLUME_INFO *vi,
+ EFI_STATUS Status
+
+ );
+
+ ExtractShortFileName (
+ VOLUME_INFO *Vi,
+ CHAR16 *lfn,
+ UINT8 *Buffer
+ );
+
+ EFI_STATUS
+ CheckCached (
+ VOLUME_INFO *vi,
+ UINT64 AbsoluteOffset,
+ UINT32 ByteCount,
+ UINT8 **cBuffer,
+ UINT32 *cBufferLength,
+ CACHE_HEADER **ch,
+ REGIONS DataRegion
+ );
+
+ BOOLEAN
+ IsCacheHit (
+ VOLUME_INFO *vi,
+ REGIONS DataRegion,
+ UINT64 AbsoluteOffset,
+ UINT32 ByteCount,
+ UINT8 **cBuffer,
+ UINT32 *cBufferLength,
+ CACHE_HEADER **ch1
+ );
+
+ void
+ CreateSpaceforCache (
+ VOLUME_INFO *vi,
+ UINT32 ByteCount,
+ REGIONS DataRegion,
+ CACHE_HEADER **ch1
+ );
+
+ EFI_STATUS
+ ReadClusterOfDirectoryEntries (
+ IN FILE_HANDLE *fh,
+ IN UINT32 ClusterNumber,
+ OUT UINT32 *ClusterRead,
+ UINT8 *Buffer,
+ UINT32 *BufferSize
+ );
+
+ EFI_STATUS
+ ReadFatClusterNumber (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ IN UINT8 FatNumber,
+ OUT UINT32 *Value
+ );
+
+ EFI_STATUS
+ FatClusterNumberLocation (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ IN UINT8 FatNumber,
+ OUT UINT32 *Sector,
+ OUT UINT32 *SectorOffset
+ );
+
+ EFI_STATUS
+ WriteFatClusterNumber (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ IN UINT8 FatNumber,
+ IN UINT32 Value
+ );
+
+ EFI_STATUS
+ UnlinkFat (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ OUT UINT32 *ClusterCount
+ );
+
+ EFI_STATUS
+ FindFreeClusters (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 From,
+ IN UINT32 To,
+ OUT UINT32 *StartCluster,
+ IN OUT UINT32 *FreeClusters,
+ OUT UINT32 *TotalFree
+ );
+
+ EFI_STATUS
+ FindNextFreeCluster (
+ IN VOLUME_INFO *Vol,
+ OUT UINT32 *Cluster
+ );
+
+ EFI_STATUS
+ GetFreeClusterCount (
+ IN VOLUME_INFO *Vol,
+ OUT UINT32 *FreeClustersCount,
+ OUT UINT32 *FreeClusterBlock,
+ OUT UINT32 *FreeBlockCount
+ );
+
+ UINT32
+ ClusterToSector (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster
+ );
+
+ UINT32
+ SectorToCluster (
+ IN VOLUME_INFO *Vol,
+ IN OUT UINT32 Sector
+ );
+
+ EFI_STATUS
+ GetClusterCount (
+ IN VOLUME_INFO *Vol,
+ IN OUT UINT32 Cluster
+ );
+
+ int
+ Wcscmpcaseinsensitive(
+ CHAR16 *string1,
+ CHAR16 *string2
+ );
+
+ EFI_STATUS
+ ReadFromFile (
+ IN FILE_HANDLE_INSTANCE *File,
+ IN OUT VOID *Buffer,
+ IN OUT UINT32 *Size,
+ IN REGIONS DataRegion
+ );
+
+ EFI_STATUS
+ WriteToFile (
+ IN FILE_HANDLE_INSTANCE *File,
+ IN OUT VOID *Buffer,
+ IN OUT UINT32 *Size,
+ IN REGIONS DataRegion
+ );
+
+
+ EFI_STATUS
+ AllocateFirstCluster (
+ IN FILE_HANDLE_INSTANCE *File,
+ OUT UINT32 *Cluster
+ );
+
+ EFI_STATUS
+ AllocateAndLinkClusters (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 BeginCluster,
+ IN UINT32 Size,
+ OUT UINT32 *FirstCluster,
+ OUT UINT32 *ClusterCount
+ );
+
+ static int AllocateAndLinkNewCluster (
+ VOLUME_INFO *Vol,
+ IN UINT32 PrevCluster,
+ OUT UINT32 *Cluster
+ );
+
+
+ EFI_STATUS
+ ExtendFile (
+ IN FILE_HANDLE_INSTANCE *fhi,
+ IN UINT32 Length
+ );
+
+ EFI_STATUS
+ GetContiguousClusters (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Size,
+ IN OUT UINT32 Cluster,
+ OUT UINT32 *LastCluster,
+ OUT UINT32 *Count
+ );
+
+ VOID
+ GetAbsSectorInfo (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ IN UINT32 ClusterOffset,
+ OUT UINT32 *Sector,
+ OUT UINT32 *SectorOffset
+ );
+
+ EFI_STATUS
+ GetClusterPosition (
+ IN FILE_HANDLE_INSTANCE *File,
+ IN UINT64 Position,
+ OUT UINT32 *Cluster,
+ OUT UINT32 *ClusterOffset
+ );
+
+ UINT32
+ GetEocValue (
+ IN VOLUME_INFO *Vol
+ );
+
+ EFI_STATUS
+ ValidateCurrentStatus (
+ FILE_HANDLE_INSTANCE *fhi
+ );
+
+ VOID
+ GetSectorAddressDir (
+ FILE_HANDLE *fh,
+ UINT32 Cluster,
+ UINT32 ClusterOffset,
+ UINT32 *Sector,
+ UINT32 *SectorOffset
+ );
+
+ EFI_STATUS
+ UpdateAccAndWriteTime (
+ IN OUT DIR_ENTRY_LIST *del
+ );
+
+ EFI_STATUS
+ UpdateAccDate(
+ IN OUT DIR_ENTRY_LIST *del
+ );
+
+ BOOLEAN
+ UpdateAccDateRequired (
+ IN OUT DIR_ENTRY_LIST *del
+ );
+
+ EFI_STATUS
+ GetSpaceforDirEntry(
+ IN FILE_HANDLE *fh,
+ IN UINT32 FreeBytesRequired,
+ OUT UINT32 *FreeDirCluster,
+ OUT UINT32 *FreeDirClusterOffset,
+ BOOLEAN *LastDirEntry
+ );
+
+ EFI_STATUS
+ CheckforValidDirSpace (
+ IN VOLUME_INFO *Vi,
+ IN BOOLEAN ROOTDIR,
+ IN UINT32 Cluster,
+ IN UINT32 Offset,
+ IN UINT32 FreeBytesRequired,
+ IN UINT32 *FreeDirCluster,
+ IN UINT32 *FreeDirClusterOffset
+ );
+
+ EFI_STATUS
+ LocateFreeDirEntry(
+ IN FILE_HANDLE *fh,
+ IN UINT32 FreeBytesRequired,
+ OUT UINT32 *FreeDirCluster,
+ OUT UINT32 *FreeDirClusterOffset,
+ BOOLEAN *LastDirEntry
+ );
+
+ EFI_STATUS
+ GenShortFilename (
+ IN VOLUME_INFO *Vol,
+ IN CHAR16 *InPath,
+ OUT CHAR8 *ShortName
+ );
+
+ EFI_STATUS
+ UpdateDirListFromFHDir (
+ FILE_HANDLE *fh
+ );
+
+ EFI_STATUS
+ LocateDel (
+ DLINK *dlink,
+ UINT32 Cluster,
+ UINT32 ClusterOffset,
+ DIR_ENTRY_LIST **Del,
+ UINT32 *Position
+ );
+
+ EFI_STATUS
+ GenUniqueShortFname (
+ IN FILE_HANDLE *fh,
+ IN CHAR16 *LongName,
+ OUT CHAR8 *ShortName,
+ OUT BOOLEAN *LfnNeeded
+ );
+
+ EFI_STATUS
+ SplitLFN (
+ IN CHAR16 *LongName,
+ IN DIR_ENTRY_32 *ShortEntry,
+ OUT DIR_ENTRY_LFN *Slot,
+ OUT UINT32 *NumSlots
+ );
+
+ EFI_STATUS
+ ZeroOutdisk (
+ IN VOLUME_INFO *Vi,
+ IN UINT32 Cluster,
+ IN UINT32 ClusterOffset,
+ IN UINT32 Size
+ );
+
+ EFI_STATUS
+ ShrinkClusters (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 StartCluster,
+ IN UINT32 ClusterCount
+ );
+
+ UINT32
+ GetClustersRequired (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 N
+ );
+
+ EFI_STATUS
+ UpdateFreeSpace (
+ IN VOLUME_INFO *vi,
+ IN UINT32 Count,
+ IN BOOLEAN Add
+ );
+
+ EFI_STATUS
+ FreeUpResources (
+ VOLUME_INFO *vi,
+ EFI_STATUS Status
+ );
+
+ EFI_STATUS
+ MarkVolumeDirty (
+ IN VOLUME_INFO *vi
+ );
+
+ EFI_STATUS
+ UnloadSimpleFileSystemDriver (
+ IN EFI_HANDLE ImageHandle
+ );
+
+ void
+ Zeromemory (
+ void *Buffer,
+ UINT32 Size
+ );
+
+ EFI_STATUS
+ CheckFileWrite (
+ FILE_HANDLE_INSTANCE *fhi,
+ BOOLEAN IgnoreOpenMode
+ );
+
+ VOID EfiInitializeDriverLib(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+ EFI_STATUS
+ InternalMemAllocate (
+ VOLUME_INFO *vi,
+ UINT32 Size,
+ VOID **Buffer,
+ BOOLEAN CLEAR
+ );
+
+ EFI_STATUS
+ AddBlocktoInternalMemManager (
+ VOLUME_INFO *vi
+ );
+
+ EFI_STATUS
+ GetMemory (
+ MEM_HEADER *Mem,
+ UINT32 Blocks,
+ VOID **Buffer,
+ BOOLEAN CLEAR
+ );
+
+ EFI_STATUS
+ FreeMemory (
+ VOLUME_INFO *vi,
+ VOID *Buffer
+ );
+
+
+ VOID
+ GetTempBuffer (
+ VOLUME_INFO *vi,
+ VOID **Buffer
+ );
+
+ VOID
+ ReleaseTempBuffer (
+ VOLUME_INFO *vi
+ );
+
+ void
+ PrintOpenfhiandfh (
+ VOLUME_INFO *vi
+ );
+
+ VOID Labcpy(
+ CHAR16 *string1,
+ CHAR16 * string2
+ );
+
+ UINTN Lablen(
+ CHAR16 *string
+ );
+
+ EFI_TPL
+ FindNextTpl (
+ EFI_TPL TplLevel
+ );
+
+ VOID EfiDebugPrint (
+ IN UINTN ErrorLevel,
+ IN CHAR8 *Format,
+ ...
+ );
+
+ /****** DO NOT WRITE BELOW THIS LINE *******/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
diff --git a/Core/EM/FileSystem/FileSystem.sdl b/Core/EM/FileSystem/FileSystem.sdl
new file mode 100644
index 0000000..43f4467
--- /dev/null
+++ b/Core/EM/FileSystem/FileSystem.sdl
@@ -0,0 +1,49 @@
+TOKEN
+ Name = "FILESYSTEM_SUPPORT"
+ Value = "1"
+ Help = "Main switch to enable FileSystem Support"
+ TokenType = Boolean
+ TargetEQU = Yes
+ TargetMAK = Yes
+ Master = Yes
+End
+
+TOKEN
+ Name = "DIRECTORTY_ENTRIES_CACHED"
+ Value = "100"
+ Help = "Indicate the number of Directory entries \that can be cached."
+ TokenType = Integer
+ TargetH = Yes
+End
+
+TOKEN
+ Name = "FAT_CACHE_SIZE"
+ Value = "4000h"
+ Help = "Specifiy the FAT CACHE size for each volume."
+ TokenType = Integer
+ TargetH = Yes
+End
+
+TOKEN
+ Name = "DIR_CACHE_SIZE"
+ Value = "4000h"
+ Help = "Specify the DIR Cache size for each volume."
+ TokenType = Integer
+ TargetH = Yes
+End
+
+PATH
+ Name = "FILESYSTEM_DIR"
+End
+
+MODULE
+ Help = "Includes FileSystem.mak to Project"
+ File = "FileSystem.mak"
+End
+
+ELINK
+ Name = "$(BUILD_DIR)\FileSystem.ffs"
+ Parent = "$(CORE_DIR)\FileSystem$(ARCH).ffs"
+ InvokeOrder = ReplaceParent
+End
+
diff --git a/Core/EM/FileSystem/FileSystemComponentName.c b/Core/EM/FileSystem/FileSystemComponentName.c
new file mode 100644
index 0000000..f2ac049
--- /dev/null
+++ b/Core/EM/FileSystem/FileSystemComponentName.c
@@ -0,0 +1,271 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Core/Modules/FileSystem/FileSystemComponentName.c 7 8/28/09 11:59a Felixp $
+//
+// $ $
+//
+// $ $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Core/Modules/FileSystem/FileSystemComponentName.c $
+//
+// 7 8/28/09 11:59a Felixp
+// Component Name protocol implementation is upadted to support both
+// ComponentName and ComponentName2 protocols
+// (based on value of the EFI_SPECIFICATION_VERSION SDL token).
+//
+// 6 7/02/09 5:47p Pats
+// Updated to latest coding standard. No code changes.
+//
+// 5 4/13/07 7:07p Pats
+// Edited to conform with coding standards. No code changes.
+//
+// 2 7/16/05 2:01p Felixp
+// bug fixes in Component Name implementation
+//
+// 1 4/26/05 6:05p Srinin
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: FileSystemComponentName.c
+//
+// Description: Simple File System controller name functions
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+#include "FileSystem.h"
+
+#ifndef EFI_COMPONENT_NAME2_PROTOCOL_GUID //old Core
+#ifndef LANGUAGE_CODE_ENGLISH
+#define LANGUAGE_CODE_ENGLISH "eng"
+#endif
+static BOOLEAN LanguageCodesEqual(
+ CONST CHAR8* LangCode1, CONST CHAR8* LangCode2
+){
+ return LangCode1[0]==LangCode2[0]
+ && LangCode1[1]==LangCode2[1]
+ && LangCode1[2]==LangCode2[2];
+}
+#endif
+//----------------------------------------------------------------------
+
+EFI_STATUS
+SimpleFileSystemCtlDriverName(
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+);
+
+EFI_STATUS
+SimpleFileSystemCtlGetControllerName(
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+);
+
+//----------------------------------------------------------------------
+
+CHAR16 *gFileSystemDriverName = L"AMI File System Driver";
+CHAR16 *gFileSystemControllerName = L"FAT File System";
+extern EFI_GUID guidFS;
+extern EFI_DRIVER_BINDING_PROTOCOL gSimpleFileSystemDriverBinding;
+//==================================================================================
+EFI_COMPONENT_NAME_PROTOCOL gSimpleFileSystemDriverName = {
+ SimpleFileSystemCtlDriverName,
+ SimpleFileSystemCtlGetControllerName,
+ LANGUAGE_CODE_ENGLISH
+};
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: SimpleFileSystemCtlDriverName
+//
+// Description: Retrieves a Unicode string that is the user readable name of
+// the EFI Driver.
+//
+//
+// Parameters:
+// EFI_COMPONENT_NAME_PROTOCOL
+// This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+// CHAR8
+// Language - A pointer to a three character ISO 639-2 language identifier.
+// This is the language of the driver name that that the caller
+// is requesting, and it must match one of the languages specified
+// in SupportedLanguages. The number of languages supported by a
+// driver is up to the driver writer.
+// CHAR16
+// DriverName - A pointer to the Unicode string to return. This Unicode string
+// is the name of the driver specified by This in the language
+// specified by Language.
+//
+// Return value:
+// EFI_SUCCES - The Unicode string for the Driver specified by This
+// and the language specified by Language was returned
+// in DriverName.
+// EFI_INVALID_PARAMETER - Language is NULL.
+// EFI_INVALID_PARAMETER - DriverName is NULL.
+// EFI_UNSUPPORTED - The driver specified by This does not support the
+// language specified by Language.
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SimpleFileSystemCtlDriverName(
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+)
+{
+ if (!Language || !DriverName) return EFI_INVALID_PARAMETER;
+
+ if (!LanguageCodesEqual( Language, LANGUAGE_CODE_ENGLISH))
+ return EFI_UNSUPPORTED;
+
+ *DriverName = gFileSystemDriverName;
+ return EFI_SUCCESS;
+}
+
+
+
+//<AMI_PHDR_START>
+//---------------------------------------------------------------------------
+//
+// Procedure: SimpleFileSystemCtlGetControllerName
+//
+// Description: Retrieves a Unicode string that is the user readable name of
+// the controller that is being managed by an EFI Driver.
+//
+// Parameters:
+// EFI_COMPONENT_NAME_PROTOCOL
+// This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+// EFI_HANDLE
+// ControllerHandle - The handle of a controller that the driver specified by
+// This is managing. This handle specifies the controller
+// whose name is to be returned.
+// EFI_HANDLE
+// ChildHandle - The handle of the child controller to retrieve the name
+// of. This is an optional parameter that may be NULL. It
+// will be NULL for device drivers. It will also be NULL
+// for a bus drivers that wish to retrieve the name of the
+// bus controller. It will not be NULL for a bus driver
+// that wishes to retrieve the name of a child controller.
+// CHAR8
+// Language - A pointer to a three character ISO 639-2 language
+// identifier. This is the language of the controller name
+// that that the caller is requesting, and it must match one
+// of the languages specified in SupportedLanguages. The
+// number of languages supported by a driver is up to the
+// driver writer.
+// CHAR16
+// ControllerName - A pointer to the Unicode string to return. This Unicode
+// string is the name of the controller specified by
+// ControllerHandle and ChildHandle in the language
+// specified by Language from the point of view of the
+// driver specified by This.
+//
+// Return value:
+// EFI_SUCCESS - The Unicode string for the user readable name in the
+// language specified by Language for the driver
+// specified by This was returned in DriverName.
+// EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE.
+// EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid
+// EFI_HANDLE.
+// EFI_INVALID_PARAMETER - Language is NULL.
+// EFI_INVALID_PARAMETER - ControllerName is NULL.
+// EFI_UNSUPPORTED - The driver specified by This is not currently
+// managing the controller specified by
+// ControllerHandle and ChildHandle.
+// EFI_UNSUPPORTED - The driver specified by This does not support the
+// language specified by Language.
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//---------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SimpleFileSystemCtlGetControllerName(
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+)
+{
+
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
+ VOLUME_INFO *vi;
+
+ if (!Language || !ControllerName) return EFI_INVALID_PARAMETER;
+
+ if (ChildHandle != NULL) return EFI_UNSUPPORTED;
+
+ Status = pBS->OpenProtocol ( Controller,
+ &guidFS,
+ &FileSystem,
+ gSimpleFileSystemDriverBinding.DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ if (EFI_ERROR(Status)) return EFI_UNSUPPORTED;
+
+ vi = (VOLUME_INFO *)FileSystem;
+
+ // Compare the Language
+ if (!LanguageCodesEqual( Language, LANGUAGE_CODE_ENGLISH))
+ return EFI_UNSUPPORTED;
+
+ if (vi->FileSystemName) *ControllerName = vi->FileSystemName;
+ else *ControllerName = gFileSystemControllerName;
+
+ return EFI_SUCCESS;
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
diff --git a/Core/EM/FileSystem/Info.c b/Core/EM/FileSystem/Info.c
new file mode 100644
index 0000000..9435c34
--- /dev/null
+++ b/Core/EM/FileSystem/Info.c
@@ -0,0 +1,1313 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2011, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Core/Modules/FileSystem/Info.c 15 5/05/11 3:44p Pats $
+//
+// $Revision: 15 $
+//
+// $Date: 5/05/11 3:44p $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Core/Modules/FileSystem/Info.c $
+//
+// 15 5/05/11 3:44p Pats
+// [TAG] - EIP 58999
+// [Category]- BUG FIX
+// [Severity]- Major
+// [Symptom] - Cannot launch Shell from USB Filesystem device in Debug
+// mode with latest Filesystem driver.
+// [RootCause] - Functions using DISKIO were raising TPL to a fixed level.
+// [Solution] - Modified above functions to check for the higher of the
+// fixed level or current level.
+// [Files] - Info.c, MediaAccess.c, Open.c, FileSystem.h
+//
+// 14 2/25/11 2:44p Pats
+// [TAG] - EIP 54399
+// [Category]- BUG FIX
+// [Severity] - Urgent
+// [Symptom] - SCT 2.3 fails Bootable Image Support Test\Simple File
+// System Protocol
+// [RootCause] - Does not check for matching name when attempting to
+// change file name.
+// [Solution] - Modified function SetfileInfo() to check for matching
+// name.
+// [Files] - info.c
+//
+// 13 1/19/11 4:56p Pats
+// [TAG] - EIP 52430
+// [Category]- BUG FIX
+// [Severity] - Normal
+// [Symptom] - When a directory is moved, the long name of the old
+// directory is not deleted.
+// [RootCause] - Only the short name component was being deleted in
+// SetFileInfo().
+// [Solution] - Modified function SetfileInfo() to delete the long name
+// component also.
+// [Files] - info.c
+//
+// 12 1/14/11 2:59p Pats
+// [TAG] - EIP 51754
+// [Category]- BUG FIX
+// [Severity]- Minor
+// [Symptom] - The shell "mv" command makes directories dissapear.
+// [RootCause] - Directorys were not removed from cache when deleted..
+// [Solution] - Modified function SetfileInfo() to remove directories from
+// cache when deleted.
+// [Files] - info.c
+//
+// 11 1/06/11 5:54p Oleksiyy
+// [TAG] EIP28607
+// [Category] Improvement
+// [Description] System was hanging for some time if Floppy Media
+// removed while writing in meda in progress.
+// EFI_TPL_CALLBACK priority level rised during media related calls.
+//
+// [Files] DiskIo.c, Info.c, MediaAccess.c, Open.c, Partition.c
+//
+// 10 1/22/10 4:39p Yul
+// Refer to EIP 32983.
+//
+// 9 7/02/09 5:47p Pats
+// Updated to latest coding standard. No code changes.
+//
+// 8 4/13/07 7:07p Pats
+// Edited to conform with coding standards. No code changes.
+//
+// 7 8/16/06 12:03p Markw
+// Fixed UINTN* and UINT32* 64-bit issues.
+//
+// 10 11/03/05 2:16p Srinin
+// Fixed VC7.1 warning msg.
+//
+// 9 8/08/05 3:55p Markw
+// In SetVolumeLabel, after CreateDirectoryEntry, check if valid file
+// handle before removing.
+//
+// 6 6/22/05 4:29p Pats
+// Added function Labcpy() to replace Wcscpy() so that volume labels are
+// copied correctly. Dumps period added by ExtractShortFileName.
+//
+// 4 6/21/05 9:51a Pats
+// Fixed GetVolumeLabel so that it properly handles the case when there is
+// no label on the volume, to pass SCT tests.
+//
+// 3 6/16/05 4:17p Pats
+// Modified to mark both long and short name entries deleted when a file
+// is deleted, instead of just short name entries.
+//
+// 2 4/27/05 5:30p Srinin
+// 'MV' command supported (Move file/Directories in a volume)
+//
+// 1 4/26/05 6:05p Srinin
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: Info.c
+//
+// Description: Simple File System driver information handling functions
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+//**********************************************************************
+
+//----------------------------------------------------------------------
+
+#include "FileSystem.h"
+#define EFI_TPL_CALLBACK TPL_CALLBACK
+//----------------------------------------------------------------------
+
+extern EFI_GUID gEfiFileSystemVolumeLabelGuid;
+extern EFI_GUID gEfiFileInfoGuid;
+extern EFI_GUID gEfiFileSystemInfoGuid;
+
+//----------------------------------------------------------------------
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: UpdateAccAndWriteTime
+//
+// Description: Updates access and write times in a directory entry
+//
+// Parameters: DIR_ENTRY_LIST *del - pointer to the directory entry list
+// structure
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+UpdateAccAndWriteTime (
+ DIR_ENTRY_LIST *del
+)
+{
+
+ EFI_TIME EfiTime;
+ EFI_TIME_CAPABILITIES Capabilities;
+ UINT16 DummyTime;
+
+ pRS->GetTime(&EfiTime, &Capabilities);
+ EfiToFatTime (EfiTime, &del->DirectoryEntry.Dir_LstAccDate, &DummyTime);
+ EfiToFatTime (EfiTime, &del->DirectoryEntry.Dir_WrtDate, &del->DirectoryEntry.Dir_WrtTime);
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: UpdateAccDate
+//
+// Description: Updates the access date in a directory entry
+//
+// Parameters: DIR_ENTRY_LIST *del - pointer to the directory entry list
+// structure
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+UpdateAccDate(
+ DIR_ENTRY_LIST *del
+)
+{
+
+ EFI_TIME EfiTime;
+ EFI_TIME_CAPABILITIES Capabilities;
+ UINT16 DummyTime;
+
+ pRS->GetTime(&EfiTime, &Capabilities);
+ EfiToFatTime (EfiTime, &del->DirectoryEntry.Dir_LstAccDate, &DummyTime);
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: UpdateAccDateRequired
+//
+// Description: Indicates when update of the access date of a file is
+// required
+//
+// Parameters: DIR_ENTRY_LIST *del - pointer to the directory entry list
+// structure
+//
+// Return value: BOOLEAN - True if update required
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+BOOLEAN
+UpdateAccDateRequired (
+ DIR_ENTRY_LIST *del
+)
+{
+
+ EFI_TIME EfiTime;
+ EFI_TIME_CAPABILITIES Capabilities;
+ UINT16 DummyTime;
+ UINT16 DummyDate;
+
+ pRS->GetTime(&EfiTime, &Capabilities);
+ EfiToFatTime (EfiTime, &DummyDate, &DummyTime);
+
+ if (DummyDate == del->DirectoryEntry.Dir_LstAccDate) return FALSE;
+
+ del->DirectoryEntry.Dir_LstAccDate = DummyDate;
+ return TRUE;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetInfoFileHandle
+//
+// Description: Returns file info, system info, or the label of a volume
+// depending on information type specified
+//
+// Parameters: EFI_FILE_PROTOCOL *This - Pointer to this instance of
+// file protocol
+// EFI_GUID *InformationType - Pointer to information type
+// requested
+// UINTN *BufferSize - Pointer to size of buffer
+// VOID *Buffer - Pointer to buffer for returned info
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetInfoFileHandle(
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+)
+{
+
+ EFI_STATUS Status = EFI_UNSUPPORTED;
+ FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)This;
+ FILE_HANDLE *Pfh;
+ VOLUME_INFO *vi;
+ EFI_TPL SaveTpl;
+ EFI_TPL NextTpl;
+
+ Status = ValidateCurrentStatus (fhi);
+
+ if (EFI_ERROR(Status)) return Status;
+ Pfh = fhi->pFH;
+ vi = Pfh->VolumeInterface;
+// Compare the GUID
+ NextTpl = FindNextTpl (EFI_TPL_CALLBACK);
+ SaveTpl = pBS->RaiseTPL (NextTpl);
+ if (!guidcmp(InformationType, &gEfiFileInfoGuid))
+ Status = GetfileInfo (fhi, BufferSize, Buffer);
+
+ else {
+ if (!guidcmp(InformationType, &gEfiFileSystemInfoGuid))
+ Status = GetSystemInfo (vi, BufferSize, (EFI_FILE_SYSTEM_INFO *)Buffer);
+
+ else {
+ if (!guidcmp(InformationType, &gEfiFileSystemVolumeLabelGuid))
+ Status = GetVolumeLabel (vi, BufferSize, Buffer);
+
+ else{
+ pBS->RestoreTPL(SaveTpl);
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetfileInfo
+//
+// Description: Returns information on a file
+//
+// Parameters: FILE_HANDLE_INSTANCE *fh1 - Pointer to file handle
+// instance
+// UINTN *BufferSize - Pointer to size of buffer
+// VOID *Buffer - Ponter to buffer for returned data
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetfileInfo (
+ IN FILE_HANDLE_INSTANCE *fhi,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+)
+{
+
+ FILE_HANDLE *Pfh = fhi->pFH;
+ return (GetFileInfoFromFH (Pfh, BufferSize, Buffer));
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetSystemInfo
+//
+// Description: Returns file system info on a volume
+//
+// Parameters: VOLUME_INFO *vi - Pointer to volume info structure
+// UINTN *BufferSize - Pointer to size of buffer
+// VOID *Buffer - Ponter to buffer for returned data
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetSystemInfo (
+ IN VOLUME_INFO *vi,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FILE_SYSTEM_INFO *Buffer
+)
+{
+
+ UINTN Length = 0;
+ GetVolumeLabel (vi, &Length, Buffer);
+
+ if (*BufferSize < Length + EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO, VolumeLabel)) {
+
+#ifdef Debug_GetSystemInfo
+ EfiDebugPrint(TRACE_ALWAYS,"GetSystemInfo: I/P BufferSize %x O/P BufferSize %x\n", *BufferSize, Length + EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO, VolumeLabel));
+#endif
+
+ *BufferSize = Length + EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO, VolumeLabel);
+ return EFI_BUFFER_TOO_SMALL;
+
+ }
+
+ Buffer->Size = Length + EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO, VolumeLabel);
+ Buffer->ReadOnly = vi->ReadOnly;
+ Buffer->VolumeSize = vi->VolumeSize;
+ Buffer->FreeSpace = Mul64(ReturnFreeSpace(vi), vi->BytesPerCluster);
+ Buffer->BlockSize = vi->BytesPerCluster;
+ GetVolumeLabel (vi, BufferSize, ((UINT8 *)Buffer) + EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO, VolumeLabel));
+ *BufferSize += EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO, VolumeLabel);
+
+#ifdef Debug_GetSystemInfo
+ EfiDebugPrint(TRACE_ALWAYS,"GetSystemInfo: VolumeLabel %s, BufferSize %x\n", Buffer->VolumeLabel, *BufferSize);
+ EfiDebugPrint(TRACE_ALWAYS,"Size %lx, ReadOnly %x, VolumeSize %lx, FreeSpace %lx, BlockSize %x\n", Buffer->Size, Buffer->ReadOnly, Buffer->VolumeSize, Buffer->FreeSpace, Buffer->BlockSize);
+#endif
+
+ return EFI_SUCCESS;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetVolumeLabel
+//
+// Description: Returns label of a volume
+//
+// Parameters: VOLUME_INFO *vi - Pointer to volume info structure
+// UINTN *BufferSize - Pointer to size of buffer
+// VOID *Buffer - Ponter to buffer for returned data
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetVolumeLabel (
+ IN VOLUME_INFO *vi,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+)
+{
+
+ EFI_STATUS Status;
+ EFI_STATUS LocalStatus;
+ FILE_HANDLE *fh = vi->RootFH;
+ UINTN Length;
+ DLINK *dlink;
+ DIR_ENTRY_LIST *del=NULL;
+
+ if (vi->ValidVolumeID) {
+ Length = Wcslen (vi->VolumeID) << 1;
+
+#ifdef Debug_GetVolumeLabel
+ EfiDebugPrint(-1,"GetVolumeLabel: VolLabel %s I/P BufferSize %x O/P BufferSize %x\n", vi->VolumeID, *BufferSize, Length + 2);
+#endif
+
+ if (*BufferSize < (Length + 2)) {
+ *BufferSize = Length + 2;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ Wcscpy (Buffer, vi->VolumeID);
+ *BufferSize = Length + 2;
+ return EFI_SUCCESS;
+
+ } else {
+ if (*BufferSize < 2) {
+ Status = EFI_BUFFER_TOO_SMALL; // To pass SCT test.
+
+ } else Status = EFI_NOT_FOUND;
+ }
+
+
+// See if the Linked List is Valid
+ if (!fh->DirList.pHead) ReadAllDirectoryEntries (fh);
+
+ dlink = fh->DirList.pHead;
+ LocalStatus = EFI_UNSUPPORTED;
+
+ if (!dlink) return EFI_UNSUPPORTED;
+
+ for ( ; dlink; ) {
+ del = OUTTER(dlink, DirLink, DIR_ENTRY_LIST);
+
+ if ((del->DirectoryEntry.Dir_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) == ATTR_VOLUME_ID) {
+ LocalStatus = EFI_SUCCESS;
+ break;
+ }
+
+ dlink = dlink->pNext;
+ }
+
+ if (LocalStatus == EFI_SUCCESS) {
+ Length = Lablen (del->FileNameLFN) << 1;
+
+ if (Length <= 22) {
+ Zeromemory (vi->VolumeID, sizeof (vi->VolumeID));
+ Labcpy (vi->VolumeID, del->FileNameLFN); // Don't put "." in name
+ vi->ValidVolumeID = TRUE;
+ }
+
+ if (*BufferSize < (Length + 2)) {
+
+#ifdef Debug_GetVolumeLabel
+ EfiDebugPrint(-1,"GetVolumeLabel: VolLabel %s I/P BufferSize %x O/P BufferSize %x\n", vi->VolumeID, *BufferSize, Length + 2);
+#endif
+
+ *BufferSize = Length + 2;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ Status = EFI_SUCCESS;
+ Labcpy (Buffer, del->FileNameLFN);
+ *BufferSize = Length >> 1;
+
+#ifdef Debug_GetVolumeLabel
+ EfiDebugPrint(-1,"GetVolumeLabel: VolLabel %s I/P BufferSize %x O/P BufferSize %x\n", Buffer, *BufferSize, Length + 2);
+#endif
+
+ }
+
+// If there is no volume label, we must return a null label of size 2.
+ else if (Status == EFI_NOT_FOUND) {
+ if (*BufferSize >= 2) Zeromemory (Buffer, 2);
+
+ *BufferSize = 2;
+ Status = EFI_SUCCESS;
+
+ } else if (Status == EFI_BUFFER_TOO_SMALL) *BufferSize = 2;
+
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SetfileInfo
+//
+// Description: Sets the information on a file (updates dir entry)
+//
+// Parameters: FILE_HANDLE_INSTANCE *fh1 - Pointer to file handle
+// instance
+// UINTN *BufferSize - Pointer to size of buffer
+// VOID *Buffer - Ponter to buffer containing new data
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SetfileInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN FILE_HANDLE_INSTANCE *fhi,
+ IN OUT UINTN BufferSize,
+ OUT VOID *Buffer
+)
+{
+
+ EFI_STATUS Status;
+ EFI_FILE_PROTOCOL *NewHandle;
+ FILE_HANDLE *fh = fhi->pFH;
+ FILE_HANDLE *ParentFh = fh->Parent;
+ DIR_ENTRY_LIST *Del = NULL;
+ FILE_HANDLE_INSTANCE *Newfhi;
+ VOLUME_INFO *vi = fh->VolumeInterface;
+ EFI_FILE_INFO *buffer = Buffer;
+ UINT16 Dummy;
+ UINT32 Length;
+ UINT32 OldClusterCount, NewClusterCount;
+ UINT8 DirErase = DIR_ENTRY_ERASE;
+ CHAR16 *NewFileName;
+ BOOLEAN IsSizeChange = fh->DirectoryEntry.Dir_FileSize != (UINT32)(buffer->FileSize) ? TRUE : FALSE;
+ BOOLEAN IsNameChange = (BOOLEAN)Wcscmpcaseinsensitive(buffer->FileName, fh->FileNameLFN);
+
+#ifdef Debug_SetFileInfo
+ EfiDebugPrint(-1,"SetFileInfo: %S I/P BufferSize %x\n", fh->FileNameLFN, BufferSize);
+ EfiDebugPrint(-1,"FileSize %lx, Physical %lx Attribute %lx\n", buffer->FileSize, buffer->PhysicalSize, buffer->Attribute);
+#endif
+
+ Length = EFI_FIELD_OFFSET(EFI_FILE_INFO,FileName);
+
+ if (BufferSize < Length) return EFI_BAD_BUFFER_SIZE;
+
+// Is it a Directory Entry, attr can't be set
+// For a file, it cannot be set as Directory
+ if ((fh->DirectoryEntry.Dir_Attr & ATTR_DIRECTORY) ^
+ ((UINT8)(buffer->Attribute) & ATTR_DIRECTORY)) return EFI_ACCESS_DENIED;
+
+// For Root Directory no entries can be modified
+ if (fh->ROOTDIR) return EFI_ACCESS_DENIED;
+
+ if (buffer->Attribute & ~EFI_FILE_VALID_ATTR) return EFI_INVALID_PARAMETER;
+
+ if (fh->DirectoryEntry.Dir_Attr & ATTR_DIRECTORY && IsSizeChange) return EFI_ACCESS_DENIED;
+
+ if (vi->ReadOnly) return EFI_WRITE_PROTECTED;
+
+ if ((fh->DirectoryEntry.Dir_Attr & ATTR_READ_ONLY ||
+ fhi->OpenMode == EFI_FILE_MODE_READ) && (IsSizeChange || IsNameChange))
+ return EFI_ACCESS_DENIED;
+
+// Update Attribute
+#ifdef Debug_SetFileInfo
+ EfiDebugPrint(-1, "Updated Attribute %x\n", fh->DirectoryEntry.Dir_Attr);
+#endif
+
+ fh->DirectoryEntry.Dir_Attr = (UINT8) buffer->Attribute;
+
+// Rename File/Directory?
+ if (IsNameChange) {
+
+#ifdef Debug_SetFileInfo
+ EfiDebugPrint(-1,"SetFileInfo: New File Name %S Old FileName %S \n", buffer->FileName, fh->FileNameLFN);
+#endif
+
+// Copy the Input FileName
+ Length = (UINT32) (Wcslen(buffer->FileName) * sizeof (CHAR16))+ 2;
+ Status = fsAllocateMemory (vi, Length, &NewFileName, FALSE);
+ pBS->CopyMem (NewFileName, buffer->FileName, Length);
+
+ if (FindMatchingDirEntry (ParentFh, NewFileName, &Del)) {
+ fsDeAllocateMemory (vi, NewFileName);
+ return EFI_ACCESS_DENIED; // Name already exists, can't rename to it
+ }
+
+ Status = ProcessOpenFileHandle (fhi, &NewFileName, &NewHandle, EFI_FILE_MODE_CREATE | 3, 0);
+ fsDeAllocateMemory (vi, NewFileName);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ Newfhi = (FILE_HANDLE_INSTANCE *) NewHandle;
+
+// Delete the old Entry
+ if (fh->DirCluster || fh->DirOffset) {
+ fh->DirectoryEntry.Dir_Name[0] = DirErase;
+ Status = UpdateDirListFromFHDir(fh);
+ if (EFI_ERROR(Status)) return Status;
+ //Remove directory list from cache when deleted.
+ RemoveAllDirList(fh);
+ }
+
+// Other than FileName, copy all the directory entries.
+ pBS->CopyMem (&(Newfhi->pFH->DirectoryEntry.Dir_Attr), &(fh->DirectoryEntry.Dir_Attr), 32 - 11);
+
+// Transfer Information from New to Old
+ fhi->pFH = Newfhi->pFH;
+
+// Release the NewFileHandle Instance Created.
+ DListDelete (&(vi->OpenFIs), &(Newfhi->ViFILink));
+ fsDeAllocateMemory (vi, Newfhi);
+
+ RemoveAllDirList(fh->Parent); // Dir Listing for OLD File Handle
+ RemoveAllDirList(Newfhi->pFH->Parent); // Dir Listing for New File Handle
+ fh->InstancesCount--;
+ RemoveFH(fh); // Remove old File Handle
+ fh = Newfhi->pFH; // fh points to new FH
+//###DEBUG
+ /*
+ // For Directories, ".." entry should point to the new Parent.
+ if (fh->DirectoryEntry.Dir_Attr & ATTR_DIRECTORY) {
+ // Read 40h Bytes
+ GetTempBuffer (vi, &TempBuffer);
+ GetSectorAddressDir(fh, FIRSTCLUSTER(fh->DirectoryEntry), 0, &Sector, &SectorOffset);
+ Status = FsReadMedia (vi, TempBuffer, Sector, SectorOffset, 0x40, DIRECTORY_REGION);
+ if (EFI_ERROR(Status)) return Status;
+
+ if (TempBuffer [0] == '.' && TempBuffer[0x20] == '.' && TempBuffer[0x21] == '.') {
+ (UINT32) TempBuffer += sizeof (DIR_ENTRY_32);
+ ((DIR_ENTRY_32 *) TempBuffer)->Dir_FstClusLO = fh->Parent->DirectoryEntry.Dir_FstClusLO;
+ ((DIR_ENTRY_32 *) TempBuffer)->Dir_FstClusHI = fh->Parent->DirectoryEntry.Dir_FstClusHI;
+ Status = FsWriteMedia (vi, TempBuffer, Sector, SectorOffset, 0x40, DIRECTORY_REGION);
+ if (EFI_ERROR(Status)) return Status;
+ }
+ ReleaseTempBuffer(vi);
+ }
+ */
+//###DEBUG END
+ fh->DirectoryEntry.Dir_Attr |= ATTR_ARCHIVE;
+
+ }
+
+// Update the Date and Time?
+ if (*(UINT32 *)&(buffer->CreateTime) != 0)
+ EfiToFatTime(buffer->CreateTime, &fh->DirectoryEntry.Dir_CrtDate, &fh->DirectoryEntry.Dir_CrtTime);
+
+ if (*(UINT32 *)&(buffer->LastAccessTime) != 0)
+ EfiToFatTime(buffer->LastAccessTime, &fh->DirectoryEntry.Dir_LstAccDate, &Dummy);
+
+ if (*(UINT32 *)&(buffer->ModificationTime) != 0)
+ EfiToFatTime(buffer->ModificationTime, &fh->DirectoryEntry.Dir_WrtDate, &fh->DirectoryEntry.Dir_WrtTime);
+
+// Newsize smaller than Original size?
+ if (fh->DirectoryEntry.Dir_FileSize > (UINT32)(buffer->FileSize)) {
+
+ Status = CheckFileWrite (fhi, FALSE);
+
+ if (EFI_ERROR(Status)) return Status;
+
+#ifdef Debug_SetFileInfo
+ EfiDebugPrint(-1,"SetFileInfo: File Name %S New Size %x Old Size %x\n", buffer->FileName, buffer->FileSize, fh->DirectoryEntry.Dir_FileSize);
+#endif
+
+ Length = fh->DirectoryEntry.Dir_FileSize - (UINT32)(buffer->FileSize);
+ OldClusterCount = GetClustersRequired(vi, fh->DirectoryEntry.Dir_FileSize);
+ NewClusterCount = GetClustersRequired(vi, (UINT32)(buffer->FileSize));
+
+ if (NewClusterCount < OldClusterCount)
+ ShrinkClusters (vi, FIRSTCLUSTER(fh->DirectoryEntry), NewClusterCount);
+
+ fh->DirectoryEntry.Dir_FileSize = (UINT32)(buffer->FileSize);
+ fh->DirectoryEntry.Dir_Attr |= ATTR_ARCHIVE;
+
+ if (buffer->FileSize == 0 ) {
+ fh->DirectoryEntry.Dir_FstClusLO = 0;
+ fh->DirectoryEntry.Dir_FstClusHI = 0;
+ SetPositionFileHandle (fhi, 0);
+ }
+
+ if (fhi->Position > buffer->FileSize) {
+ SetPositionFileHandle (fhi, 0);
+ }
+ }
+
+// Newsize bigger than Original size?
+ if (fh->DirectoryEntry.Dir_FileSize < buffer->FileSize) {
+
+#ifdef Debug_SetFileInfo
+ EfiDebugPrint(-1,"SetFileInfo: File Name %S New Size %x Old Size %x\n", buffer->FileName, buffer->FileSize, fh->DirectoryEntry.Dir_FileSize);
+#endif
+
+ Status = CheckFileWrite (fhi, FALSE);
+
+ if (EFI_ERROR(Status)) return Status;
+
+// Get the Size in Bytes to be grown
+ Length = (UINT32) (buffer->FileSize) - fh->DirectoryEntry.Dir_FileSize;
+ Status = ExtendFile (fhi, Length);
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+// Update New File Size
+ fh->DirectoryEntry.Dir_FileSize = (UINT32)(buffer->FileSize);
+
+ }
+
+
+ Status = UpdateDirListFromFHDir(fh);
+ fhi->pFH->DirEntryChanged = FALSE;
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: UpdateDirListFromFHDir
+//
+// Description: Updates directory list from file handle directory entry
+//
+// Parameters: FILE_HANDLE *fh - Pointer to file handle structure
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S): Updates DIR list from FH Directory Entry and also writes
+// to the disk.
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+UpdateDirListFromFHDir (
+ FILE_HANDLE *fh
+)
+{
+ EFI_STATUS Status;
+ DIR_ENTRY_LIST *Del;
+ UINT32 Sector, SectorOffset, Position;
+ UINT8 TempDirEntry[32];
+ UINT32 TempOffset, TempSector;
+ UINTN i;
+
+#ifdef Debug_CloseFileHandle
+// EfiDebugPrint(-1,"Update Dir Entry: %s, Dir Cluster %x, Dir Offset %x\n", fh->FileNameLFN, fh->DirCluster, fh->DirOffset);
+#endif
+
+ Status = LocateDel (fh->Parent->DirList.pHead, fh->DirCluster, fh->DirOffset, &Del, &Position);
+
+ if (!EFI_ERROR(Status)) {
+ pBS->CopyMem (&(Del->DirectoryEntry), &fh->DirectoryEntry, sizeof(DIR_ENTRY_32));
+ Del->Cluster = fh->DirCluster;
+ Del->Offset = fh->DirOffset;
+ Del->SlotNumber = fh->SlotNumber;
+ }
+
+ GetSectorAddressDir(fh->Parent, fh->DirCluster, fh->DirOffset, &Sector, &SectorOffset);
+
+ if (fh->DirectoryEntry.Dir_Name[0] == DIR_ENTRY_ERASE) {
+ TempSector = Sector;
+ TempOffset = SectorOffset;
+
+ if (TempOffset == 0) {
+ TempSector--;
+ TempOffset = fh->VolumeInterface->VolumeBPB.BPB_BytePerSec;
+ }
+
+ for (i = 0; i < MAX_LFN_SLOTS; i++) {
+ TempOffset -= sizeof(DIR_ENTRY_LFN);
+ Status = FsReadMedia (fh->VolumeInterface, (void *)&TempDirEntry, TempSector, TempOffset, sizeof(DIR_ENTRY_32), DIRECTORY_REGION);
+
+ if (TempDirEntry[11] == (ATTR_LONG_NAME)) {
+ TempDirEntry[0] = DIR_ENTRY_ERASE; // Mark long entry erased.
+ Status = FsWriteMedia (fh->VolumeInterface, (void *)&TempDirEntry, TempSector, TempOffset, sizeof(DIR_ENTRY_32), DIRECTORY_REGION);
+
+ } else break;
+
+ if (TempOffset == 0) {
+ TempSector--;
+ TempOffset = fh->VolumeInterface->VolumeBPB.BPB_BytePerSec;
+ }
+ }
+ }
+
+ return FsWriteMedia (fh->VolumeInterface, (void *)&fh->DirectoryEntry, Sector,SectorOffset, sizeof(DIR_ENTRY_32), DIRECTORY_REGION);
+}
+
+
+//**********************************************************************
+//<AMI_PHDR_START>
+//
+// Procedure: LocateDel
+//
+// Description:
+//
+// Input:
+//
+// Output:
+//
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//<AMI_PHDR_END>
+//**********************************************************************
+EFI_STATUS
+LocateDel (
+ DLINK *dlink,
+ UINT32 Cluster,
+ UINT32 ClusterOffset,
+ DIR_ENTRY_LIST **Del,
+ UINT32 *Position
+)
+{
+
+ EFI_STATUS Status = EFI_NOT_FOUND;
+// DLINK *dlink = fh->Parent->DirList.pHead;
+ DIR_ENTRY_LIST *del;
+
+ *Del = NULL;
+ *Position = 0;
+
+// Copy this info to DIR_LIST if Present
+ for ( ; dlink; dlink = dlink->pNext, ++*Position) {
+ del = OUTTER(dlink, DirLink, DIR_ENTRY_LIST);
+
+// if (del->Cluster == fh->DirCluster && del->Offset == fh->DirOffset) {
+ if (del->Cluster == Cluster && del->Offset == ClusterOffset) {
+ *Del = del;
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SetSystemInfo
+//
+// Description: Sets the information in a volume label
+//
+// Parameters: VOLUME_INFO *vi - Pointer to volume info structure
+// UINTN *BufferSize - Pointer to size of buffer
+// VOID *Buffer - Ponter to buffer containing new data
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SetSystemInfo (
+ IN VOLUME_INFO *vi,
+ IN UINTN BufferSize,
+ OUT EFI_FILE_SYSTEM_INFO *Buffer
+)
+{
+
+ EFI_STATUS Status;
+ EFI_FILE_SYSTEM_INFO *buffer = Buffer;
+ UINT32 Length = (UINT32)Wcslen(Buffer->VolumeLabel) + 2;
+
+#ifdef Debug_SetSystemInfo
+ Length += EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO, VolumeLabel);
+
+ EfiDebugPrint(-1,"SetSystemInfo: VolumeLabel %s, BufferSize %x BufferRequired %x\n", Buffer->VolumeLabel, BufferSize, Length);
+ EfiDebugPrint(-1,"Size %lx, ReadOnly %x, VolumeSize %lx, FreeSpace %lx, BlockSize %x\n", Buffer->Size, Buffer->ReadOnly, Buffer->VolumeSize, Buffer->FreeSpace, Buffer->BlockSize);
+#endif
+
+ if (BufferSize < (EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_INFO, VolumeLabel) + 2) || buffer->Size > BufferSize) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+// if (BufferSize < Length) return EFI_BAD_BUFFER_SIZE;
+
+// Only Volume Label can be set
+ Status = SetVolumeLabel (vi, Length, &Buffer->VolumeLabel);
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SetVolumeLabel
+//
+// Description: Updates the label on a volume
+//
+// Parameters: VOLUME_INFO *vi - Pointer to volume info structure
+// UINTN *BufferSize - Pointer to size of buffer
+// VOID *Buffer - Ponter to buffer containing new label
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SetVolumeLabel (
+ IN VOLUME_INFO *vi,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+)
+{
+
+ EFI_STATUS Status;
+ UINT8 VolumeLabel[12];
+ UINT32 Sector, SectorOffset, Length;
+ FILE_HANDLE *fh = vi->RootFH, *fh1;
+ DLINK *dlink;
+ DIR_ENTRY_LIST *del;
+ UINT8 i;
+
+// Convert the Unicode string to English
+// Shell Doen't support remove of LABEL right now.
+// if (!BufferSize ) return EFI_BAD_BUFFER_SIZE;
+
+ Length = (UINT32)Wcslen(Buffer) * sizeof (CHAR16) + 2;
+
+#ifdef Debug_SetVolumeLabel
+ EfiDebugPrint(-1,"SetVolumeLabel: VolumeLabel %s BufferSize %x Length %x\n", Buffer, BufferSize, Length);
+#endif
+
+ Length = EFI_FIELD_OFFSET(EFI_FILE_SYSTEM_VOLUME_LABEL, VolumeLabel);
+
+ if (BufferSize < Length + 2) return EFI_BAD_BUFFER_SIZE;
+
+ MemSet(VolumeLabel, 11, 0x20); // Fill short name with spaces
+ vi->UnicodeCollationInterface->StrToFat (vi->UnicodeCollationInterface,
+ Buffer,
+ 11,
+ VolumeLabel);
+ VolumeLabel[11] = 0;
+
+// Update volume Label in vi->Volume
+ if (Strlen(VolumeLabel) > 11) return EFI_BAD_BUFFER_SIZE;
+
+ vi->UnicodeCollationInterface->FatToStr(vi->UnicodeCollationInterface, 11, VolumeLabel, vi->VolumeID);
+
+ for (i=0; i<11; i++) {
+ if (vi->VolumeID[i] == 0x20) break;
+ }
+
+ vi->VolumeID[i] = 0;
+ vi->ValidVolumeID = TRUE;
+
+// Check if Volume ID Directory Entry is present. If so Modify it.
+ if (!fh->DirList.pHead) ReadAllDirectoryEntries (fh);
+
+ dlink = fh->DirList.pHead;
+ Status = EFI_NOT_FOUND;
+
+ for ( ; dlink; dlink = dlink->pNext) {
+ del = OUTTER(dlink, DirLink, DIR_ENTRY_LIST);
+
+ if ((del->DirectoryEntry.Dir_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) == ATTR_VOLUME_ID) {
+
+ pBS->CopyMem(&del->DirectoryEntry.Dir_Name, VolumeLabel, 11);
+
+// Update LastAcc date and Wrtdate/Time and the Attribute
+ UpdateAccAndWriteTime (del);
+ del->DirectoryEntry.Dir_Attr |= ATTR_ARCHIVE;
+
+ if (VolumeLabel[0] == 0x20) del->DirectoryEntry.Dir_Name[0] = 0xE5;
+
+ GetSectorAddressDir (fh, del->Cluster, del->Offset, &Sector, &SectorOffset);
+ Status = FsWriteMedia (vi, (void *)&del->DirectoryEntry, Sector, SectorOffset, sizeof(DIR_ENTRY_32), DIRECTORY_REGION);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (VolumeLabel[0] == 0x20) RemoveDirList(fh, del);
+
+ break;
+ }
+ }
+
+
+ if (Status == EFI_NOT_FOUND && VolumeLabel[0] != 0x20) {
+ fh1 = 0;
+ CreateDirectoryEntry (fh, vi->VolumeID, &fh1, ATTR_VOLUME_ID |ATTR_ARCHIVE);
+
+ if (fh1) RemoveFH(fh1); // FILE_HANDLE Created is not needed.
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetFileInfoFromFH
+//
+// Description: Returns information on a file from it's handle
+//
+// Parameters: FILE_HANDLE_INSTANCE *fh1 - Pointer to file handle
+// instance
+// UINTN *BufferSize - Pointer to size of buffer
+// VOID *Buffer - Ponter to buffer for returned data
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetFileInfoFromFH (
+ FILE_HANDLE *Pfh,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+)
+{
+ VOLUME_INFO *vi = Pfh->VolumeInterface;
+ EFI_FILE_INFO *buffer = Buffer;
+ UINTN Length;
+
+ Length = (UINT32)Wcslen(Pfh->FileNameLFN) * sizeof (CHAR16) + 2;
+ Length += EFI_FIELD_OFFSET(EFI_FILE_INFO,FileName);
+
+// Length += sizeof(EFI_FILE_INFO);
+ if (*BufferSize < Length) {
+#ifdef Debug_GetFileInfo_1
+ EfiDebugPrint(-1,"GetFileInfo: %S BufferSize %x LengthRequired %x Status: EFI_BUFFER_TOO_SMALL\n", Pfh->FileNameLFN, *BufferSize, Length + 2);
+#endif
+ *BufferSize = Length;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *BufferSize = Length;
+ buffer->Size = Length;
+ buffer->FileSize = Pfh->DirectoryEntry.Dir_FileSize;
+ buffer->PhysicalSize = buffer->FileSize;
+
+ Length = (Pfh->DirectoryEntry.Dir_FileSize % vi->BytesPerCluster);
+
+ if (Length)
+ buffer->PhysicalSize += vi->BytesPerCluster - (Pfh->DirectoryEntry.Dir_FileSize % vi->BytesPerCluster);
+
+ FatToEfiTime (&(buffer->CreateTime), Pfh->DirectoryEntry.Dir_CrtDate, Pfh->DirectoryEntry.Dir_CrtTime);
+ FatToEfiTime (&(buffer->LastAccessTime), Pfh->DirectoryEntry.Dir_LstAccDate, 0);
+ FatToEfiTime (&(buffer->ModificationTime), Pfh->DirectoryEntry.Dir_WrtDate, Pfh->DirectoryEntry.Dir_WrtTime);
+ buffer->Attribute = Pfh->DirectoryEntry.Dir_Attr & EFI_FILE_VALID_ATTR;
+ Wcscpy (buffer->FileName, Pfh->FileNameLFN);
+#ifdef Debug_GetFileInfo_0
+ EfiDebugPrint(-1,"GetFileInfo: %S File Size %lx \n", Pfh->FileNameLFN, buffer->FileSize);
+#endif
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FatToEfiTime
+//
+// Description: Converts time/date in FAT format to EFI format
+//
+// Parameters: EFI_TIME *EfiTime - Ponter to returned time in EFI format
+// UINT16 Date - Date in FAT format
+// UINT16 Time - Time in FAT format
+//
+// Return value: None
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+FatToEfiTime (
+ EFI_TIME *EfiTime,
+ UINT16 Date,
+ UINT16 Time
+)
+{
+
+ EfiTime->Year = (UINT16) (((FAT_DATE*) &Date)->Year + 1980);
+ EfiTime->Month = (UINT8 ) ((FAT_DATE*) &Date)->Month;
+ EfiTime->Day = (UINT8) ((FAT_DATE*) &Date)->Day;
+ EfiTime->Hour = (UINT8) ((FAT_TIME*) &Time)->Hour;
+ EfiTime->Minute = (UINT8) ((FAT_TIME*) &Time)->Minute;
+ EfiTime->Second = (UINT8) ((FAT_TIME*) &Time)->DoubleSecond;
+ EfiTime->Nanosecond = 0;
+ EfiTime->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+ EfiTime->Pad1 = 0;
+ EfiTime->Daylight = 0;
+ EfiTime->Pad2 = 0;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: EfiToFatTime
+//
+// Description: Converts date/time in EFI format to FAT format
+//
+// Parameters: EFI_TIME EfiTime - Time in EFI format
+// UINT16 *Date - Pointer to returned date in FAT format
+// UINT16 *Time - Pointer to returned time in FAT format
+//
+// Return value: None
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+EfiToFatTime (
+ EFI_TIME EfiTime,
+ UINT16 *Date,
+ UINT16 *Time
+)
+{
+
+ ((FAT_DATE*)Date)->Year = EfiTime.Year - 1980;
+ ((FAT_DATE*)Date)->Month = EfiTime.Month;
+ ((FAT_DATE*)Date)->Day = EfiTime.Day;
+ ((FAT_TIME*)Time)->Hour = EfiTime.Hour;
+ ((FAT_TIME*)Time)->Minute = EfiTime.Minute;
+ ((FAT_TIME*)Time)->DoubleSecond = EfiTime.Second;
+
+}
+
+// Special string copy for volume labels.
+// Skips the "." that ExtractShortFileName puts in. Replaces Wcscpy().
+VOID Labcpy(
+ CHAR16 *string1,
+ CHAR16 * string2
+)
+{
+ while (*string2) {
+ if ((CHAR8)*string2 != '.') {
+ *string1++ = *string2++;
+
+ } else *string2++;
+ }
+}
+
+// Special string length counter for volume labels.
+// Skips the "." that ExtractShortFileName puts in. Replaces Wcslen().
+UINTN Lablen(
+ CHAR16 *string
+)
+{
+ UINTN length=0;
+
+ while (*string++) {
+ if ((CHAR8)*string != '.') length++;
+ }
+
+ return length;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FindNextTpl
+//
+// Description: Returns the higher of a desired TPL level or the current
+// next higher TPL level
+//
+// Parameters: EFI_TPL TplLevel -- desired level to raise to
+//
+// Return Value: EFI_TPL
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_TPL
+FindNextTpl (
+ EFI_TPL TplLevel
+ )
+{
+ EFI_TPL NextTpl;
+
+ NextTpl = pBS->RaiseTPL (TPL_HIGH_LEVEL);
+ pBS->RestoreTPL(NextTpl);\
+ if(NextTpl<=TplLevel) NextTpl = TplLevel;
+ return NextTpl;
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2011, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
diff --git a/Core/EM/FileSystem/MediaAccess.c b/Core/EM/FileSystem/MediaAccess.c
new file mode 100644
index 0000000..f87fb15
--- /dev/null
+++ b/Core/EM/FileSystem/MediaAccess.c
@@ -0,0 +1,1479 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2011, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Core/Modules/FileSystem/MediaAccess.c 11 10/24/11 10:55a Artems $
+//
+// $Revision: 11 $
+//
+// $Date: 10/24/11 10:55a $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Core/Modules/FileSystem/MediaAccess.c $
+//
+// 11 10/24/11 10:55a Artems
+// EIP 73254: Remove "magic number" from source
+//
+// 10 5/05/11 3:44p Pats
+// [TAG] - EIP 58999
+// [Category]- BUG FIX
+// [Severity]- Major
+// [Symptom] - Cannot launch Shell from USB Filesystem device in Debug
+// mode with latest Filesystem driver.
+// [RootCause] - Functions using DISKIO were raising TPL to a fixed level.
+// [Solution] - Modified above functions to check for the higher of the
+// fixed level or current level.
+// [Files] - Info.c, MediaAccess.c, Open.c, FileSystem.h
+//
+// 9 1/06/11 5:55p Oleksiyy
+// [TAG] EIP28607
+// [Category] Improvement
+// [Description] System was hanging for some time if Floppy Media
+// removed while writing in meda in progress.
+// EFI_TPL_CALLBACK priority level rised during media related calls.
+//
+// [Files] DiskIo.c, Info.c, MediaAccess.c, Open.c, Partition.c
+//
+// 8 7/02/09 5:47p Pats
+// Updated to latest coding standard. No code changes.
+//
+// 7 4/13/07 7:07p Pats
+// Edited to conform with coding standards. No code changes.
+//
+// 6 8/25/06 12:10p Felixp
+// Bug fix in GetNextCompName
+//
+// 5 8/25/06 12:06p Felixp
+// Bug fix in GetNextCompName
+//
+// 5 11/03/05 2:17p Srinin
+// Fixed VC7.1 warning msg.
+//
+// 4 7/06/05 11:25a Pats
+// Modified function RemoveFH to delete child Dlist only if the parent is
+// valid. Fixes problem of booting to floppy failing under certain
+// conditions.
+//
+// 2 5/27/05 10:01a Srinin
+// Fix for Media change and SCT long file name handling.
+//
+// 1 4/26/05 6:05p Srinin
+//
+//
+//
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: MediaAccess.c
+//
+// Description: Handles all Media access
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+//----------------------------------------------------------------------
+
+#include "FileSystem.h"
+#define EFI_TPL_CALLBACK TPL_CALLBACK
+//----------------------------------------------------------------------
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FsReadMedia
+//
+// Description: Reads a specified no. of bytes from media at a specified
+// location (abs. sector and offset in sector)
+//
+// Parameters:
+// VOLUME_INFO *vi, Pointer to Volume Info structure
+// UINT8 *Buffer, Valid Buffer pointer should be Passed
+// UINT64 Sector, Start Sector number
+// UINT32 Offset, Offset within the sector to read from
+// UINT32 ByteCount, Number of bytes to read from the offset
+// REGIONS DataRegion See descriptions of REGION. Primarily
+// used to dtermine caching algorithm.
+//typedef enum {
+// RESERVED_REGION,
+// FAT_REGION,
+// DIRECTORY_REGION,
+// DATA_REGION
+//} REGIONS;
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FsReadMedia (
+ VOLUME_INFO *vi,
+ UINT8 *Buffer,
+ UINT64 Sector,
+ UINT32 Offset,
+ UINT32 ByteCount,
+ REGIONS DataRegion
+)
+{
+
+ EFI_STATUS Status;
+ UINT64 AbsoluteOffset;
+ UINT8 *cBuffer;
+ UINT32 cBufferLength;
+ CACHE_HEADER *ch = NULL;
+
+// Convert Sector number to Absolute offset.
+ AbsoluteOffset = Shl64 (Sector, vi->BytesPerSecPowerof2) + Offset;
+
+ if (DataRegion == DATA_REGION) {
+ Status= vi->DiskIo->ReadDisk (vi->DiskIo, vi->MediaID, AbsoluteOffset, ByteCount, Buffer);
+
+ if (EFI_ERROR(Status)) HandleDiskIoError(vi, Status);
+
+ return Status;
+ }
+
+// DATA_REGION is FAT or DIRECTORY
+ for ( ; ByteCount; ) {
+ Status = CheckCached(vi, AbsoluteOffset, ByteCount, &cBuffer, &cBufferLength, &ch, DataRegion);
+
+ if (EFI_ERROR(Status)) {
+ HandleDiskIoError(vi, Status);
+ return Status;
+ }
+
+ pBS->CopyMem(Buffer, cBuffer, cBufferLength);
+ ByteCount -= cBufferLength;
+ Buffer += cBufferLength;
+ AbsoluteOffset += cBufferLength;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: CheckCached
+//
+// Description: Checks to see if the media data we're working with is
+// cached
+//
+// Parameters:
+// VOLUME_INFO *vi, Pointer to volume info structure
+// UINT64 AbsoluteOffset, Absolute offset of data
+// UINT32 ByteCount, Byte Count of data
+// UINT8 **cBuffer, Cache buffer
+// UINT32 *cBufferLength Cache buffer length
+// CACHE_HEADER **ch Cache header stucture
+// REGIONS DataRegion See descriptions of REGION. Primarily
+// used to dtermine caching algorithm.
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+CheckCached (
+ VOLUME_INFO *vi,
+ UINT64 AbsoluteOffset,
+ UINT32 ByteCount,
+ UINT8 **cBuffer,
+ UINT32 *cBufferLength,
+ CACHE_HEADER **ch,
+ REGIONS DataRegion
+)
+{
+
+ EFI_STATUS Status;
+ UINT32 Mask;
+ UINT64 AlignedAbsoluteOffset;
+ UINT32 AlignedBytecount;
+ CACHE_HEADER *ch1 = NULL;
+
+ if (!IsCacheHit(vi, DataRegion, AbsoluteOffset, ByteCount, cBuffer, cBufferLength, &ch1)) {
+
+// No match found for AbsoluteOffset
+ Mask = 0x80000000;
+ Mask -= vi->BytesPerCluster;
+ Mask |= 0xf0000000;
+ AlignedAbsoluteOffset = AbsoluteOffset;
+ *(UINT32 *)&AlignedAbsoluteOffset = *(UINT32 *)&AbsoluteOffset & Mask;
+ AlignedBytecount = vi->BytesPerCluster;
+
+ CreateSpaceforCache (vi, AlignedBytecount, DataRegion, &ch1);
+ Status= vi->DiskIo->ReadDisk (vi->DiskIo, vi->MediaID, AlignedAbsoluteOffset, AlignedBytecount, ch1->Buffer);
+
+ if (EFI_ERROR(Status)) {
+ HandleDiskIoError(vi, Status);
+ return Status;
+ }
+
+ ch1->AbsoluteOffset = AlignedAbsoluteOffset;
+ ch1->AbsoluteOffsetEnd = AlignedAbsoluteOffset + AlignedBytecount;
+ ch1->DIRTY_FLAG = FALSE;
+ ch1->DataRegion = DataRegion;
+ DListDelete (&(vi->CacheList), &(ch1->CacheLink));
+ DListAdd(&(vi->CacheList), &(ch1->CacheLink));
+
+#ifdef Debug_Caching
+ EfiDebugPrint(-1,"Caching Offset %lx End Offset %lx MemAddress %x\n", ch1->AbsoluteOffset, ch1->AbsoluteOffsetEnd, ch1->Buffer);
+#endif
+
+ if (!(IsCacheHit(vi, DataRegion, AbsoluteOffset, ByteCount, cBuffer, cBufferLength, &ch1))) {
+ Status = EFI_DEVICE_ERROR;
+ ASSERT_EFI_ERROR(Status); // something wrong in the algorithm
+ }
+ }
+
+ *ch = ch1;
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: IsCacheHit
+//
+// Description:
+//
+// Parameters:
+// VOLUME_INFO *vi, Pointer to volume info structure
+// UINT64 AbsoluteOffset, Absolute offset of data
+// UINT32 ByteCount, Byte Count of data
+// UINT8 **cBuffer, Cache buffer
+// UINT32 *cBufferLength Cache buffer length
+//
+// Return value: BOOLEAN - True if cache hit
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+BOOLEAN
+IsCacheHit (
+ VOLUME_INFO *vi,
+ REGIONS DataRegion,
+ UINT64 AbsoluteOffset,
+ UINT32 ByteCount,
+ UINT8 **cBuffer,
+ UINT32 *cBufferLength,
+ CACHE_HEADER **ch1
+)
+{
+
+ DLINK *dlink = vi->CacheList.pTail;
+ CACHE_HEADER *ch;
+
+ for ( ; dlink; ) {
+
+ ch = OUTTER(dlink, CacheLink, CACHE_HEADER);
+
+ if (ch->DataRegion == DataRegion && AbsoluteOffset >= ch->AbsoluteOffset && AbsoluteOffset < ch->AbsoluteOffsetEnd) {
+
+ *cBuffer = (UINT8 *)(ch->Buffer + (UINT32) (AbsoluteOffset - ch->AbsoluteOffset));
+ *cBufferLength = (UINT32) (ch->AbsoluteOffsetEnd - AbsoluteOffset);
+
+ if (*cBufferLength > ByteCount) *cBufferLength = ByteCount;
+
+// Important. Remove the link and add it to the end.
+// As least used data area will be moved to the front of the LIST
+ DListDelete (&(vi->CacheList), &(ch->CacheLink));
+ DListAdd(&(vi->CacheList), &(ch->CacheLink));
+ *ch1 = ch;
+ return TRUE;
+ }
+
+ dlink = dlink->pPrev;
+
+ }
+
+ return FALSE;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: CreateSpaceforCache
+//
+// Description: Creates space on media for cache
+//
+// Parameters:
+// VOLUME_INFO *vi, Volume info structure
+// UINT32 ByteCount, Bytes of space to create
+// REGIONS DataRegion See descriptions of REGION. Primarily used
+// to dtermine caching algorithm.
+//
+// Return value: None
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+void
+CreateSpaceforCache (
+ VOLUME_INFO *vi,
+ UINT32 ByteCount,
+ REGIONS DataRegion,
+ CACHE_HEADER **ch1
+)
+{
+
+ EFI_STATUS Status;
+ DLINK *dlink = vi->CacheList.pHead;
+ CACHE_HEADER *ch;
+
+ for ( ; dlink; ) {
+
+ ch = OUTTER(dlink, CacheLink, CACHE_HEADER);
+ dlink = dlink->pNext;
+
+ if (ch->DataRegion != DataRegion) continue;
+
+ if (ch->DIRTY_FLAG) {
+ Status= vi->DiskIo->WriteDisk (vi->DiskIo, vi->MediaID, ch->AbsoluteOffset, (UINT32) (ch->AbsoluteOffsetEnd - ch->AbsoluteOffset), ch->Buffer);
+
+ if (EFI_ERROR(Status)) HandleDiskIoError(vi, Status);
+
+ ch->DIRTY_FLAG = FALSE;
+ }
+
+ *ch1 = ch;
+ break;
+
+ }
+
+ return;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FsWriteMedia
+//
+// Description: Writes a specified no. of bytes to media at a specified
+// location (abs. sector and offset in sector)
+//
+// Parameters:
+// VOLUME_INFO *vi,
+// UINT8 *Buffer, Valid Buffer pointer should be Passed
+// UINT64 Sector, Start Sector number
+// UINT32 Offset, Offset within the sector to read from
+// UINT32 ByteCount, Number of bytes to read from the offset
+// REGIONS DataRegion See descriptions of REGION. Primarily used
+// to dtermine caching algorithm.
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FsWriteMedia (
+ VOLUME_INFO *vi,
+ UINT8 *Buffer,
+ UINT64 Sector,
+ UINT32 Offset,
+ UINT32 ByteCount,
+ REGIONS DataRegion
+)
+{
+
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT64 AbsoluteOffset;
+ UINT8 *cBuffer = NULL;
+ UINT32 cBufferLength;
+ CACHE_HEADER *ch = NULL;
+
+// Convert Sector number to Absolute offset.
+ AbsoluteOffset = Shl64 (Sector, vi->BytesPerSecPowerof2) + Offset;
+
+ if (DataRegion == DATA_REGION) {
+ Status= vi->DiskIo->WriteDisk (vi->DiskIo, vi->MediaID, AbsoluteOffset, ByteCount, Buffer);
+
+ if (EFI_ERROR(Status)) HandleDiskIoError(vi, Status);
+
+ return Status;
+ }
+
+//###DEBUG
+ /*
+ // Check for cache hit
+ do {
+ if (!IsCacheHit (vi, DataRegion, AbsoluteOffset, ByteCount, &cBuffer, &cBufferLength, &ch)) {
+ // Cache the region, before writing it
+ for (AbsoluteOffset1 = AbsoluteOffset, ByteCount1 = ByteCount; ByteCount1; ) {
+ Status = CheckCached(vi, AbsoluteOffset1, ByteCount1, &cBuffer1, &cBufferLength1, DataRegion);
+ if (EFI_ERROR(Status)) {
+ HandleDiskIoError(vi, Status);
+ return Status;
+ }
+ ByteCount1 -= cBufferLength1;
+ AbsoluteOffset1 += cBufferLength1;
+ }
+ continue;
+ }
+ // Copy i/p buffer to the cache. Update the flag
+ pBS->CopyMem(cBuffer, Buffer, cBufferLength);
+ Buffer += cBufferLength;
+ ByteCount -= cBufferLength;
+ ch->DIRTY_FLAG = TRUE;
+ }
+ while (ByteCount);
+ */
+//###DEBUG END
+ do {
+ Status = CheckCached(vi, AbsoluteOffset, ByteCount, &cBuffer, &cBufferLength, &ch, DataRegion);
+
+ if (EFI_ERROR(Status)) {
+ HandleDiskIoError(vi, Status);
+ return Status;
+ }
+
+ pBS->CopyMem(cBuffer, Buffer, cBufferLength);
+ ByteCount -= cBufferLength;
+ Buffer += cBufferLength;
+ AbsoluteOffset += cBufferLength;
+ ch->DIRTY_FLAG = TRUE;
+ } while (ByteCount);
+
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: HandleDiskIoError
+//
+// Description: Handles disk read/write error
+//
+// Parameters:
+// VOLUME_INFO *vi, Volume Info Structure
+//
+// Return value: None
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+void
+HandleDiskIoError (
+ VOLUME_INFO *vi,
+ EFI_STATUS Status
+
+)
+{
+
+//###DEBUG
+// We may need some error handling here
+//###DEBUG END
+ if (Status == EFI_MEDIA_CHANGED || Status == EFI_NO_MEDIA)
+ FreeUpResources (vi, Status);
+
+ return;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FreeUpResources
+//
+// Description: Frees up resouces when volumes opened/closed
+//
+// Parameters:
+// VOLUME_INFO *vi, Volume info structure
+// EFI_STATUS Status Status to update file handles with
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FreeUpResources (
+ VOLUME_INFO *vi,
+ EFI_STATUS Status
+)
+{
+
+ DLINK *dlink = vi->OpenFIs.pHead;
+ FILE_HANDLE *fh;
+ FILE_HANDLE_INSTANCE *fhi;
+ CACHE_HEADER *ch;
+
+
+// Go through the list of Open File Handles Instances and update the status
+ while (dlink) {
+ fhi = OUTTER(dlink, ViFILink, FILE_HANDLE_INSTANCE);
+ fhi->HandleInstanceStatus = Status;
+ fhi->pFH = NULL;
+ DListDelete (&(vi->OpenFIs), &(fhi->ViFILink));
+
+ if (!dlink->pNext) break;
+
+ dlink = dlink->pNext;
+ }
+
+
+// Release all File_Handles/DirList
+ dlink = vi->OpenFHs.pHead;
+
+ while (dlink) {
+ fh = OUTTER(dlink, ViFHLink, FILE_HANDLE);
+ fh->InstancesCount = 0;
+ dlink = dlink->pNext;
+
+ if (fh->DirList.pHead) RemoveAllDirList(fh);
+
+ if (fh->ROOTDIR) vi->RootFH = NULL;
+
+ RemoveFH(fh);
+ }
+
+// Update the Status in VOLUME_INFO
+ vi->VolumeStatus = Status;
+ vi->ValidVolumeID = FALSE;
+
+ if (vi->FileSystemName) pBS->FreePool (vi->FileSystemName);
+
+ vi->FileSystemName = NULL;
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+ dlink = vi->CacheList.pTail;
+
+ if (!dlink) return FALSE;
+
+ for ( ; dlink; ) {
+ ch = OUTTER(dlink, CacheLink, CACHE_HEADER);
+ ch->AbsoluteOffset = 0;
+ ch->AbsoluteOffsetEnd = 0;
+ ch->DIRTY_FLAG = FALSE;
+ dlink = dlink->pPrev;
+ }
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ValidateCurrentStatus
+//
+// Description: Validates status if file handle instance
+//
+// Parameters:
+// FILE_HANDLE_INSTANCE *fhi
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+ValidateCurrentStatus (
+ FILE_HANDLE_INSTANCE *fhi
+)
+{
+ FILE_HANDLE *Pfh = fhi->pFH;
+
+ if (fhi->HandleInstanceStatus != EFI_SUCCESS) return fhi->HandleInstanceStatus;
+
+ if (!Pfh) return EFI_NOT_FOUND;
+
+ if (Pfh->HandleStatus != EFI_SUCCESS) return Pfh->HandleStatus;
+
+ if (EFI_ERROR(Pfh->VolumeInterface->VolumeStatus)) return Pfh->VolumeInterface->VolumeStatus;
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetPositionFileHandle
+//
+// Description: Gets position in an open file handle
+//
+// Parameters:
+// IN EFI_FILE_PROTOCOL *This,
+// IN UINT64 *Position
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetPositionFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 *Position
+)
+{
+
+ EFI_STATUS Status;
+ FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)This;
+ FILE_HANDLE *Pfh = fhi->pFH;
+ VOLUME_INFO *vi = Pfh->VolumeInterface;
+
+ Status = ValidateCurrentStatus (fhi);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (fhi->HandleInstanceStatus | Pfh->HandleStatus | vi->VolumeStatus) return EFI_UNSUPPORTED;
+
+ if (Pfh->DirectoryEntry.Dir_Attr & (ATTR_VOLUME_ID | ATTR_DIRECTORY)) return EFI_UNSUPPORTED;
+
+ *Position = fhi->Position;
+
+#ifdef Debug_GetPosition
+ EfiDebugPrint(-1,"GetPosition: File Name %s Position %x\n", Pfh->FileNameLFN, buffer->FileSize, Position);
+#endif
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SetPositionFileHandleThis
+//
+// Description: Sets position in current file handle instance
+//
+// Parameters:
+// IN EFI_FILE_PROTOCOL *This,
+// IN UINT64 Position
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SetPositionFileHandleThis (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+)
+{
+ EFI_TPL SaveTpl;
+ EFI_TPL NextTpl;
+ EFI_STATUS Status;
+ FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)This;
+
+ Status = ValidateCurrentStatus (fhi);
+
+ if (EFI_ERROR(Status)) return Status;
+ NextTpl = FindNextTpl (EFI_TPL_CALLBACK);
+ SaveTpl = pBS->RaiseTPL (NextTpl);
+ Status = SetPositionFileHandle (fhi, Position);
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SetPositionFileHandle
+//
+// Description: Sets position in an open file handle
+//
+// Parameters:
+// IN FILE_HANDLE_INSTANCE *fhi,
+// IN UINT64 Position
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SetPositionFileHandle (
+ IN FILE_HANDLE_INSTANCE *fhi,
+ IN UINT64 Position
+)
+{
+
+ FILE_HANDLE *Pfh = fhi->pFH;
+ VOLUME_INFO *vi = Pfh->VolumeInterface;
+
+#ifdef Debug_SetPosition
+ EfiDebugPrint(-1,"SetPosition: %s Pos %lx", fhi->pFH->FileNameLFN, Position);
+#endif
+
+ if (fhi->HandleInstanceStatus | Pfh->HandleStatus | vi->VolumeStatus) return EFI_UNSUPPORTED;
+
+ if (Pfh->DirectoryEntry.Dir_Attr & ATTR_DIRECTORY) {
+ if (Position != 0) return EFI_UNSUPPORTED;
+ }
+
+ fhi->Position = Position;
+
+//TODO TODO TODO
+// If Position is beyond the filesize, update the file position.
+// For reads issues Device_error. While writing, extend the file.
+//TODO TODO TODO
+
+// Update internal data Area
+ if (fhi->Position == -1) fhi->Position = Pfh->DirectoryEntry.Dir_FileSize;
+
+ if (fhi->Position == 0) {
+ fhi->CurrentCluster = FIRSTCLUSTER(fhi->pFH->DirectoryEntry);
+ fhi->CurrentClusterOffset = 0;
+
+ } else {
+ GetClusterPosition(fhi, fhi->Position, &fhi->CurrentCluster, &fhi->CurrentClusterOffset);
+ }
+
+#ifdef Debug_SetPosition
+ EfiDebugPrint(-1," Clus %x ClusOffset %x\n", fhi->CurrentCluster, fhi->CurrentClusterOffset);
+#endif
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: RemoveFH
+//
+// Description: Romoves file handle (closed file)
+//
+// Parameters:
+// FILE_HANDLE *fh
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+RemoveFH (
+ FILE_HANDLE *fh
+)
+{
+
+ VOLUME_INFO *vi = fh->VolumeInterface;
+
+#ifdef Debug_RemoveFH
+ EfiDebugPrint(-1,"RemoveFH: %s\n", fh->FileNameLFN);
+#endif
+
+// Check if there any open instances for this FH
+ if (fh->InstancesCount) return EFI_ACCESS_DENIED;
+
+// Check if DLIST is NULL.
+ if (fh->DirList.pHead) return EFI_ACCESS_DENIED;
+
+ fsDeAllocateMemory(vi, fh->FileNameLFN);
+ DListDelete (&(vi->OpenFHs), &(fh->ViFHLink));
+
+// Delete child Dlist only if parent is valid.
+ if (fh->Parent) DListDelete (&(fh->Parent->ChildList), &(fh->ChildLink));
+
+ fsDeAllocateMemory(vi, fh);
+
+#ifdef Debug_RemoveFH
+ EfiDebugPrint(-1,"RemoveFH Success\n");
+#endif
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetNextCompName
+//
+// Description: Gets next component name in path
+//
+// Parameters:
+// IN OUT CHAR16 **FileName,
+// IN CHAR16 *NextCompName
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetNextCompName (
+ IN OUT CHAR16 **FileName,
+ IN CHAR16 *NextCompName
+)
+{
+
+ UINT32 Index = 0;
+ NextCompName[Index] = (*FileName)[Index];
+
+ while ((*FileName)[Index] !=0 && (*FileName)[Index] != '\\') {
+ NextCompName[Index] = (*FileName)[Index];
+ Index++;
+
+ if (Index >= MAX_TOTAL_PATH_LENGTH) return EFI_INVALID_PARAMETER;
+ }
+
+ NextCompName[Index] = 0;
+
+// Point *FileName beyond the trailing '\\'
+ if ((*FileName)[Index] == '\\') {
+ Index++;
+ }
+
+// After '\\' it should not be 0.
+ if (Index != 0 && (*FileName)[Index - 1] == '\\' &&
+ (*FileName)[Index] == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *FileName = (*FileName) + Index;
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: fsAllocateMemory
+//
+// Description: Allocates memory for use by file system driver
+//
+// Parameters:
+// VOLUME_INFO *vi
+// VOID **Buffer
+// UINT32 Size
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+fsAllocateMemory (
+ VOLUME_INFO *vi,
+ UINT32 Size,
+ VOID **Buffer,
+ BOOLEAN CLEAR
+)
+{
+
+ EFI_STATUS Status;
+ UINTN Address = (UINTN) Buffer;
+ UINT32 Length;
+
+
+ if (Size <= 1024) {
+ Status = InternalMemAllocate (vi, Size, Buffer, CLEAR);
+ return Status;
+ }
+
+ Status = pBS->AllocatePool (EfiBootServicesData,
+ Size,
+ (VOID**)Buffer);
+
+ Address = (UINTN) *Buffer;
+ Address -=0xc; // Point to the Size
+ Length = *(UINT32 *)Address; // Get the size
+
+ if (Status == EFI_SUCCESS) vi->AllocatedMemorySize += Length;
+
+ if (Status == EFI_SUCCESS && CLEAR) Zeromemory (*Buffer, Size);
+
+#ifdef Debug_Allocatememory
+ EfiDebugPrint(-1,"AllocateMemory : %x Total mememory Allocated : %x\n", Length, vi->AllocatedMemorySize);
+#endif
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: fsDeAllocateMemory
+//
+// Description: De-allocates memory used by file system driver
+//
+// Parameters:
+// VOLUME_INFO *vi,
+// void *Buffer
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+fsDeAllocateMemory (
+ VOLUME_INFO *vi,
+ void *Buffer
+)
+{
+ UINTN Address = (UINTN) Buffer;
+ UINT32 Size;
+ EFI_STATUS Status;
+
+
+ Status = FreeMemory (vi, Buffer);
+
+ if (Status == EFI_SUCCESS) return EFI_SUCCESS;
+
+ Address -=0xc; // Point to the Size
+ Size = *(UINT32 *)Address; // Get the size
+ vi->AllocatedMemorySize -= Size;
+ Status = pBS->FreePool(Buffer);
+
+ if (Status == EFI_SUCCESS) Buffer = NULL;
+
+#ifdef Debug_Allocatememory
+ EfiDebugPrint(-1,"DeAllocateMemory : %x Total mememory Allocated : %x\n", Size, vi->AllocatedMemorySize);
+#endif
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: InternalMemAllocate
+//
+// Description: Adds allocated memory to internal manager
+//
+// Parameters:
+// VOLUME_INFO *vi,
+// UINT32 Size,
+// VOID **Buffer,
+// BOOLEAN CLEAR
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+InternalMemAllocate (
+ VOLUME_INFO *vi,
+ UINT32 Size,
+ VOID **Buffer,
+ BOOLEAN CLEAR
+)
+{
+ EFI_STATUS Status = EFI_OUT_OF_RESOURCES;
+ DLINK *dlink = vi->MemList.pTail;
+ MEM_HEADER *Mem;
+ UINT32 Blocks;
+
+ Blocks = Size / MEMALLOCSIZE;
+
+ if (Size % MEMALLOCSIZE) Blocks++;
+
+ for ( ; ; ) {
+ if (!dlink) {
+ Status = AddBlocktoInternalMemManager (vi);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ dlink = vi->MemList.pTail;
+ }
+
+ Mem = OUTTER(dlink, MemLink, MEM_HEADER);
+ Status = GetMemory (Mem, Blocks, Buffer, CLEAR);
+
+ if (Status == EFI_SUCCESS) return Status;
+
+ dlink = dlink->pPrev;
+ }
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetMemory
+//
+// Description: Gets memory for a buffer
+//
+// Parameters:
+// MEM_HEADER *Mem,
+// UINT32 Blocks,
+// VOID **Buffer,
+// BOOLEAN CLEAR
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetMemory (
+ MEM_HEADER *Mem,
+ UINT32 Blocks,
+ VOID **Buffer,
+ BOOLEAN CLEAR
+)
+{
+ UINT32 i, FreeBlockCounts = 0, StartBlock, Count;
+ UINT8 *MemMap = (UINT8 *)(Mem->AddresMap);
+ EFI_STATUS Status = EFI_NOT_FOUND;
+
+ for (i = 0; i < MEMBLOCKSIZE / MEMALLOCSIZE; i++) {
+ if (!MemMap[i]) {
+ if (!FreeBlockCounts) StartBlock = i;
+
+ FreeBlockCounts++;
+
+ if (FreeBlockCounts >= Blocks) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ } else FreeBlockCounts = 0;
+ }
+
+ if (Status == EFI_SUCCESS) {
+ *Buffer = (void *)(Mem->BufferStart + StartBlock * MEMALLOCSIZE);
+
+ for (i = 0, Count = 1; i < Blocks; i++, StartBlock++, Count++)
+ MemMap[StartBlock] = Count;
+
+ if (CLEAR) Zeromemory (*Buffer, MEMALLOCSIZE * Blocks);
+ }
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FreeMemory
+//
+// Description:
+//
+// Parameters:
+// VOLUME_INFO *Vi,
+// VOID *Buffer
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FreeMemory (
+ VOLUME_INFO *vi,
+ VOID *Buffer
+)
+{
+
+ EFI_STATUS Status = EFI_NOT_FOUND;
+ DLINK *dlink = vi->MemList.pHead;
+ MEM_HEADER *Mem;
+ UINT32 StartBlock, Count;
+
+ for ( ; dlink ; ) {
+ Mem = OUTTER(dlink, MemLink, MEM_HEADER);
+
+ if (Buffer >= (void *)(Mem->BufferStart) && Buffer < (void *)(Mem->BufferEnd)) {
+
+ StartBlock = (UINT32) (((UINTN)Buffer - Mem->BufferStart) / MEMALLOCSIZE);
+
+ Status = EFI_SUCCESS;
+
+ for (Count = 1; ; Count++, StartBlock++)
+ if (((UINT8 *)(Mem->AddresMap))[StartBlock] == Count) ((UINT8 *)(Mem->AddresMap))[StartBlock] = 0;
+
+ else break;
+
+ }
+
+ if (Status == EFI_SUCCESS) break;
+
+ dlink = dlink->pNext;
+ }
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: InternalMemAllocate
+//
+// Description:
+//
+// Parameters:
+// VOLUME_INFO *Vi,
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+AddBlocktoInternalMemManager (
+ VOLUME_INFO *vi
+)
+{
+ EFI_STATUS Status;
+ UINT32 *Buffer;
+ MEM_HEADER *Mem;
+ Status = pBS->AllocatePool (EfiBootServicesData,
+ MEMBLOCKSIZE + MEMBLOCKSIZE / MEMALLOCSIZE,
+ (VOID**)&Buffer);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ vi->AllocatedMemorySize += MEMBLOCKSIZE + MEMBLOCKSIZE / MEMALLOCSIZE;
+
+ Status = pBS->AllocatePool (EfiBootServicesData,
+ sizeof (MEM_HEADER),
+ (VOID**)&Mem);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ vi->AllocatedMemorySize += sizeof (MEM_HEADER);
+
+ Mem->AddresMap = (UINTN) Buffer;
+ Mem->AddresMapLength = MEMBLOCKSIZE / MEMALLOCSIZE;
+ Mem->BufferStart = (UINTN) (Buffer) + MEMBLOCKSIZE / MEMALLOCSIZE;
+ Mem->BufferEnd = Mem->BufferStart + MEMBLOCKSIZE;
+ DListAdd(&(vi->MemList), &(Mem->MemLink));
+ Zeromemory (Buffer, MEMBLOCKSIZE / MEMALLOCSIZE);
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FatLfnIsValid
+//
+// Description: Checks for valid long file name
+//
+// Parameters:
+// CHAR16 *Name
+//
+// Return value: BOOLEAN - True if long file name is valid
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+BOOLEAN
+FatLfnIsValid (
+ CHAR16 *Name
+)
+{
+ CHAR16 *p1, *p2;
+ BOOLEAN IsAllDot;
+
+ IsAllDot = TRUE;
+
+ p1 = Name;
+
+ do {
+ if (*p1 != '.') {
+ IsAllDot = FALSE;
+ }
+
+ p1++;
+ } while (*p1);
+
+ if (IsAllDot) {
+ return TRUE;
+ }
+
+ //
+ // Strip off starting/trailing spaces and trailing periods
+ //
+ for (p1 = Name; *p1 && *p1 == ' '; p1++) {
+ ;
+ }
+
+ p2 = Name;
+
+ while (*p1) {
+ *p2 = *p1;
+ p1++;
+ p2++;
+ }
+
+ *p2 = 0;
+
+ for (p1 = Name + Wcslen(Name) - 1;
+ p1 >= Name && (*p1 == ' ' || *p1 == '.');
+ p1--) {
+ ;
+ }
+
+ *(p1 + 1) = 0;
+
+ //
+ // We don't allow zero length name
+ //
+ if (*Name == 0) {
+ return FALSE;
+ }
+
+ //
+ // See if there is any illegal characters within the name
+ //
+ while (*Name) {
+ if ( *Name < 0x20 ||
+ *Name == '\"' ||
+ *Name == '*' ||
+ *Name == '/' ||
+ *Name == ':' ||
+ *Name == '<' ||
+ *Name == '>' ||
+ *Name == '?' ||
+ *Name == '\\' ||
+ *Name == '|' ) {
+ return FALSE;
+ }
+
+ Name++;
+ }
+
+ return TRUE;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ExtractShortFileName
+//
+// Description: Extracts short file name from buffer
+//
+// Parameters:
+// VOLUME_INFO *Vi,
+// CHAR16 *lfn,
+// UINT8 *Buffer
+//
+// Return value: EFI_STATUS - Status of the operation
+//
+// Modified:
+//
+// Referral(s):
+//
+// NOTE(S):
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+ExtractShortFileName (
+ VOLUME_INFO *Vi,
+ CHAR16 *lfn,
+ UINT8 *Buffer
+)
+{
+
+ CHAR16 *p1;
+
+// Copy 8 characters
+ Vi->UnicodeCollationInterface->FatToStr (Vi->UnicodeCollationInterface,
+ 8,
+ Buffer,
+ lfn);
+
+
+// Remove trailing Spaces
+ for (p1 = lfn + 7; p1 >= lfn && (*p1 == ' '); p1--) {
+ ;
+ }
+
+ p1++;
+// P1 Points to the first Space in the 8 character sequence
+ Vi->UnicodeCollationInterface->FatToStr (Vi->UnicodeCollationInterface,
+ 3,
+ Buffer + 8,
+ p1 + 1); // leave space for '.'
+
+ *(p1 + 4) = 0; // if all three characters are valid
+
+ if (*(p1 + 1) != ' ') {
+ *p1 = '.'; // extension is valid
+
+ if (*(p1 + 3) == ' ') *(p1 + 3) = 0;
+
+ if (*(p1 + 2) == ' ') *(p1 + 2) = 0;
+
+ if (*(p1 + 1) == ' ') *(p1 + 1) = 0;
+
+ } else {
+ *p1 = 0; // No extension
+ }
+
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2011, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
diff --git a/Core/EM/FileSystem/Open.c b/Core/EM/FileSystem/Open.c
new file mode 100644
index 0000000..cdfdabf
--- /dev/null
+++ b/Core/EM/FileSystem/Open.c
@@ -0,0 +1,2601 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2011, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Core/Modules/FileSystem/Open.c 25 4/30/12 2:02p Pats $
+//
+// $Revision: 25 $
+//
+// $Date: 4/30/12 2:02p $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Core/Modules/FileSystem/Open.c $
+//
+// 25 4/30/12 2:02p Pats
+// [TAG] EIP87352
+// [Category] Bug Fix
+// [Symptom] FAT Direcotry Opean/Creation Issue
+// [RootCause] If a directory open was attempted with EFI_FILE_MODE_CREATE
+// set, check for existing directory was not done.
+// [Solution] Check for existing directory if opened with
+// EFI_FILE_MODE_CREATE set in ProcessOpenFileHandle().
+// [Files] Open.c
+//
+// 24 11/28/11 11:09a Pats
+// [TAG] - EIP 75631
+// [Category] - BUG FIX
+// [Severity] - Major
+// [Symptom] - If an application name includes a path, it won't run.
+// [Root Cause] - In the function ProcessOpenFileHandle(), the driver
+// attempts to replace "\" in the path with a zero, but the code was one
+// off, and the character past the "\" was being replaced.
+// [Solution] - Modified the function ProcessOpenFileHandle() to replace
+// the proper character.
+// [Files] - Open.c
+//
+// 23 10/24/11 10:55a Artems
+// EIP 73254: Remove "magic number" from source
+//
+// 22 5/05/11 3:44p Pats
+// [TAG] - EIP 58999
+// [Category]- BUG FIX
+// [Severity]- Major
+// [Symptom] - Cannot launch Shell from USB Filesystem device in Debug
+// mode with latest Filesystem driver.
+// [RootCause] - Functions using DISKIO were raising TPL to a fixed level.
+// [Solution] - Modified above functions to check for the higher of the
+// fixed level or current level.
+// [Files] - Info.c, MediaAccess.c, Open.c, FileSystem.h
+//
+// 21 2/05/11 3:20p Artems
+// Bug fix - restore original TPL in all branches of OpenFileHandle
+// function
+//
+// 20 1/13/11 12:24p Pats
+// [TAG] - EIP 51705
+// [Category]- BUG FIX
+// [Severity]- Major
+// [Symptom] - If the volume label is the same name as a directory or
+// file, the directory or file cannot be accessed. Also, a new directory
+// cannot be created with the same name as the volume.
+// [RootCause] - The functions FindMatchingFH() and FindMatchingDirEntry()
+// did not check for ATTR_VOLUME_ID.
+// [Solution] - Modified above functions to check for ATTR_VOLUME_ID.
+// [Files] - open.c
+//
+// 19 1/06/11 5:53p Oleksiyy
+// [TAG] EIP28607
+// [Category] Improvement
+// [Description] System was hanging for some time if Floppy Media
+// removed while writing in meda in progress.
+// EFI_TPL_CALLBACK priority level rised during media related calls.
+//
+// [Files] DiskIo.c, Info.c, MediaAccess.c, Open.c, Partition.c
+//
+// 18 1/06/11 5:03p Pats
+// [TAG] - EIP 49934
+// [Category]- BUG FIX
+// [Severity]- Minor
+// [Symptom] - The new EDKII shell was not displaying filesystem devices
+// properly.
+// [RootCause] - Root directory file name was "\", with a size of one.
+// Shell expected a null name for the root directory.
+// [Solution] - Changed root directory name to null.
+// [Files] - open.c, function OpenRoot().
+//
+// 17 12/03/10 10:08a Pats
+// EIP 44532: USB key is not returning file list as expected.
+// Problem: ReadFIleHandle was not resetting pointers when a directory
+// read returned an error.
+// Solution. Changed ReadFileHandle to reset pointers on error condition.
+//
+// 16 7/07/10 3:00p Pats
+// EIP 38291: Fails Klocwork test.
+// Problem: No error return if file handle is null in
+// ProcessOpenFileHandle()
+// Solution: Added error return.
+// Problem: Variable vi initialized improperly.
+// Solution: Changed initialization (moved to after possible error exit).
+//
+// 15 6/11/10 5:39p Pats
+// EIP 39171: Long name sometimes not displayed, only short name.
+// FetchLongName() in Open.c did not handle case where long name spilt
+// over 2 clusters. Function modified to handle the case.
+//
+// 14 1/22/10 4:39p Yul
+// Refer to EIP 32983.
+//
+// 13 12/17/09 12:44p Felixp
+// SCT workaround: CloseFileHandle function is updated to validate input
+// parameter before using it (EIP 32474).
+// SCT passes handle of the deleted file.
+//
+// 12 7/02/09 5:47p Pats
+// Updated to latest coding standard. No code changes.
+//
+// 11 7/30/08 11:36a Pats
+// Bug fix for file renaming.
+//
+// 10 4/13/07 7:07p Pats
+// Edited to conform with coding standards. No code changes.
+//
+// 9 8/24/06 9:32a Felixp
+// bug fix in CreateDirEntryInDisk
+//
+// 8 8/16/06 12:03p Markw
+// Fixed UINTN* and UINT32* 64-bit issues.
+//
+// Fixed VC7.1 warning msg.
+//
+// 4 6/21/05 4:00p Pats
+// Modified to call MarkVolumeDirty when EFI_VOLUME_CORRUPTED error
+// occurs. Removed commented-out debug code.
+//
+// 3 6/21/05 9:57a Pats
+// Corrected some spelling to match changes in Info.c.
+//
+// 2 5/27/05 10:02a Srinin
+// Fix for Media change and free space calculation.
+//
+// 1 4/26/05 6:05p Srinin
+//
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: Open.c
+//
+// Description: Handles Opening File Handles.
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+//----------------------------------------------------------------------
+
+#include "FileSystem.h"
+#define EFI_TPL_CALLBACK TPL_CALLBACK
+//----------------------------------------------------------------------
+
+extern EFI_GUID gEfiFileSystemVolumeLabelGuid;
+extern EFI_GUID gEfiFileInfoGuid;
+extern EFI_GUID gEfiFileSystemInfoGuid;
+
+//----------------------------------------------------------------------
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: OpenVolume
+//
+// Description: Opens a file system Volume.
+//
+// Parameters:
+// IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This - File System Protocol Instance
+// OUT EFI_FILE_PROTOCOL **Root
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+OpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **Root
+)
+{
+
+ EFI_STATUS Status;
+ FILE_HANDLE *RootHandle = NULL;
+ FILE_HANDLE_INSTANCE *RootInstance = NULL;
+ VOLUME_INFO *VolumeInfo = (VOLUME_INFO *)This;
+ FAT_TYPE Old_FAT_Type = VolumeInfo->FatType;
+ UINT32 Length;
+
+ if (VolumeInfo->RootFH && (VolumeInfo->VolumeStatus == EFI_MEDIA_CHANGED || VolumeInfo->VolumeStatus == EFI_NO_MEDIA)) {
+ FreeUpResources (VolumeInfo, VolumeInfo->VolumeStatus); // Media changed occurred earlier
+ }
+
+ if (VolumeInfo->RootFH) {
+ if (VolumeInfo->BlkIo->Media->RemovableMedia) {
+ Status = DetectVolume(VolumeInfo, TRUE); // Just reads the sector 0
+
+ if (EFI_ERROR(Status)) {
+ FreeUpResources (VolumeInfo, Status);
+ goto ContinueOpen;
+ }
+ }
+
+ RootHandle = VolumeInfo->RootFH; // Everything is fine
+
+ } else {
+ContinueOpen:
+ VolumeInfo->VolumeStatus = EFI_UNSUPPORTED;
+ VolumeInfo->BlockSize = VolumeInfo->BlkIo->Media->BlockSize;
+ VolumeInfo->ReadOnly = VolumeInfo->BlkIo->Media->ReadOnly;
+ VolumeInfo->MediaID = VolumeInfo->BlkIo->Media->MediaId;
+ Status = DetectVolume(VolumeInfo, FALSE);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (Old_FAT_Type && Old_FAT_Type != VolumeInfo->FatType) return EFI_UNSUPPORTED;
+
+// Create a FILE_HANDLE for Root Directory. Called for the first time.
+// VolumeInfo->VolumeSize = VolumeInfo->TotalSectors * VolumeInfo->VolumeBPB.BPB_BytePerSec;
+// Only count Data Sectors when determining Volume Size, to match DOS
+ VolumeInfo->VolumeSize = Mul64((UINT64)VolumeInfo->DataSectors, (UINT32)VolumeInfo->VolumeBPB.BPB_BytePerSec);
+ VolumeInfo->FreeSpaceinClusters = (UINTN)-1; // Means not calculated yet
+ VolumeInfo->FreeSpaceinSector1 = (UINTN)-1;
+ Status= OpenRoot(VolumeInfo, &RootHandle);
+ VolumeInfo->LastFreeCluster = (UINTN)-1;
+
+ if (EFI_ERROR(Status)) return Status;
+
+ VolumeInfo->RootFH = RootHandle;
+ DListAdd((DLIST *)(UINTN)&(VolumeInfo->OpenFHs),(DLINK *)(UINTN)&(RootHandle->ViFHLink));
+ }
+
+ if (!VolumeInfo->FileSystemName) {
+ Status = pBS->AllocatePool (EfiBootServicesData, 80, (VOID**)&VolumeInfo->FileSystemName);
+ Wcscpy (VolumeInfo->FileSystemName, L"FAT");
+ Length = (UINT32) Wcslen(VolumeInfo->FileSystemName);
+
+ switch (VolumeInfo->FatType) {
+ case FAT12:
+ Wcscpy (VolumeInfo->FileSystemName + Length, L"12 ");
+ break;
+ case FAT16:
+ Wcscpy (VolumeInfo->FileSystemName + Length, L"16 ");
+ break;
+ case FAT32:
+ Wcscpy (VolumeInfo->FileSystemName + Length, L"32 ");
+ break;
+ default:
+ Wcscpy (VolumeInfo->FileSystemName + Length, L"UnKnown ");
+ };
+
+ Length = (UINT32) Wcslen(VolumeInfo->FileSystemName);
+
+ Wcscpy (VolumeInfo->FileSystemName + Length, L"File System [");
+
+ Length = (UINT32) Wcslen(VolumeInfo->FileSystemName);
+
+ if (VolumeInfo->VolumeSize < 0x100000) { //Less than 1MB
+ ItowEx(Shr64 (VolumeInfo->VolumeSize, 10), VolumeInfo->FileSystemName + Length, 10, FALSE);
+ Length = (UINT32) Wcslen(VolumeInfo->FileSystemName);
+ Wcscpy (VolumeInfo->FileSystemName + Length, L"KB]");
+
+ } else if (VolumeInfo->VolumeSize < 0x40000000) { //Less than 1GB
+ ItowEx(Shr64 (VolumeInfo->VolumeSize, 20), VolumeInfo->FileSystemName + Length, 10, FALSE);
+ Length = (UINT32) Wcslen(VolumeInfo->FileSystemName);
+ Wcscpy (VolumeInfo->FileSystemName + Length, L"MB]");
+
+ } else {
+ ItowEx(Shr64 (VolumeInfo->VolumeSize, 30), VolumeInfo->FileSystemName + Length, 10, FALSE);
+ Length = (UINT32) Wcslen(VolumeInfo->FileSystemName);
+ Wcscpy (VolumeInfo->FileSystemName + Length, L"GB]");
+ }
+ }
+
+
+// Create a FILE_HANDLE_INSTANCE
+ Status = CreateFileHandleInstance(RootHandle, &RootInstance, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
+
+// Return FILE_HANDLE_INSTANCE
+ if (Status == EFI_SUCCESS) *Root = (EFI_FILE_PROTOCOL *)RootInstance;
+
+ VolumeInfo->VolumeStatus = Status;
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: OpenRoot
+//
+// Description: Opens the Root Directory on the Volume.
+//
+// Parameters:
+// IN VOLUME_INFO *VolumeInfo - Volume Info Structure
+// IN OUT FILE_HANDLE **Root - Root directory handle
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+OpenRoot(
+ IN VOLUME_INFO *VolumeInfo,
+ IN OUT FILE_HANDLE **Root
+)
+{
+
+ EFI_STATUS Status;
+ FILE_HANDLE *RootHandle;
+
+ Status = fsAllocateMemory(VolumeInfo, sizeof(FILE_HANDLE), (VOID**)&RootHandle, TRUE);
+
+ if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES;
+
+ Status = fsAllocateMemory(VolumeInfo, 4, (VOID**)&(RootHandle->FileNameLFN), FALSE);
+
+ RootHandle->FileNameLFN[0]= 0;
+ RootHandle->ROOTDIR = TRUE;
+ RootHandle->VolumeInterface = VolumeInfo;
+ RootHandle->DirectoryEntry.Dir_Attr = EFI_FILE_DIRECTORY;
+ RootHandle->HandleStatus= EFI_SUCCESS;
+
+ if (VolumeInfo->FatType == FAT32) {
+ RootHandle->DirCluster = VolumeInfo->VolumeBPB.BPB_FAT.BPB_FAT32.BPB_RootClus;
+ RootHandle->DirOffset = 0;
+ }
+
+ DListInit((DLIST *)(UINTN)&(RootHandle->DirList));
+ *Root = RootHandle;
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: CreateFileHandleInstance
+//
+// Description: Creates an instance of a file handle
+//
+// Parameters:
+// IN FILE_HANDLE *fh - Handle of the file to work on
+// IN OUT FILE_HANDLE_INSTANCE **fhi - File handle instance
+// IN UINT64 OpenMode - Open mode (read, write, both)
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+CreateFileHandleInstance (
+ IN FILE_HANDLE *fh,
+ IN OUT FILE_HANDLE_INSTANCE **fhi,
+ IN UINT64 OpenMode
+)
+{
+
+ EFI_STATUS Status;
+ VOLUME_INFO *Vi = fh->VolumeInterface;
+ FILE_HANDLE_INSTANCE *nfi;
+
+ Status = fsAllocateMemory(Vi, sizeof(FILE_HANDLE_INSTANCE), (VOID**)&nfi, TRUE);
+
+ if (EFI_ERROR(Status)) return EFI_OUT_OF_RESOURCES;
+
+ nfi->Position = 0;
+ nfi->HandleInstanceStatus = EFI_SUCCESS;
+ nfi->CurrentCluster = FIRSTCLUSTER(fh->DirectoryEntry);
+ nfi->pFH = fh;
+ nfi->OpenMode = OpenMode;
+ InitEFIFileInterface(&(nfi->FileHandle));
+ fh->InstancesCount++;
+ DListAdd((DLIST *)(UINTN)&(Vi->OpenFIs), (DLINK *)(UINTN)&(nfi->ViFILink));
+ *fhi = nfi;
+ return EFI_SUCCESS;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: InitEFIFileInterface
+//
+// Description: Initializes the EFI_FILE_PROTOCOL interface
+//
+// Parameters:
+// EFI_FILE_PROTOCOL *EFIFileInterface - Interface structure
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: OpenProtocol CloseProtocol
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+void
+InitEFIFileInterface (
+ EFI_FILE_PROTOCOL *EFIFileInterface
+)
+{
+
+ EFIFileInterface->Revision = SIMPLE_FILE_SYSTEM_DRIVER_VERSION;
+ EFIFileInterface->Open = OpenFileHandle;
+ EFIFileInterface->Close = CloseFileHandle;
+ EFIFileInterface->Delete = DeleteFileHandle;
+ EFIFileInterface->Read = ReadFileHandle;
+ EFIFileInterface->Write = WriteFileHandle;
+ EFIFileInterface->GetPosition = GetPositionFileHandle;
+ EFIFileInterface->SetPosition = SetPositionFileHandleThis;
+ EFIFileInterface->GetInfo = GetInfoFileHandle;
+ EFIFileInterface->SetInfo = SetInfoFileHandle;
+ EFIFileInterface->Flush = FlushFileHandle;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: OpenFileHandle
+//
+// Description: Opens a file handle (when a file is opened)
+//
+// Parameters:
+// IN EFI_FILE_PROTOCOL *This - File System Protocol instance
+// OUT EFI_FILE_PROTOCOL **NewHandle - Handle of open file
+// IN CHAR16 *FileName - Unicode name of file
+// IN UINT64 OpenMode - Open mode (read, write, both)
+// IN UINT64 Attributes - Attributes of open file
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+OpenFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+)
+{
+
+ EFI_STATUS Status;
+ FILE_HANDLE_INSTANCE *Fi= (FILE_HANDLE_INSTANCE *) This;
+ FILE_HANDLE *ParentFh;
+ VOLUME_INFO *Vi;
+ EFI_TPL SaveTpl;
+ EFI_TPL NextTpl;
+#ifdef Debug_OpenFile
+ EfiDebugPrint(-1,"OpenFile: %S OpenMode %lx Attribute %lx\n", FileName, OpenMode, Attributes);
+#endif
+
+// Validate Inputs
+ switch (OpenMode) {
+ case (EFI_FILE_MODE_READ):
+ case (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE):
+ case (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE):
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ NextTpl = FindNextTpl (EFI_TPL_CALLBACK);
+ SaveTpl = pBS->RaiseTPL (NextTpl);
+ Status = ValidateCurrentStatus (Fi);
+ if (EFI_ERROR(Status))
+ {
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+ ParentFh = Fi->pFH;
+ Vi = ParentFh->VolumeInterface;
+ if (Vi->ReadOnly && OpenMode & EFI_FILE_MODE_WRITE)
+ {
+ pBS->RestoreTPL(SaveTpl);
+ return EFI_WRITE_PROTECTED;
+ }
+ if (FileName == NULL)
+ {
+ pBS->RestoreTPL(SaveTpl);
+ return EFI_NOT_FOUND;
+ }
+ if ( Attributes & ~EFI_FILE_VALID_ATTR)
+ {
+ pBS->RestoreTPL(SaveTpl);
+ return EFI_NOT_FOUND;
+ }
+ Status = ProcessOpenFileHandle (Fi, &FileName, NewHandle, OpenMode, Attributes);
+ pBS->RestoreTPL(SaveTpl);
+#ifdef Debug_OpenFile
+ EfiDebugPrint(-1,"OpenFile Status: %x\n", Status);
+#endif
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ReadFileHandle
+//
+// Description: Read from a file (normal file or directory)
+//
+// Parameters:
+// IN EFI_FILE_PROTOCOL *This - File System Protocol instance
+// IN OUT UINTN *BufferSize - Size of read buffer
+// OUT VOID *Buffer - Points to read buffer
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+ReadFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+)
+{
+
+ EFI_STATUS Status = EFI_UNSUPPORTED;
+ FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)This;
+ FILE_HANDLE *Pfh;
+ FILE_HANDLE *fh1;
+ DIR_ENTRY_LIST *Del;
+ UINT32 Position;
+ FILE_HANDLE_INSTANCE TempFhi;
+ FILE_HANDLE TempPfh;
+ EFI_TPL SaveTpl;
+ EFI_TPL NextTpl;
+
+ if (*BufferSize > 0xffffffff) return EFI_INVALID_PARAMETER;
+
+ TempFhi = *fhi;
+ Status = ValidateCurrentStatus (fhi);
+ if (EFI_ERROR(Status)) return Status;
+ Pfh = fhi->pFH;
+ TempPfh = *Pfh;
+#ifdef Debug_ReadFile
+ EfiDebugPrint(TRACE_ALWAYS,"ReadFile: %S Position %lx Length %x \n", Pfh->FileNameLFN, fhi->Position, *BufferSize);
+#endif
+ NextTpl = FindNextTpl (EFI_TPL_CALLBACK);
+ SaveTpl = pBS->RaiseTPL (NextTpl);
+
+// Check if this Instance is a Directory.
+ if (Pfh->DirectoryEntry.Dir_Attr & ATTR_DIRECTORY) {
+
+// Check if Dir List has been changed. If so, release the list and read it again.
+ if (Pfh->DirListChanged == TRUE) {
+ RemoveAllDirList (Pfh);
+ Pfh->DirListChanged = FALSE;
+ }
+
+// Check if the file Handle has a valid DIR_ENTRY_LIST
+ if (!Pfh->DirList.pHead) {
+ Status = ReadAllDirectoryEntries (Pfh);
+
+ if (EFI_ERROR(Status)) {
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+ }
+
+// If Dir_List has been changed, this should take care of it.
+ if (fhi->Position != 0) {
+ Status = LocateDel (Pfh->DirList.pHead, fhi->CurrentCluster, fhi->CurrentClusterOffset, &Del, &Position);
+ fhi->Position = Position;
+ }
+
+
+ for (;; fhi->Position++) {
+ Status = GetDirListAtPosition (Pfh, fhi->Position, &Del);
+
+ if (!Del) {
+ *BufferSize = 0; // End of entries
+ pBS->RestoreTPL(SaveTpl);
+ return EFI_SUCCESS;
+ }
+
+// Check whether it is a Label
+ if ((Del->DirectoryEntry.Dir_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) != ATTR_VOLUME_ID)
+ break;
+ }
+
+///////////////////////////////////////////////
+//A long Process. Do we need to reduce it
+ Status = CreateFHFromDirEntryList(Del, Pfh, &fh1);
+
+ if (EFI_ERROR(Status)){
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+
+ Status = GetFileInfoFromFH (fh1, BufferSize, Buffer);
+
+ if (EFI_ERROR(Status)) {
+ *fhi = TempFhi;
+ *Pfh = TempPfh;
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+
+//A long Process. Do we need to reduce it
+///////////////////////////////////////////////
+
+ fhi->Position++;
+
+// Make sure CurrentCluster and CurrentClusterOffset gets updated to the new position
+ for (;; fhi->Position++) {
+ Status = GetDirListAtPosition (Pfh, fhi->Position, &Del);
+
+ if (!Del) break;
+
+// Check whether it is a Label
+ if ((Del->DirectoryEntry.Dir_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) != ATTR_VOLUME_ID)
+ break;
+ }
+
+// Update the CurrentCluster, CurrentClusterOffset for the new position
+ if (Del) {
+ fhi->CurrentCluster = Del->Cluster;
+ fhi->CurrentClusterOffset = Del->Offset;
+
+ } else {
+ fhi->CurrentCluster = (UINTN) -1;
+ fhi->CurrentClusterOffset = (UINTN)-1;
+ Status = EFI_SUCCESS;
+ }
+
+ RemoveFH(fh1);
+
+ } else {
+// It is File.
+ //Buffer size is on input is required to be less than 4G.
+ Status = ReadFromFile (fhi, Buffer, (UINT32*)BufferSize, DATA_REGION);
+ }
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: WriteFileHandle
+//
+// Description: Writes to a file
+//
+// Parameters:
+// IN EFI_FILE_PROTOCOL *This,
+// IN OUT UINTN *BufferSize,
+// IN VOID *Buffer
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+WriteFileHandle (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+)
+{
+ EFI_TPL SaveTpl;
+ EFI_TPL NextTpl;
+ EFI_STATUS Status;
+ FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)This;
+
+#ifdef Debug_WriteFile
+ FILE_HANDLE *Pfh;
+ VOLUME_INFO *vi;
+#endif
+
+ if (*BufferSize > 0xffffffff) return EFI_INVALID_PARAMETER;
+
+ Status = ValidateCurrentStatus (fhi);
+ if (EFI_ERROR(Status)) return Status;
+ NextTpl = FindNextTpl (EFI_TPL_CALLBACK);
+ SaveTpl = pBS->RaiseTPL (NextTpl);
+#ifdef Debug_WriteFile
+ Pfh = fhi->pFH;
+ vi = Pfh->VolumeInterface;
+ EfiDebugPrint(TRACE_ALWAYS,"WriteFile: %S FSize %x Pos %lx Len %x LoCluster %x\n",
+ Pfh->FileNameLFN, Pfh->DirectoryEntry.Dir_FileSize, fhi->Position, *BufferSize, Pfh->DirectoryEntry.Dir_FstClusLO);
+#endif
+
+ Status = CheckFileWrite (fhi, FALSE);
+ if (EFI_ERROR(Status)){
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+
+ //Buffer size is on input is required to be less than 4G.
+ Status = WriteToFile (fhi, Buffer, (UINT32*)BufferSize, DATA_REGION);
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SetInfoFileHandle
+//
+// Description: Sets file info
+//
+// Parameters:
+// IN EFI_FILE_PROTOCOL *This,
+// IN EFI_GUID *InformationType,
+// IN UINTN BufferSize,
+// IN VOID *Buffer
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+SetInfoFileHandle(
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+)
+{
+
+
+ EFI_STATUS Status = EFI_UNSUPPORTED;
+ FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)This;
+ FILE_HANDLE *Pfh;
+ VOLUME_INFO *vi;
+ EFI_TPL SaveTpl;
+ EFI_TPL NextTpl;
+
+ Status = ValidateCurrentStatus (fhi);
+ if (EFI_ERROR(Status)) return Status;
+ Pfh = fhi->pFH;
+ vi = Pfh->VolumeInterface;
+ if (vi->ReadOnly) return EFI_WRITE_PROTECTED;
+
+// Compare the GUID
+ NextTpl = FindNextTpl (EFI_TPL_CALLBACK);
+ SaveTpl = pBS->RaiseTPL (NextTpl);
+ if (!guidcmp(InformationType, &gEfiFileInfoGuid)) {
+ Status = SetfileInfo (This, fhi, BufferSize, Buffer);
+
+ if (EFI_ERROR(Status)){
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+ }
+
+ else {
+ if (!guidcmp(InformationType, &gEfiFileSystemInfoGuid)) {
+ Status = SetSystemInfo (vi, BufferSize, (EFI_FILE_SYSTEM_INFO *)Buffer);
+
+ if (EFI_ERROR(Status)){
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+
+ Status = FlushFileHandle(This);
+
+ if (EFI_ERROR(Status)){
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+
+ } else {
+ if (!guidcmp(InformationType, &gEfiFileSystemVolumeLabelGuid)) {
+ Status = SetVolumeLabel (vi, BufferSize, Buffer);
+
+ if (EFI_ERROR(Status)){
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+
+ Status = FlushFileHandle(This);
+
+ if (EFI_ERROR(Status)) {
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+
+ } else {
+ pBS->RestoreTPL(SaveTpl);
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+
+}
+
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: DeleteFileHandle
+//
+// Description: Deletes a file
+//
+// Parameters:
+// IN EFI_FILE_PROTOCOL *This - File Protocol instance
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: For FAT32, Cluster(s) occupied by root directory will not be released
+// as Del/rm command will not give a call to delete RootHandle.
+// In a empty FAt32 disk, free space will be less by clusters occupied by ROOT Directory
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+DeleteFileHandle (
+ IN EFI_FILE_PROTOCOL *This
+)
+{
+
+ EFI_STATUS Status;
+ FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)This, *fhi1;
+ FILE_HANDLE *fh;
+ FILE_HANDLE *PPfh;
+ VOLUME_INFO *vi;
+ UINT32 ClusterCount;
+// UINT32 Sector, SectorOffset, ClusterCount;
+ UINT8 DirErase = DIR_ENTRY_ERASE;
+ DLINK *dlink;
+ DIR_ENTRY_LIST *Del;
+ UINT32 Position;
+ EFI_TPL SaveTpl;
+ EFI_TPL NextTpl;
+
+ Status = ValidateCurrentStatus (fhi);
+ if (EFI_ERROR(Status)) return Status;
+
+ fh = fhi->pFH;
+ vi = fh->VolumeInterface;
+ PPfh = fh->Parent;
+ dlink = PPfh->DirList.pHead ;
+
+#ifdef Debug_DeleteFile
+ EfiDebugPrint(TRACE_ALWAYS,"Del File: %S Dir Cluster %x Dir Offset %x\n", fh->FileNameLFN, fh->DirCluster, fh->DirOffset);
+#endif
+
+
+ if ( vi->ReadOnly || fh->ROOTDIR
+ || fh->DirectoryEntry.Dir_Attr & ATTR_READ_ONLY
+ || !(fhi->OpenMode & EFI_FILE_MODE_WRITE)){
+
+ CloseFileHandle (This);
+
+#ifdef Debug_DeleteFile
+ EfiDebugPrint(-1,"DEL WARN FAILURE Instances Open %x\n", fh->InstancesCount);
+#endif
+ return EFI_WARN_DELETE_FAILURE;
+ }
+
+ if (fh->DirectoryEntry.Dir_Attr & ATTR_DIRECTORY) {
+ if (fh->DirList.Size > 2) {
+ CloseFileHandle (This);
+#ifdef Debug_DeleteFile
+ EfiDebugPrint(-1,"DEL WARN FAILURE Dir Not Empty\n");
+#endif
+ return EFI_WARN_DELETE_FAILURE;
+ }
+
+//###DEBUG
+// TODO TODO TODO
+// Before removing the Directory Entry, check if it is empty.
+// TODO TODO TODO
+//##DEBUG END
+// Release all Dir_List
+ RemoveAllDirList(fh);
+ }
+
+ NextTpl = FindNextTpl (EFI_TPL_CALLBACK);
+ SaveTpl = pBS->RaiseTPL (NextTpl);
+
+ if (fh->DirCluster || fh->DirOffset) {
+ fh->DirectoryEntry.Dir_Name[0] = DirErase;
+ fh->DirEntryChanged = TRUE;
+// Update the FAT Chain
+ UnlinkFat(vi, FIRSTCLUSTER(fh->DirectoryEntry), &ClusterCount);
+ }
+
+// Check if DIR_LIST is valid. If yes, remove from the list.
+ Status = LocateDel (fh->Parent->DirList.pHead, fh->DirCluster, fh->DirOffset, &Del, &Position);
+
+ if (!EFI_ERROR(Status)) RemoveDirList(PPfh, Del);
+
+// Force next Scan for the parent directory to begin from the beginning
+ fh->Parent->FreeDirEntryCluster = 0;
+ fh->Parent->FreeDirEntryOffset = 0;
+
+// Remove File Handle and File List
+ CloseFileHandle (This);
+
+// Check for multiple instances
+ if (fh->InstancesCount ) {
+ dlink = vi->OpenFIs.pHead;
+
+ for ( ; dlink; ) {
+ fhi1 = OUTTER(dlink, ViFILink, FILE_HANDLE_INSTANCE);
+
+ if (fhi1->pFH == fh) {
+ fhi1->HandleInstanceStatus = EFI_NOT_FOUND;
+ fhi1->pFH = NULL;
+ fh->InstancesCount--;
+ }
+
+ dlink = dlink->pNext;
+ }
+ }
+
+ Status = RemoveFH(fh);
+ pBS->RestoreTPL(SaveTpl);
+#ifdef Debug_DeleteFile
+ EfiDebugPrint(-1,"Del File Success\n");
+#endif
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FlushFileHandle
+//
+// Description: Flushes a file (writes any portion left in cache)
+//
+// Parameters:
+// IN EFI_FILE_PROTOCOL *This - File Protocol instance
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FlushFileHandle (
+ IN EFI_FILE_PROTOCOL *This
+)
+{
+
+ EFI_STATUS Status;
+ FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)This;
+ FILE_HANDLE *Pfh;
+ VOLUME_INFO *vi;
+ DLINK *dlink;
+ CACHE_HEADER *ch;
+ EFI_TPL SaveTpl;
+ EFI_TPL NextTpl;
+
+ Status = ValidateCurrentStatus (fhi);
+ if (EFI_ERROR(Status)) return Status;
+
+ Pfh =fhi->pFH;
+ vi = Pfh->VolumeInterface;
+ dlink = vi->CacheList.pHead;
+ if (fhi->OpenMode == EFI_FILE_MODE_READ) return EFI_ACCESS_DENIED;
+
+ if (vi->ReadOnly) return EFI_ACCESS_DENIED;
+ NextTpl = FindNextTpl (EFI_TPL_CALLBACK);
+ SaveTpl = pBS->RaiseTPL (NextTpl);
+ for ( ; dlink; ) {
+
+ ch = OUTTER(dlink, CacheLink, CACHE_HEADER);
+
+ if (ch->DIRTY_FLAG) {
+ Status= vi->DiskIo->WriteDisk (vi->DiskIo, vi->MediaID, ch->AbsoluteOffset, (UINT32) (ch->AbsoluteOffsetEnd - ch->AbsoluteOffset), ch->Buffer);
+
+ if (EFI_ERROR(Status)) {
+ HandleDiskIoError(vi, Status);
+ pBS->RestoreTPL(SaveTpl);
+ return Status;
+ }
+
+ ch->DIRTY_FLAG = FALSE;
+ }
+
+ dlink = dlink->pNext;
+
+ }
+ pBS->RestoreTPL(SaveTpl);
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ProcessOpenFileHandle
+//
+// Description: Performs whatever is needed to process an open handle
+// (create dir. entry, create instance, allocate clusters)
+//
+// Parameters:
+// IN FILE_HANDLE_INSTANCE *ParentFi - Parent file handle instance
+// IN CHAR16 **FileName - Unicode file name
+// OUT EFI_FILE_PROTOCOL **NewHandle - New file handle
+// IN UINT64 OpenMode - Open mode (read, write, both)
+// IN UINT64 Attributes - File attributes
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+ProcessOpenFileHandle(
+ IN FILE_HANDLE_INSTANCE *Fi,
+ IN CHAR16 **FileName,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+)
+{
+
+ EFI_STATUS Status;
+ FILE_HANDLE *fh = Fi->pFH, *fh1;
+ VOLUME_INFO *Vi = fh->VolumeInterface;
+ CHAR16 *Next;
+ UINT32 Length;
+ CHAR16 NextCompName[MAX_TOTAL_PATH_LENGTH];
+ FILE_HANDLE_INSTANCE *fhi;
+ DIR_ENTRY_LIST *Del;
+ CHAR16 CurrentDir[] = {'.', 0};
+ CHAR16 ParentDir[] = {'.', '.', 0};
+ UINT8 *Buffer;
+ BOOLEAN DirFound = FALSE;
+
+ if (EFI_ERROR(fh->HandleStatus)) return fh->HandleStatus;
+
+ Next = *FileName;
+
+ if ((*FileName)[0] == '\\') {
+ fh = Vi->RootFH;
+ (*FileName) += 1;
+ }
+
+// Check for '\\' at the end of the FileName. If so remove it. Eg: \windows\system
+ Length = (UINT32) Wcslen(*FileName);
+
+ if (Length > 2 && (*FileName)[Length-1] == '\\') (*FileName)[Length-1] = 0;
+
+ Status = EFI_SUCCESS;
+
+ while (! EFI_ERROR(Status)) {
+
+ if ( EFI_ERROR(GetNextCompName (FileName, NextCompName))) return EFI_NOT_FOUND;
+
+ if (NextCompName[0] == 0) break;
+
+ if (!FatLfnIsValid (NextCompName)) return EFI_NOT_FOUND;
+
+ if (!Wcscmp(NextCompName, CurrentDir)) continue;
+
+ if (!Wcscmp(NextCompName, ParentDir)) {
+ if (fh == Vi->RootFH) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ fh = fh->Parent;
+
+ if (!fh) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+ continue;
+ }
+
+// A component name is present. Parent should be directory. Else return error
+ if (!(fh->DirectoryEntry.Dir_Attr & ATTR_DIRECTORY)) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+
+// Check whether a match can be found for nextcompname
+ if (FindMatchingFH(Vi, NextCompName, fh, &fh1)) {
+ fh = fh1;
+ Status = EFI_SUCCESS;
+ continue;
+ }
+
+// See if the Linked List is Valid
+ if (!fh->DirList.pHead) {
+ ReadAllDirectoryEntries (fh);
+
+ if (EFI_ERROR(Status)) return Status;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ DirFound = FALSE;
+ if (FindMatchingDirEntry (fh, NextCompName, &Del)) {
+ DirFound = TRUE; // Flag existing directory found
+ Status = CreateFHFromDirEntryList(Del, fh, &fh1);
+
+ // Add to the List in Volume Interface
+ if (Status == EFI_SUCCESS) {
+ fh = fh1;
+ }
+ }
+ }
+
+ if (EFI_ERROR(Status)) {
+
+// Make sure NextCompName is the last compname.
+ if ((*FileName[0]) != 0) return EFI_NOT_FOUND;
+
+// If it is a file that needs to be openend, and not found create one. For directories return error.
+ if (OpenMode & EFI_FILE_MODE_CREATE) {
+
+ if (!fh) return EFI_NOT_FOUND;
+
+ if (!(fh->DirectoryEntry.Dir_Attr & ATTR_DIRECTORY)) {
+ // if this is not a directory then the input is just a filename. So get the parent handle of this instance
+ fh = fh->Parent;
+ }
+
+// Create a file entry in the parent directory
+ Status = CreateDirectoryEntry (fh, NextCompName, &fh1, Attributes);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ fh = fh1;
+
+ } else return EFI_NOT_FOUND;
+ }
+
+// Create an instance
+ Status = CreateFileHandleInstance (fh, &fhi, OpenMode);
+ *NewHandle = (EFI_FILE_PROTOCOL *) fhi;
+
+// If asked to create a directory, and it already exists, the UEFI spec says to
+// just open and return EFI_SUCCESS.
+ if (DirFound && (OpenMode & EFI_FILE_MODE_CREATE)) {
+ return EFI_SUCCESS;
+ }
+
+ if ((fhi->pFH->DirectoryEntry.Dir_Attr == ATTR_DIRECTORY) &&
+ (OpenMode & EFI_FILE_MODE_CREATE)) { // If creating a new directory, create dot and dotdot entries
+
+// Allocate Cluster for the sub Directory that was created before.
+// The new allocated cluster should be cleared.
+// fsAllocateMemory (Vi, Vi->BytesPerCluster, (void **)&Buffer, TRUE);
+ GetTempBuffer (Vi, &Buffer);
+ Zeromemory (Buffer, Vi->BytesPerCluster);
+ Length = Vi->BytesPerCluster;
+ Status = WriteToFile (fhi, Buffer, &Length, DIRECTORY_REGION);
+
+ if (EFI_ERROR(Status)) return Status;
+
+// fsDeAllocateMemory(Vi, Buffer);
+ ReleaseTempBuffer(Vi);
+
+ fhi->Position = 0;
+ fhi->pFH->DirectoryEntry.Dir_FileSize = 0;
+
+ if (fhi->pFH->DirEntryChanged == TRUE) UpdateDirListFromFHDir(fhi->pFH);
+
+ fhi->pFH->DirEntryChanged = FALSE;
+ fhi->pFH->FreeDirEntryCluster = FIRSTCLUSTER(fh->DirectoryEntry);
+ fhi->pFH->FreeDirEntryOffset = 0;
+
+// Create '.' entry
+ Status = CreateDirectoryEntry(fh, CurrentDir, &fh1, ATTR_DIRECTORY);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ RemoveFH(fh1);
+
+// Create'..' entry
+ Status = CreateDirectoryEntry(fh, ParentDir, &fh1, ATTR_DIRECTORY);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ RemoveFH(fh1);
+
+ }
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ReadAllDirectoryEntries
+//
+// Description: Reads entries in a directory
+//
+// Parameters:
+// IN FILE_HANDLE *fh - File handle structure
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ReadFileHandle, ProcessOpenFileHandle
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+ReadAllDirectoryEntries (
+ IN FILE_HANDLE *fh
+)
+{
+
+ EFI_STATUS Status;
+ CHAR16 lfn[256], *lfnBuffer;
+ UINT32 Offset, SlotNumber = 0, BufferSize, OrgBufferSize, Slots;
+ UINT32 BytesReadPerLoop;
+ UINT8 *Buffer;
+ VOLUME_INFO *Vi = fh->VolumeInterface;
+ UINT32 ClusterNumber, Cluster;
+
+ if (Vi->TotalDirEntryList > DIRECTORTY_ENTRIES_CACHED) FreeUpDirEntries (Vi, NULL);
+
+// Allocate space for a temp buffer.
+ BytesReadPerLoop = Vi->BytesPerCluster;
+
+ if (fh->ROOTDIR && (Vi->FatType != FAT32))
+ BytesReadPerLoop = Vi->RootDirSectorCount << Vi->BytesPerSecPowerof2;
+
+ GetTempBuffer (Vi, &Buffer);
+
+ for (ClusterNumber = 0; ; ClusterNumber++, Cluster = 0) {
+
+ Status = ReadClusterOfDirectoryEntries(fh, ClusterNumber, &Cluster, Buffer, &BytesReadPerLoop);
+
+ if (Status == EFI_SUCCESS && BytesReadPerLoop == 0) {
+ break; // Empty Directory or End of Directory reached
+ }
+
+ if (EFI_ERROR(Status)) break;
+
+ OrgBufferSize = BytesReadPerLoop;
+ BufferSize = BytesReadPerLoop;
+ Offset = 0;
+
+ for ( ; BufferSize; Offset += sizeof (DIR_ENTRY_32), BufferSize = OrgBufferSize - Offset) {
+
+ if (!(FindShortName (Buffer, &Offset, BufferSize))) break;
+
+// Find a matching LFN
+ Slots = FetchLongName(fh, (DIR_ENTRY_32 *)(Buffer), Offset, lfn, ClusterNumber, BytesReadPerLoop);
+
+ if (Slots == 0) ExtractShortFileName (Vi, lfn, Buffer + Offset);
+
+ Status = fsAllocateMemory (Vi, (UINT32)((Wcslen(lfn) * sizeof (CHAR16))+ 2), (VOID**)&lfnBuffer, FALSE);
+ pBS->CopyMem (lfnBuffer, lfn, (Wcslen(lfn) * sizeof (CHAR16))+ 2);
+
+// Create a Dir Entry List and add it to the Parent File Handle
+// Valid Entry has been found. *lfn, DirectoryEntry, Offset
+ AddToDirList (fh, *(DIR_ENTRY_32 *)(Buffer + Offset), lfnBuffer, Cluster, Offset, SlotNumber);
+ SlotNumber++;
+ }
+
+ if (Offset == -1) break; // No more directory Entries.
+
+ if (fh->ROOTDIR && (Vi->FatType != FAT32)) break; // Only one loop.
+ }
+
+ ReleaseTempBuffer (Vi);
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ReadClusterOfDirectoryEntries
+//
+// Description: Reads one cluster of directory entries
+//
+// Parameters:
+// IN FILE_HANDLE *fh,
+// IN UINT32 ClusterNumber -- 0-based number of which cluster to read
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ReadAllDirectoryEntries
+//
+// Notes: For end of cluster, BufferSize = 0 and EFI_SUCCESS returned.
+// For FAT12/16, All the Root Directories are read in one shot.
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+ReadClusterOfDirectoryEntries (
+ IN FILE_HANDLE *fh,
+ IN UINT32 ClusterNumber,
+ OUT UINT32 *ClusterRead,
+ UINT8 *Buffer,
+ UINT32 *BufferSize
+)
+{
+ EFI_STATUS Status;
+ VOLUME_INFO *Vi = fh->VolumeInterface;
+ UINT32 Cluster;
+ UINT32 Sector;
+ UINT32 i;
+
+// Find the starting sector of the cluster to read.
+ Cluster = FIRSTCLUSTER(fh->DirectoryEntry);
+
+ if (fh->ROOTDIR && (Vi->FatType != FAT32)) {
+// Offset = ClusterNumber * (UINT32)Vi->VolumeBPB.BPB_SecPerClus;
+// if(Offset >= Vi->RootDirSectorCount) return EFI_NOT_FOUND; // Requested cluster is beyond directory
+ if (ClusterNumber) {
+ *BufferSize = 0;
+ return EFI_SUCCESS; // For FAT12/16 root dir, Clusternumber should be always zero.
+ }
+
+ Sector = Vi->VolumeBPB.BPB_RsvdSecCnt + Vi->FATSz * Vi->VolumeBPB.BPB_NumFATs;
+ *ClusterRead = Sector;
+
+ } else {
+ if (Vi->FatType == FAT32 && fh->ROOTDIR) Cluster = Vi->VolumeBPB.BPB_FAT.BPB_FAT32.BPB_RootClus;
+
+ if (ClusterNumber != 0) {
+ for (i=0; i<ClusterNumber ; i++) { // Follow the fat chain to find the desired cluster
+ Status = ReadFatClusterNumber(Vi, Cluster, 0, &Cluster);
+
+ if (EFI_ERROR(Status)) return EFI_NOT_FOUND;
+
+ if (Cluster < 2) {
+ MarkVolumeDirty (Vi);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ if (Cluster >= Vi->EOCMark) {
+ *BufferSize = 0; // End of Directory reached.
+ return EFI_SUCCESS; // Requested cluster is beyond directory end
+ }
+ }
+ }
+
+// Convert this cluster to a sector.
+ Sector = ClusterToSector(Vi, Cluster);
+ *ClusterRead = Cluster;
+ }
+
+// Read one cluster of the directory into the temp buffer.
+ Status = FsReadMedia (Vi,
+ Buffer,
+ (UINT64)Sector,
+ 0,
+ *BufferSize,
+ DIRECTORY_REGION);
+
+ return Status;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: AddToDirList
+//
+// Description: Adds a directory entry to DirList
+//
+// Parameters:
+// IN FILE_HANDLE *fh - File Handle
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ReadAllDirectoryEntries
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+AddToDirList (
+ FILE_HANDLE *fh,
+ DIR_ENTRY_32 DirectoryEntry,
+ CHAR16 *lfn,
+ UINT32 Cluster,
+ UINT32 Offset,
+ UINT32 SlotNumber
+
+)
+{
+ DIR_ENTRY_LIST *Del;
+ EFI_STATUS Status;
+
+ Status = fsAllocateMemory(fh->VolumeInterface, sizeof(DIR_ENTRY_LIST), (VOID**)&Del, FALSE);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ pBS->CopyMem (&(Del->DirectoryEntry), &DirectoryEntry, sizeof(DIR_ENTRY_32));
+ Del->FileNameLFN = lfn;
+ Del->Cluster = Cluster;
+ Del->Offset= Offset;
+ Del->SlotNumber= SlotNumber;
+ DListAdd((DLIST *)(UINTN)&(fh->DirList), (DLINK *)(UINTN)&(Del->DirLink));
+ fh->VolumeInterface->TotalDirEntryList++;
+ return EFI_SUCCESS;
+
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: CreateFHFromDirEntryList
+//
+// Description: Creates a file handle from directory entry list
+//
+// Parameters:
+// IN DIR_ENTRY_LIST *Del - Directory entry list
+// IN FILE_HANDLE *fh - Directory file handle
+// OUT FILE_HANDLE **fh1 - New file handle
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ReadFileHandle, ProcessOpenFileHandle
+//
+// Notes: Should not link the FH to any LIST
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+CreateFHFromDirEntryList(
+ IN DIR_ENTRY_LIST *Del,
+ IN FILE_HANDLE *fh,
+ OUT FILE_HANDLE **fh1
+)
+{
+
+ FILE_HANDLE *nfh;
+ EFI_STATUS Status;
+
+ Status = fsAllocateMemory(fh->VolumeInterface, sizeof(FILE_HANDLE), (VOID**)&nfh, TRUE);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ Status = fsAllocateMemory(fh->VolumeInterface, (UINT32)((Wcslen(Del->FileNameLFN) * sizeof(CHAR16)) + 2), (VOID**)&(nfh->FileNameLFN), FALSE);
+
+ if (EFI_ERROR(Status)) return Status;
+
+// Initialize FILE_HANDLE_STRUCTURE
+ nfh->VolumeInterface = fh->VolumeInterface;
+ nfh->HandleStatus = EFI_SUCCESS;
+ nfh->ROOTDIR = FALSE;
+ pBS->CopyMem (&(nfh->DirectoryEntry), &(Del->DirectoryEntry), sizeof(DIR_ENTRY_32));
+ Wcscpy(nfh->FileNameLFN, Del->FileNameLFN);
+ nfh->DirCluster = Del->Cluster;
+ nfh->DirOffset = Del->Offset;
+ nfh->SlotNumber = Del->SlotNumber;
+ nfh->Parent = fh;
+ *fh1 = nfh;
+
+// Add the new FH to the parent's Child List
+ DListAdd((DLIST *)(UINTN)&(fh->ChildList), (DLINK *)(UINTN)&(nfh->ChildLink));
+
+// Add to VolumeInterface List
+ DListAdd((DLIST *)(UINTN)&(fh->VolumeInterface->OpenFHs), (DLINK *)(UINTN)&(nfh->ViFHLink));
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FindMatchingFH
+//
+// Description: Finds the Child FH, whose name matches with the input.
+// In the Attributes, check whther both are file or Directory
+//
+// Parameters:
+// IN VOLUME_INFO *Vi - Volume info structure
+// IN CHAR16 *NextCompName - Unicode name to compare
+// IN FILE_HANDLE *fh - Parent file handle
+// OUT FILE_HANDLE **fh1 - Child file handle
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ProcessOpenFileHandle
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+BOOLEAN
+FindMatchingFH (
+ IN VOLUME_INFO *Vi,
+ IN CHAR16 *NextCompName,
+ IN FILE_HANDLE *fh,
+ OUT FILE_HANDLE **fh1
+)
+{
+
+
+ DLINK *fhlink = fh->ChildList.pHead;
+ FILE_HANDLE *fh2;
+
+ for ( ; fhlink; ) {
+ fh2 = OUTTER(fhlink, ChildLink, FILE_HANDLE);
+
+ if (!Wcscmpcaseinsensitive (fh2->FileNameLFN, NextCompName)) {
+ if (!(fh2->DirectoryEntry.Dir_Attr & ATTR_VOLUME_ID)) {
+ if (fh2->HandleStatus == EFI_SUCCESS) {
+ *fh1 = fh2;
+ return TRUE;
+ }
+ }
+ }
+
+ fhlink = fhlink->pNext;
+ }
+
+ return FALSE;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FindMatchingDirEntry
+//
+// Description: Finds a directory entry matching the input name
+//
+// Parameters:
+// IN FILE_HANDLE *fh - Directory file handle
+// IN CHAR16 *NextCompName - Unicode name to match
+// OUT DIR_ENTRY_LIST **Del - Directory list where found
+//
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ProcessOpenFileHandle
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+BOOLEAN
+FindMatchingDirEntry (
+ IN FILE_HANDLE *fh,
+ IN CHAR16 *NextCompName,
+ OUT DIR_ENTRY_LIST **Del
+)
+{
+
+ DLINK *dlink = fh->DirList.pHead;
+ DIR_ENTRY_LIST *del;
+
+ for ( ; dlink; ) {
+ del = OUTTER(dlink, DirLink, DIR_ENTRY_LIST);
+
+ if (!Wcscmpcaseinsensitive (del->FileNameLFN, NextCompName)) {
+ if (!(del->DirectoryEntry.Dir_Attr & ATTR_VOLUME_ID)) {
+ *Del = del;
+ return TRUE;
+ }
+ }
+
+ dlink = dlink->pNext;
+ }
+
+ return FALSE;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FindMatchingSFNDirEntry
+//
+// Description: Finds short file name directory entry matching input
+//
+// Parameters:
+// IN FILE_HANDLE *fh - Directory file handle
+// IN CHAR8 *ShortFileName - Name to find
+// OUT DIR_ENTRY_LIST **Del - Directory list where found
+//
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+BOOLEAN
+FindMatchingSFNDirEntry (
+ IN FILE_HANDLE *fh,
+ IN CHAR8 *ShortFileName,
+ OUT DIR_ENTRY_LIST **Del
+)
+{
+
+ DLINK *dlink = fh->DirList.pHead;
+ DIR_ENTRY_LIST *del;
+ UINT8 Attrb;
+
+ for ( ; dlink; ) {
+ del = OUTTER(dlink, DirLink, DIR_ENTRY_LIST);
+ Attrb = del->DirectoryEntry.Dir_Attr;
+ del->DirectoryEntry.Dir_Attr = 0; // Generate a NULL terminated string
+
+ if (!Strcmp((CHAR8 *)&del->DirectoryEntry, ShortFileName)) {
+ del->DirectoryEntry.Dir_Attr = Attrb; // restore Attribute
+ *Del = del;
+ return TRUE;
+ }
+
+ del->DirectoryEntry.Dir_Attr = Attrb; // restore Attribute
+ dlink = dlink->pNext;
+ }
+
+ return FALSE;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: Wcscmpcaseinsensitive
+//
+// Description: Case insensitive unicode string compare
+//
+// Parameters:
+// CHAR16 *string1 - First string
+// CHAR16 *string2 - Second string
+//
+// Return Value:
+// INT - Difference where mis-matched
+//
+// Modified:
+//
+// Referrals: FindMatchingFH, FindMatchingDirEntry
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+int Wcscmpcaseinsensitive(
+ CHAR16 *string1,
+ CHAR16 *string2
+)
+{
+
+ CHAR16 ch1, ch2;
+
+ while (*string1) {
+ if (*string1 >=0x61 && *string1<=0x7a) ch1 = *string1 - 0x20;
+
+ else ch1 = *string1;
+
+ if (*string2 >=0x61 && *string2<=0x7a) ch2 = *string2 - 0x20;
+
+ else ch2 = *string2;
+
+ if (ch1 != ch2) break;
+
+ *string1++;
+ *string2++;
+ }
+
+ return *string1 - *string2; // Don't use ch1 - ch2
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetDirListAtPosition
+//
+// Description: Get directory list at current position in directory file
+//
+// Parameters:
+// FILE_HANDLE *Pfh - Parent file handle
+// UINT64 Position - Current position
+// DIR_ENTRY_LIST **Del - Directory entry list
+//
+// Return Value:
+//
+// Modified:
+//
+// Referrals: ReadFileHandle
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetDirListAtPosition(
+ FILE_HANDLE *Pfh,
+ UINT64 Position,
+ DIR_ENTRY_LIST **Del
+)
+{
+
+ EFI_STATUS Status = EFI_NOT_FOUND;
+ DLINK *dlink = Pfh->DirList.pHead;
+
+ *Del = NULL;
+
+ if (!dlink) return Status;
+
+ while (Position && dlink) {
+ if (!dlink->pNext) break;
+
+ dlink = dlink->pNext;
+ Position--;
+ };
+
+ if (Position == 0 && dlink) {
+ Status = EFI_SUCCESS;
+ *Del = OUTTER(dlink, DirLink, DIR_ENTRY_LIST);
+ }
+
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: CloseFileHandle
+//
+// Description: Closes an open file
+//
+// Parameters:
+// IN EFI_FILE_PROTOCOL *This - File Protocol instance
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: DeleteFileHandle
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+CloseFileHandle (
+ IN EFI_FILE_PROTOCOL *This
+)
+{
+
+ EFI_STATUS Status;
+ FILE_HANDLE_INSTANCE *fhi = (FILE_HANDLE_INSTANCE *)This;
+ FILE_HANDLE *Pfh = fhi->pFH;
+ VOLUME_INFO *vi;
+ void *Buffer;
+ UINT32 BufferSize, Difference;
+ EFI_TPL SaveTpl;
+ EFI_TPL NextTpl;
+
+ Status = ValidateCurrentStatus (fhi);
+ if (EFI_ERROR(Status)) return Status;
+
+#ifdef Debug_CloseFileHandle
+ EfiDebugPrint(-1,"CloseFileHandle: %S Dir Cluster %x Dir Offset %x\n", Pfh->FileNameLFN, Pfh->DirCluster, Pfh->DirOffset);
+#endif
+
+// Device Removal or Media Not Present
+ if (!Pfh) {
+ Status = pBS->FreePool(fhi);
+ return EFI_SUCCESS;
+ }
+ NextTpl = FindNextTpl (EFI_TPL_CALLBACK);
+ SaveTpl = pBS->RaiseTPL (NextTpl);
+ vi = Pfh->VolumeInterface;
+
+// Check if FreeSpace and Last Free Cluster needs to be updated for FAT32
+ if (vi->FatType == FAT32 && vi->FreeSpaceinClusters != -1) {
+ Difference = vi->FreeSpaceinSector1 - vi->FreeSpaceinClusters;
+
+ if (vi->FreeSpaceinSector1 < vi->FreeSpaceinClusters) Difference = vi->FreeSpaceinClusters - vi->FreeSpaceinSector1;
+
+ if (Difference > 0x100) {
+// ReadFSInfo
+ BufferSize = vi->VolumeBPB.BPB_BytePerSec;
+ GetTempBuffer (vi, &Buffer);
+
+ Status = FsReadMedia (vi, Buffer, (UINT64)vi->VolumeBPB.BPB_FAT.BPB_FAT32.BPB_FSInfo, FSI_Free_Count, 8, FAT_REGION);
+
+ if (EFI_ERROR(Status)) goto Memallocate_error;
+
+ *(UINT32 *) ((UINT8 *)Buffer) = vi->FreeSpaceinClusters;
+ *(UINT32 *) ((UINT8 *)Buffer + 4) = vi->LastFreeCluster;
+ Status = FsWriteMedia (vi, Buffer, (UINT64)vi->VolumeBPB.BPB_FAT.BPB_FAT32.BPB_FSInfo, FSI_Free_Count, 8, FAT_REGION);
+ vi->FreeSpaceinSector1 = vi->FreeSpaceinClusters;
+ ReleaseTempBuffer(vi);
+ }
+ }
+
+Memallocate_error:
+
+ if (Pfh->DirEntryChanged == TRUE) {
+ UpdateDirListFromFHDir(Pfh);
+ Pfh->DirEntryChanged = FALSE;
+ }
+
+ DListDelete ((DLIST *)(UINTN)&(vi->OpenFIs), (DLINK *)(UINTN)&(fhi->ViFILink));
+ fsDeAllocateMemory (vi, fhi);
+
+ if (vi->TotalDirEntryList > DIRECTORTY_ENTRIES_CACHED) {
+ if (vi->OpenFHs.Size > MAX_OPEN_FHS) FreeUpFHEntries (vi, NULL);
+
+ FreeUpDirEntries (vi, Pfh->Parent);
+ }
+
+// This should be always after FreeUpDirEntries. When called from
+// DeleteFileHandle will have problem otherwise.
+ if (Pfh) Pfh->InstancesCount -= 1;
+
+ FlushFileHandle(This);
+
+ pBS->RestoreTPL(SaveTpl);
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FreeUpFHEntries
+//
+// Description: Release all file handles whose instance count is 0
+//
+// Parameters:
+// VOLUME_INFO *vi - Volume info
+// FILE_HANDLE *pfh - Parent file handle
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: CloseFileHandle
+//
+// Notes:
+// Don't remove pfh
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FreeUpFHEntries (
+ VOLUME_INFO *vi,
+ FILE_HANDLE *pfh
+)
+{
+
+ DLINK *dlink = vi->OpenFHs.pHead;
+ FILE_HANDLE *lfh;
+
+// Go through all the FHs in Volume Interface and release all whose Instance
+// count is 0, no DIR list is present and childlist is NULL
+// Don't delete:
+// 1. If Instance count is more than 0
+// 2. If Dir List is present,
+// 3. If it is a Root Dir,
+// 4. If Child List is present,
+// 5. If it is a i/p fh
+// 6. If the i/p FH is the parent of the fh.
+ for ( ; dlink; ) {
+ lfh = OUTTER(dlink, ViFHLink, FILE_HANDLE);
+ dlink = dlink->pNext;
+
+ if (lfh->InstancesCount == 0 && !(lfh->DirList.pHead) &&
+ !(lfh->ROOTDIR) && !(lfh->ChildList.pHead) && lfh != pfh) RemoveFH(lfh);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FreeUpDirEntries
+//
+// Description: Free up cached directory entries
+//
+// Parameters:
+// VOLUME_INFO *vi - Volume info
+// FILE_HANDLE *pfh - Parent file handle
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ReadAllDirectoryEntries, CloseFileHandle
+//
+// Notes:
+// Don't remove pfh
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FreeUpDirEntries (
+ VOLUME_INFO *vi,
+ FILE_HANDLE *pfh
+)
+{
+
+ DLINK *dlink = vi->OpenFHs.pHead;
+ FILE_HANDLE *lfh;
+
+ for ( ; dlink; ) {
+ if (vi->TotalDirEntryList <= DIRECTORTY_ENTRIES_CACHED) break;
+
+ lfh = OUTTER(dlink, ViFHLink, FILE_HANDLE);
+
+ if (lfh != pfh && lfh->DirList.pHead) RemoveAllDirList(lfh);
+
+ dlink = dlink->pNext;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: RemoveAllDirList
+//
+// Description: Removes all directory lists from cache (needs to be re-read)
+//
+// Parameters:
+// FILE_HANDLE *lfh - list file handle
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ReadFileHandle, DeleteFileHandle, FreeUpDirEntries
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+RemoveAllDirList(
+ FILE_HANDLE *lfh
+)
+{
+
+ DLINK *dlink = lfh->DirList.pHead;
+ DIR_ENTRY_LIST *Del;
+
+ for ( ; dlink; ) {
+ Del = OUTTER(dlink, DirLink, DIR_ENTRY_LIST);
+ dlink = dlink->pNext;
+ RemoveDirList (lfh, Del);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: RemoveDirList
+//
+// Description: Removes a directory list from cache
+//
+// Parameters:
+// FILE_HANDLE *fh - Directory file handle
+// DIR_ENTRY_LIST *Del - Directory list
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: DeleteFileHandle, RemoveAllDirList
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+RemoveDirList (
+ FILE_HANDLE *fh,
+ DIR_ENTRY_LIST *Del
+)
+{
+
+ fh->VolumeInterface->TotalDirEntryList--;
+
+ fsDeAllocateMemory (fh->VolumeInterface, Del->FileNameLFN);
+ DListDelete ((DLIST *)(UINTN)&(fh->DirList), (DLINK *)(UINTN)&(Del->DirLink));
+ fsDeAllocateMemory (fh->VolumeInterface, Del);
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FetchLongName
+//
+// Description: Fetch a long name from a directory entry
+//
+// Parameters:
+// FILE_HANDLE *fh - File handle of the directory
+// DIR_ENTRY_32 *Buffer - Buffer containing directory entry
+// UINT32 BufferPos - Position in buffer
+// UINT16 *Name - Unicode name placed here
+// UINT32 ClusterNumber - Current directory cluster
+// UINT32 ClusterSize - Cluster size in bytes
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ReadAllDirectoryEntries
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8
+FetchLongName (
+ FILE_HANDLE *fh,
+ DIR_ENTRY_32 *Buffer,
+ UINT32 BufferPos,
+ UINT16 *Name,
+ UINT32 ClusterNumber,
+ UINT32 ClusterSize
+)
+{
+
+ DIR_ENTRY_LFN *LfnSlot = (DIR_ENTRY_LFN *) ((UINT8 *)Buffer + BufferPos);
+ UINT8 Checksum = LfnChecksum((UINT8 *) Buffer + BufferPos);
+ CHAR8 Order = 0;
+ UINT32 NamePos = 0;
+ UINT32 k;
+ UINT32 Cluster = 0;
+ EFI_STATUS Status;
+ BOOLEAN Backup = FALSE;
+
+ do {
+ if (--LfnSlot < (DIR_ENTRY_LFN *) Buffer) { // Long name is split over 2 clusters
+ Status = ReadClusterOfDirectoryEntries(fh, ClusterNumber-1, &Cluster, (UINT8*)Buffer, &ClusterSize);
+ Backup = TRUE; // We had to back up into the previous cluster to get the whole name
+ if (EFI_ERROR(Status) || (Status == EFI_SUCCESS && ClusterSize == 0)) { Order = 0; goto exit; };
+ LfnSlot = (DIR_ENTRY_LFN *) ((UINT8 *)Buffer + ClusterSize);
+ LfnSlot--;
+ }
+ if (Order > MAX_LFN_SLOTS) { Order = 0; goto exit; }; // Max of 20 LFN slots are possible 255 chars max.
+
+ if ((LfnSlot->Dir_Attr & ATTR_LONG_NAME_MASK) != (ATTR_LONG_NAME)) { Order = 0; goto exit; };
+
+ if (++Order != (LfnSlot->Dir_Order & 0x1F)) { Order = 0; goto exit; };
+
+ if (Checksum != LfnSlot->Dir_Checksum) { Order = 0; goto exit; };
+
+ // Ok, the LFN slot is valid, attach it to the long name
+ for (k = 0; k < 5; k++) Name[NamePos++] = LfnSlot->Dir_Name0_4[k];
+
+ for (k = 0; k < 6; k++) Name[NamePos++] = LfnSlot->Dir_Name5_10[k];
+
+ for (k = 0; k < 2; k++) Name[NamePos++] = LfnSlot->Dir_Name11_12[k];
+ } while (!(LfnSlot->Dir_Order & 0x40));
+
+// If the name was exactly 13 characters long in the last slot, add a terminating zero.
+// Otherwise, it will already end in a zero.
+ if (Name[NamePos - 1] != 0x0000) Name[NamePos] = 0x0000;
+exit:
+ if (Backup) { // Re-read the old cluster if we had to back up
+ Status = ReadClusterOfDirectoryEntries(fh, ClusterNumber, &Cluster, (UINT8*)Buffer, &ClusterSize);
+ if (EFI_ERROR(Status)) Order = 0;
+ }
+ return Order;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: LfnChecksum
+//
+// Description: Calculate long file name entry section checksum
+//
+// Parameters:
+// UINT8 *D - Pointer to long name entry
+//
+//
+// Return Value:
+// UINT8 - Checksum
+//
+// Modified:
+//
+// Referrals: FetchLongName
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT8
+LfnChecksum(
+ UINT8 *D
+)
+{
+ UINT8 Sum = 0;
+ UINT8 i;
+
+ for (i = 11; i != 0; i--) {
+ Sum = ((Sum & 1) ? 0x80 : 0) + (Sum >> 1) + *D++;
+ }
+
+ return Sum;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FindShortName
+//
+// Description: Return a valid short name Directory Entry from DirCluster
+// beginning from ReadPosition.
+//
+// Parameters:
+// UINT8 *Buffer - Buffer to search in
+// UINT32 *Offset - Offset in buffer where entry found
+// UINT32 BufferSize - Size of buffer
+//
+//
+// Return Value:
+// BOOLEAN - True = name found
+//
+// Modified:
+//
+// Referrals: ReadAllDirectoryEntries
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+BOOLEAN
+FindShortName (
+ UINT8 *Buffer,
+ UINT32 *Offset,
+ UINT32 BufferSize
+)
+{
+ DIR_ENTRY_32 *Entry = (DIR_ENTRY_32 *)(Buffer + *Offset);
+ UINT32 i;
+
+ for (i = *Offset; BufferSize; i+=sizeof(DIR_ENTRY_32),BufferSize-=sizeof(DIR_ENTRY_32)) {
+ if (Entry->Dir_Name[0] == 0) {
+ *Offset = (UINTN)-1;
+ return FALSE; // no more directory Entries.
+ }
+
+ if (((Entry->Dir_Attr & ATTR_LONG_NAME_MASK) != (ATTR_LONG_NAME)) &&
+ (Entry->Dir_Name[0] > 0x1f) &&
+ (Entry->Dir_Name[0] != 0xe5)) {
+ *Offset = i; // Point offset to short name found
+
+ return TRUE;
+ }
+
+ Entry++;
+ }
+
+ return FALSE;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: CreateDirectoryEntry
+//
+// Description: Creates a directory entry
+//
+// Parameters:
+// IN FILE_HANDLE *fh - File handle
+// IN CHAR16 *NextCompName - Unicode name to create
+// OUT FILE_HANDLE **fh1 - File handle for new name
+// IN UINT64 Attributes
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ProcessOpenFileHandle
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+CreateDirectoryEntry (
+ IN FILE_HANDLE *fh,
+ IN CHAR16 *NextCompName,
+ OUT FILE_HANDLE **fh1,
+ IN UINT64 Attributes
+)
+{
+
+ EFI_STATUS Status;
+ UINT32 DirCluster, DirClusterOffset;
+ UINT32 Length;
+ CHAR8 DirEntry[32];
+ DIR_ENTRY_32 *Entry = (DIR_ENTRY_32 *) &DirEntry;
+ CHAR16 *lfn;
+ DIR_ENTRY_LIST *Del;
+
+ Status = CreateDirEntryInDisk (fh, NextCompName, Attributes, &DirCluster, &DirClusterOffset, Entry);
+
+ if (EFI_ERROR(Status)) return Status;
+
+// Create a Dir_List Entry
+ Length = (UINT32)(Wcslen(NextCompName) * sizeof(CHAR16)) + 2;
+ Status = fsAllocateMemory(fh->VolumeInterface, (UINT32) Length, (VOID**)&lfn, FALSE);
+ pBS->CopyMem(lfn, NextCompName, Length);
+ AddToDirList (fh, *Entry, lfn, DirCluster, DirClusterOffset, (UINTN)-1);
+
+ Del = OUTTER(fh->DirList.pTail, DirLink, DIR_ENTRY_LIST);
+// Create a File Handle
+ Status = CreateFHFromDirEntryList(Del, fh, fh1);
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: CreateDirEntryInDisk
+//
+// Description: Creates a directory entry on the disk
+//
+// Parameters:
+// IN FILE_HANDLE *fh - File handle
+// IN CHAR16 *NextCompName - Name to create
+// IN UINT64 Attributes - Attributes for entry
+// OUT UINT32 *DirCluster - Cluster of entry created
+// OUT UINT32 *DirClusterOffset - Offset in cluster
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: CreateDirectoryEntry
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+CreateDirEntryInDisk (
+ IN FILE_HANDLE *fh,
+ IN CHAR16 *NextCompName,
+ IN UINT64 Attributes,
+ OUT UINT32 *DirCluster,
+ OUT UINT32 *DirClusterOffset,
+ DIR_ENTRY_32 *Entry
+)
+{
+
+ EFI_STATUS Status;
+ VOLUME_INFO *Vi = fh->VolumeInterface;
+ CHAR8 ShortFileName[11];
+ EFI_TIME EfiTime;
+ EFI_TIME_CAPABILITIES Capabilities;
+ UINT32 Sector, SectorOffset;
+ BOOLEAN LastDirEntry = FALSE;
+ UINT32 Length;
+ BOOLEAN LfnNeeded = FALSE;
+ UINT8 *Slots;
+ UINT32 NumSlots = 0;
+
+ if (Vi->ReadOnly) return EFI_WRITE_PROTECTED;
+
+ Status = GenUniqueShortFname (fh, NextCompName, ShortFileName, &LfnNeeded);
+
+ if (EFI_ERROR(Status)) return Status;
+
+// Create Short Directory entry
+ Zeromemory (Entry, sizeof(DIR_ENTRY_32));
+ pBS->CopyMem(Entry, ShortFileName, 11);
+ Entry->Dir_Attr = (UINT8)Attributes;
+ pRS->GetTime(&EfiTime, &Capabilities);
+ EfiToFatTime (EfiTime, &Entry->Dir_CrtDate, &Entry->Dir_CrtTime);
+ Entry->Dir_LstAccDate = Entry->Dir_CrtDate;
+ Entry->Dir_WrtTime = Entry->Dir_CrtTime;
+ Entry->Dir_WrtDate = Entry->Dir_CrtDate;
+
+// Update the Cluster number in case of '.' entry.
+ if (NextCompName[0] == '.' && NextCompName[1] == 0) {
+ Length = FIRSTCLUSTER(fh->DirectoryEntry);
+ Entry->Dir_FstClusHI = (UINT16) (Length >> 16);
+ Entry->Dir_FstClusLO = (UINT16) Length;
+ }
+
+
+ fsAllocateMemory (Vi, (MAX_LFN_SLOTS + 2) * sizeof(DIR_ENTRY_32), (void **)&Slots, FALSE);
+
+ if (LfnNeeded) {
+ Status = SplitLFN (NextCompName, Entry, (DIR_ENTRY_LFN *)Slots, &NumSlots);
+
+ if (EFI_ERROR(Status)) goto Error;
+ }
+
+// Assuming a short filename FILENAME.EXT (FILENAMEEXT), generate a
+// name in the form FILENA~1.EXT, where n is a count beginning with 1.
+// GenUniqueFileName(fh, NextCompName, &ShortFileName);
+
+// Append Short Directory Entry at the End of Long File Name slots
+ Length = NumSlots * sizeof(DIR_ENTRY_32);
+ pBS->CopyMem(Slots + Length, Entry, sizeof(DIR_ENTRY_32));
+ Length += sizeof(DIR_ENTRY_32); // This is the total length
+
+ Status = LocateFreeDirEntry(fh, Length, DirCluster,
+ DirClusterOffset, &LastDirEntry);
+
+ if (EFI_ERROR(Status)) goto Error;
+
+ GetSectorAddressDir(fh, *DirCluster, *DirClusterOffset, &Sector, &SectorOffset);
+ Status = FsWriteMedia (Vi, Slots, Sector, SectorOffset, Length, DIRECTORY_REGION);
+
+ if (EFI_ERROR(Status)) goto Error;
+
+ *DirClusterOffset += Length;
+
+ if (LastDirEntry == TRUE) {
+ fh->FreeDirEntryCluster = *DirCluster;
+ fh->FreeDirEntryOffset = *DirClusterOffset;
+
+ } else {
+ fh->DirListChanged = TRUE;
+ }
+
+ *DirClusterOffset -= sizeof(DIR_ENTRY_32);
+
+Error:
+
+ fsDeAllocateMemory (Vi, Slots);
+
+ return Status;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetTempBuffer
+//
+// Description: Gets a temporary buffer
+//
+// Parameters:
+// VOLUME_INFO *Vi - Volume info
+// VOID **Buffer - Buffer
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ProcessOpenFileHandle, ReadAllDirectoryEntries, CloseFileHandle
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+GetTempBuffer (
+ VOLUME_INFO *Vi,
+ VOID **Buffer
+)
+{
+
+ *Buffer = (UINT8 *)(Vi->TempBuffer);
+ Vi->TempBufferInUse = TRUE;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ReleaseTempBuffer
+//
+// Description: Releases a temporary buffer
+//
+// Parameters:
+// VOLUME_INFO *Vi - Volume Info
+//
+// Return Value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals: ProcessOpenFileHandle, ReadAllDirectoryEntries, CloseFileHandle
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+ReleaseTempBuffer (
+ VOLUME_INFO *Vi
+)
+{
+ Vi->TempBufferInUse = FALSE;
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2011, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
diff --git a/Core/EM/FileSystem/VolFatHandler.c b/Core/EM/FileSystem/VolFatHandler.c
new file mode 100644
index 0000000..ce73b6b
--- /dev/null
+++ b/Core/EM/FileSystem/VolFatHandler.c
@@ -0,0 +1,1419 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Core/Modules/FileSystem/VolFatHandler.c 9 12/02/09 9:29a Pats $
+//
+// $Revision: 9 $
+//
+// $Date: 12/02/09 9:29a $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Core/Modules/FileSystem/VolFatHandler.c $
+//
+// 9 12/02/09 9:29a Pats
+// EIP 32115: The fat driver in aptio does not calculate free space
+// correctly.
+// Solution: AllocateAndLinkClusters() changed to calculate new cluster
+// for free space differently, and to fix error path.
+//
+// 8 7/02/09 5:47p Pats
+// Updated to latest coding standard. No code changes.
+//
+// 7 5/17/07 4:00p Srinin
+// Uninitialized varaible FreeClusters in UpdateFreeSpace initialized.
+//
+// 6 4/13/07 7:07p Pats
+// Edited to conform with coding standards. No code changes.
+//
+// 5 4/05/07 12:14p Pats
+// Fixed GetFreeClusterCount function. BufferSize variable was not being
+// handled properly on large disks.
+//
+// 4 9/13/06 5:57p Pats
+// Fixed problem of free space reported incorrectly on El Torito CD.
+//
+// 7 11/03/05 2:16p Srinin
+// Fixed VC7.1 warning msg.
+//
+// 6 9/14/05 4:30p Pats
+// Fixed problem of free disk space being calculated incorrectly in some
+// cases.
+//
+// 5 7/19/05 2:58p Pats
+// Removed a little unnecessary code and added comments.
+//
+// 4 6/21/05 3:45p Pats
+// Added function MarkVolumeDirty, to mark FAT16 and FAT32 volumes if any
+// EFI_VOLUME_CORRUPTED error occurs.
+//
+// 3 6/16/05 4:18p Pats
+// Fixed problem in UnlinkFat -- did not unlink FAT12 files properly in
+// every case.
+//
+// 2 5/27/05 10:02a Srinin
+// Fix for free space calculation.
+//
+// 1 4/26/05 6:05p Srinin
+//
+//
+//**********************************************************************
+
+//<AMI_FHDR_START>
+//----------------------------------------------------------------------
+//
+// Name: VolFatHndlr.c
+//
+// Description: Fat File System driver -- Volume Level Fat Handler
+//
+//----------------------------------------------------------------------
+//<AMI_FHDR_END>
+
+//----------------------------------------------------------------------
+
+#include "FileSystem.h"
+
+//----------------------------------------------------------------------
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetSectorAddressDir
+//
+// Description: Gets the absolute sector of a directory
+//
+// Parameters:
+// FILE_HANDLE *fh - File Handle
+// UINT32 Cluster - Cluster of directory
+// UINT32 ClusterOffset - Offset in cluster
+// UINT32 *Sector - Absolute sector of directory
+// UINT32 *SectorOffset - Offset in sector
+//
+// Return value: None
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes: Use this routine if DIR region neeeds to be Read/Written.
+// For Data Region or FAT32 ROOT dir use GetAbsSectorInfo
+// For FAT12/16 root dir, Cluster is not valid. ClusterOffset
+// is the relative offset within the Root Dir Region.
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+GetSectorAddressDir (
+ FILE_HANDLE *fh,
+ UINT32 Cluster,
+ UINT32 ClusterOffset,
+ UINT32 *Sector,
+ UINT32 *SectorOffset
+)
+{
+ VOLUME_INFO *vi = fh->VolumeInterface;
+
+ if (fh->ROOTDIR && (vi->FatType != FAT32)) {
+ *Sector = ClusterOffset / vi->VolumeBPB.BPB_BytePerSec + vi->FirstRootDirSector;
+ *SectorOffset = ClusterOffset % vi->VolumeBPB.BPB_BytePerSec;
+
+ } else {
+ GetAbsSectorInfo (vi, Cluster, ClusterOffset, Sector, SectorOffset);
+ }
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FatClusterNumberLocation
+//
+// Description: Returns the location (sector and offset) of a valid cluster
+// number in the specified FAT.
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN UINTN Cluster, A cluster number
+// IN UINTN FatNumber, The fat number (0 or 1)
+//
+// Return value:
+// EFI_STATUS
+// EFI_SUCCESS - Cluster located
+// OUT UINT32 *Sector, Fat sector in which cluster is located
+// OUT UINT32 *SectorOffset Offset in the sector where cluster is
+// other - Cluster not located
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FatClusterNumberLocation (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ IN UINT8 FatNumber,
+ OUT UINT32 *Sector,
+ OUT UINT32 *SectorOffset
+)
+{
+ UINT32 FatOffset;
+
+ if (Cluster > Vol->CountOfDataClusters + 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (Vol->FatType) {
+ case FAT12:
+ FatOffset = Cluster + (Cluster / 2);
+ break;
+ case FAT16:
+ FatOffset = Cluster * 2;
+ break;
+ case FAT32:
+ FatOffset = Cluster * 4;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ *Sector = FatNumber * Vol->FATSz + Vol->VolumeBPB.BPB_RsvdSecCnt
+ + FatOffset / Vol->VolumeBPB.BPB_BytePerSec;
+ *SectorOffset = FatOffset % Vol->VolumeBPB.BPB_BytePerSec;
+ return EFI_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ReadFatClusterNumber
+//
+// Description: Reads a single cluster number from the specified fat table
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN UINTN Cluster, A cluster number
+// IN UINT8 FatNumber, The fat number (0 or 1)
+// OUT UINT32 *Value The returned cluster number
+//
+// Return value:
+// EFI_STATUS
+// EFI_SUCCESS - Cluster read
+// other - Cluster not read
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+ReadFatClusterNumber (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ IN UINT8 FatNumber,
+ OUT UINT32 *Value
+)
+{
+ EFI_STATUS Status;
+ UINT32 Sector = 0;
+ UINT32 SectorOffset = 0;
+ UINT32 ValueSize;
+
+ Status = FatClusterNumberLocation(Vol, Cluster, FatNumber, &Sector, &SectorOffset);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (Vol->FatType == FAT32) ValueSize = sizeof(UINT32);
+
+ else ValueSize = sizeof(UINT16);
+
+ Status = FsReadMedia (Vol,
+ (UINT8 *)Value,
+ (UINT64)Sector,
+ SectorOffset,
+ ValueSize,
+ FAT_REGION);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ switch (Vol->FatType) {
+ case FAT12:
+
+ if (Cluster & 0x0001) *Value >>= 4;
+
+ *Value &= 0x0fff;
+ break;
+ case FAT16:
+ *Value &= 0x0ffff;
+ break;
+ case FAT32:
+ *Value &= 0x0fffffff; // FAT32 actually uses 28 bits
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: WriteFatClusterNumber
+//
+// Description: Writes a single cluster number into the specified FAT table
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN UINTN Cluster, A cluster number
+// IN UINT8 FatNumber, The fat number (0 or 1)
+// IN UINT32 Value The cluster value to be written
+//
+// Return value:
+// EFI_STATUS
+// EFI_SUCCESS - Cluster written
+// other - Cluster not written
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+WriteFatClusterNumber (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ IN UINT8 FatNumber,
+ IN UINT32 Value
+)
+{
+ EFI_STATUS Status;
+ UINT32 Sector = 0;
+ UINT32 SectorOffset = 0;
+ UINT32 TempValue;
+ UINT32 ValueSize;
+
+ Status = FatClusterNumberLocation(Vol, Cluster, FatNumber, &Sector, &SectorOffset);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (Vol->FatType == FAT32) ValueSize = sizeof(UINT32);
+
+ else ValueSize = sizeof(UINT16);
+
+ switch (Vol->FatType) {
+ case FAT12:
+ Status = FsReadMedia (Vol,
+ (UINT8 *)&TempValue,
+ (UINT64)Sector,
+ SectorOffset,
+ ValueSize,
+ FAT_REGION);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (Cluster & 0x0001) {
+ Value <<= 4;
+ TempValue &= 0x000f;
+
+ } else {
+ Value &= 0x0FFF;
+ TempValue &= 0xf000;
+ }
+
+ TempValue |= (UINT16)Value;
+ break;
+ case FAT16:
+ TempValue = (UINT16)Value;
+ break;
+ case FAT32:
+ Value &= 0x0fffffff;
+ TempValue = Value;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = FsWriteMedia (Vol,
+ (UINT8 *)&TempValue,
+ (UINT64)Sector,
+ SectorOffset,
+ ValueSize,
+ FAT_REGION);
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: AllocateAndLinkClusters
+//
+// Description: Allocates clusters for use in a file
+//
+// Parameters:
+// IN VOLUME_INFO *Vol - Volume info
+// IN UINT32 BeginCluster - Beginning cluster no.
+// IN UINT32 Size - Size to allocate
+// OUT UINT32 *FirstCluster - First cluster allocated
+// OUT UINT32 *ClusterCount - Count of clusters allocated
+//
+// Return value: EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+AllocateAndLinkClusters (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 BeginCluster,
+ IN UINT32 Size,
+ OUT UINT32 *FirstCluster,
+ OUT UINT32 *ClusterCount
+)
+{
+
+ UINT32 ClustersRequired, NewCluster = 2, Dummy, NewBlocks, k, j;
+ EFI_STATUS Status;
+
+ *FirstCluster = 0;
+ *ClusterCount = 0;
+
+// Calculate the # of Clusters required.
+ ClustersRequired = GetClustersRequired (Vol, Size);
+
+ if (Vol->FreeSpaceinClusters != -1 && Vol->FreeSpaceinClusters < ClustersRequired)
+ return EFI_VOLUME_FULL;
+
+ do {
+
+ NewBlocks = ClustersRequired;
+
+ if (Vol->LastFreeCluster != -1) NewCluster = Vol->LastFreeCluster;
+ else {
+ Status = ReturnFreeSpace(Vol);
+ NewCluster = Vol->LastFreeCluster;
+ if (EFI_ERROR(Status)) return Status;
+ }
+
+ Status = FindFreeClusters(Vol, NewCluster, Vol->CountOfDataClusters+2, &NewCluster, &NewBlocks, &Dummy);
+ if (EFI_ERROR(Status)) {
+ if (Status == EFI_NOT_FOUND && NewCluster != 2) {
+// No cluster found after the current one, try from the start of the disk.
+ NewBlocks = ClustersRequired;
+ Status = FindFreeClusters(Vol, 2, Vol->CountOfDataClusters+2, &NewCluster, &NewBlocks, &Dummy);
+ if (EFI_ERROR(Status)) {
+ if (Status == EFI_NOT_FOUND) return EFI_VOLUME_FULL; else return Status;
+ }
+ }
+ else if (Status == EFI_NOT_FOUND) return EFI_VOLUME_FULL;
+ if (EFI_ERROR(Status)) return Status;
+ }
+
+ if (!*FirstCluster) *FirstCluster = NewCluster;
+
+// Add new cluster(s) to fat chain.
+ for (k=1; k <= NewBlocks; k++) {
+
+ for (j=0; j < Vol->VolumeBPB.BPB_NumFATs; j++) { // Update all fats.
+// Chain the new cluster
+ if (BeginCluster >=2) {
+ Status = WriteFatClusterNumber(Vol, BeginCluster, j, NewCluster);
+ if (EFI_ERROR(Status)) return Status;
+ }
+// Update the EOCfot the Last Block
+ Status = WriteFatClusterNumber(Vol, NewCluster, j, Vol->EOCMark);
+ if (EFI_ERROR(Status)) return Status;
+ } // end of j
+
+#ifdef Debug_AllocateClusters
+ EfiDebugPrint(-1,"%x", NewCluster);
+#endif
+
+ BeginCluster = NewCluster;
+ NewCluster++;
+ } // end for (k)
+ *ClusterCount += NewBlocks;
+ ClustersRequired -= NewBlocks;
+ UpdateFreeSpace (Vol, NewBlocks, FALSE); // Subtract from Free space
+ }while (ClustersRequired);
+
+ return EFI_SUCCESS;
+}
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: UnlinkFat
+//
+// Description: Unlinks (marks as free) all the clusters of the chain
+// starting from cluster Cluster (that must be part of a valid
+// chain) until the EOC.
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN UINTN Cluster A cluster number
+//
+// Return value:
+// EFI_STATUS
+// EFI_SUCCESS - Chain unlinked.
+// other - Chain not unlinked
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+UnlinkFat (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ OUT UINT32 *ClusterCount
+)
+{
+ EFI_STATUS Status;
+ UINT8 i;
+ UINT32 Next;
+
+ *ClusterCount = 0;
+
+ do {
+ if (!Cluster) return EFI_NOT_FOUND;
+
+ Status = ReadFatClusterNumber(Vol, Cluster, 0, &Next);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (Next < 2) {
+ MarkVolumeDirty (Vol);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ /* Update every FAT in the volume */
+ for (i = 0; i < Vol->VolumeBPB.BPB_NumFATs; i++) {
+ Status = WriteFatClusterNumber(Vol, Cluster, i, 0);
+
+ if (EFI_ERROR(Status)) return Status;
+ }
+
+ Cluster = Next;
+ ++*ClusterCount;
+ } while (Next < Vol->EOCMark); // Repeat till end of chain found.
+
+ UpdateFreeSpace (Vol, *ClusterCount, TRUE); // Add to Free space
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: FindFreeClusters
+//
+// Description: Searches a volume for a free cluster in the specified range
+// of clusters.
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN UINT32 From, Cluster to start search at
+// IN UINT32 To, End of search range
+// OUT UINT32 *StartCluster Free cluster found
+// IN OUT UINT32 *FreeClusters In - free clustere requested.
+// Out - Free clusters found
+// OUT UINT32 *TotalFree Total free clusters found in this
+// search
+//
+// Return value:
+// EFI_STATUS
+// EFI_SUCCESS - Free cluster found, Vol->LastFreeCluster updated.
+// EFI_NOT_FOUND - Free cluster not found.
+// other - any other error.
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+FindFreeClusters (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 From,
+ IN UINT32 To,
+ OUT UINT32 *StartCluster,
+ IN OUT UINT32 *FreeClusters,
+ OUT UINT32 *TotalFree
+)
+{
+ EFI_STATUS Status;
+ UINT32 Count = 0;
+ UINT32 FreeCount = 0;
+ UINT32 LastFree = 0;
+ UINT32 FreeBlock = 0;
+ UINT32 PrevFreeCount, PrevFreeBlock;
+ UINT32 i;
+ UINT32 Value;
+
+// if (From == 0) return (FindNextFreeCluster (Vol, Cluster));
+
+ for (i = From; i < To; i++) {
+ Status = ReadFatClusterNumber(Vol, i, 0, &Value);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (Value == 0) {
+ Count++;
+
+ if (i != (LastFree + 1)) {
+ PrevFreeBlock = FreeBlock;
+ PrevFreeCount = FreeCount;
+ FreeBlock = i; // Reset free block if not contiguous
+ FreeCount = 0; // Restart free count
+ }
+
+ LastFree = i;
+ FreeCount++;
+
+ if (FreeCount >= *FreeClusters) { // If we found the requested count
+ *FreeClusters = FreeCount;
+ *StartCluster = Vol->LastFreeCluster = FreeBlock;
+ *TotalFree = Count;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ if (Count) {
+ *TotalFree = Count;
+
+ if (FreeCount > PrevFreeCount) { // in case the last free block is not the largest.
+ *StartCluster = FreeBlock;
+ *FreeClusters = FreeCount;
+
+ } else {
+ *StartCluster = PrevFreeBlock;
+ *FreeClusters = PrevFreeCount;
+ }
+
+ return EFI_SUCCESS;
+
+ } else return EFI_NOT_FOUND;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ClusterToSector
+//
+// Description: Converts a custer number to an absolute sector number
+// (relative to the beginning of the volume).
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// OUT UINTN Cluster The cluster to be converted
+//
+// Return value:
+// Returns the sector number.
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT32
+ClusterToSector (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster
+)
+{
+ UINT32 Offset;
+ UINT32 Sector;
+
+ Offset = Vol->VolumeBPB.BPB_RsvdSecCnt + Vol->FATSz * Vol->VolumeBPB.BPB_NumFATs +
+ Vol->RootDirSectorCount;
+
+ if (Cluster) Sector = (Cluster - 2) * (UINT32)Vol->VolumeBPB.BPB_SecPerClus + Offset;
+
+ else Sector = Offset;
+
+ return Sector;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: SectorToCluster
+//
+// Description: Converts an absolute sector number (relative to the beginning
+// of a volume) to a cluster number, and the sector within that
+// cluster.
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// OUT UINTN Sector The sector to be converted
+//
+// Return value:
+// Sector - The sector offset in the returned cluster.
+// Returns the sector number.
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT32
+SectorToCluster (
+ IN VOLUME_INFO *Vol,
+ IN OUT UINT32 Sector
+)
+{
+ UINT32 Temp1;
+ UINT32 Temp2;
+
+ // Calculate offset to 1st data sector
+ Temp1 = Vol->VolumeBPB.BPB_RsvdSecCnt + Vol->FATSz * Vol->VolumeBPB.BPB_NumFATs +
+ Vol->RootDirSectorCount;
+ Temp2 = Sector - Temp1; // "Normalize" the sector
+ Temp1 = Temp2 / (UINT32)Vol->VolumeBPB.BPB_SecPerClus; // Calculate the cluster number
+ Sector = Temp2 % (UINT32)Vol->VolumeBPB.BPB_SecPerClus; // Get sector within cluster
+ return Temp1 + 2; // Account for first cluster being no. 2
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetClusterCount
+//
+// Description: Gets the cluster count of a file (usually a directory,
+// because Dir_FileSize is zero for these, and we need to
+// know the file size).
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN OUT UINT32 Cluster In - the first cluster. Out - count
+//
+// Return value:
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetClusterCount (
+ IN VOLUME_INFO *Vol,
+ IN OUT UINT32 Cluster
+)
+{
+ UINT32 Count = 0;
+ UINT32 TempCluster = 0;
+
+ // If the first cluster is EOC, return a count of 0.
+ if (Cluster >= Vol->EOCMark) {
+ Cluster = Count;
+ return EFI_SUCCESS;
+ }
+
+ // Follow the chain and count the clusters until EOC.
+ do {
+ ReadFatClusterNumber(Vol, Cluster, 0, &TempCluster);
+
+ if (TempCluster < 2) {
+ MarkVolumeDirty (Vol);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ Count++;
+ Cluster = TempCluster;
+ } while (Cluster < Vol->EOCMark);
+
+ // Return the count in Cluster.
+ Cluster = Count;
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetClustersRequired
+//
+// Description: Gets the amount of clusters required to store N blocks.
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN UINT32 N A byte count
+//
+// Return value:
+// Returns the required clusters.
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT32
+GetClustersRequired (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 N
+)
+{
+ return (N + Vol->BytesPerCluster - 1) / (Vol->BytesPerCluster);
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetContiguousClusters
+//
+// Description: Gets the nunber of contiguous clusters starting from the
+// specified cluster
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN OUT UINT32 Cluster The cluster to start with
+//
+// Return value:
+// Returns the number of contiguous clusters in Cluster.
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetContiguousClusters (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Size,
+ IN UINT32 Cluster,
+ OUT UINT32 *NextCluster,
+ OUT UINT32 *Count
+)
+{
+ EFI_STATUS Status;
+ UINT32 TotalBytes;
+
+ if (Cluster == Vol->EOCMark) {
+ *Count = 0;
+ return EFI_SUCCESS;
+ }
+
+ *Count = 1;
+
+ TotalBytes = Vol->BytesPerCluster;
+
+ do {
+ Status = ReadFatClusterNumber(Vol, Cluster, 0, NextCluster);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (TotalBytes >= Size) break;
+
+ if (*NextCluster >= Vol->EOCMark) break;
+
+ if (*NextCluster < 2) {
+ MarkVolumeDirty (Vol);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ if (*NextCluster == (Cluster + 1)) {
+ ++*Count;
+ TotalBytes += Vol->BytesPerCluster;
+ Cluster = *NextCluster;
+ }
+ } while (Cluster == *NextCluster);
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetClusterPosition
+//
+// Description: Gets the nunber of contiguous clusters starting from the
+// specified cluster
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN OUT UINT32 Cluster The cluster to start with
+//
+// Return value:
+// Returns the number of contiguous clusters in Cluster.
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetClusterPosition (
+ IN FILE_HANDLE_INSTANCE *File,
+ IN UINT64 Position,
+ OUT UINT32 *Cluster,
+ OUT UINT32 *ClusterOffset
+)
+{
+ EFI_STATUS Status;
+ VOLUME_INFO *Vol = File->pFH->VolumeInterface;
+ UINT32 ClusterCount;
+ UINT32 TempCluster, NextCluster;
+ UINT32 i;
+
+
+ NextCluster = TempCluster = FIRSTCLUSTER(File->pFH->DirectoryEntry);
+// Get the count of clusters that Position is from the beginning of the file.
+ ClusterCount = (UINT32)Position / Vol->BytesPerCluster;
+ *Cluster = 0;
+ *ClusterOffset = 0;
+
+ if (TempCluster) {
+ for (i=0; i<ClusterCount; i++, TempCluster = NextCluster) {
+ Status = ReadFatClusterNumber(Vol, TempCluster, 0, &NextCluster);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ if (NextCluster >= Vol->EOCMark) break;
+ }
+
+// Is the Position is set to EOF, then cluster will be the last valid
+// cluster and offset set to Vol->BytesPerCluster
+// else Cluster and cluster offset will be a valid pointer to the
+// Position
+ *Cluster = NextCluster;
+ *ClusterOffset = (UINT32)Position % Vol->BytesPerCluster;
+
+ if (!*ClusterOffset) {
+ if (NextCluster >= Vol->EOCMark) {
+ File->CurrentCluster = TempCluster;
+ File->CurrentClusterOffset = Vol->BytesPerCluster;
+ }
+ }
+ }
+
+//TODO TODO
+// Should be removed later
+// if (*Cluster >= Vol->EOCMark) {
+// _asm jmp $
+// }
+//TODO TODO
+
+ return EFI_SUCCESS;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetAbsSectorInfo
+//
+// Description: Gets the nunber of contiguous clusters starting from the
+// specified cluster
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// IN OUT UINT32 Cluster The cluster to start with
+//
+// Return value:
+// Returns the number of contiguous clusters in Cluster.
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+VOID
+GetAbsSectorInfo (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 Cluster,
+ IN UINT32 ClusterOffset,
+ OUT UINT32 *Sector,
+ OUT UINT32 *SectorOffset
+)
+{
+ *Sector = ClusterToSector(Vol, Cluster) + (ClusterOffset / (UINT32)Vol->VolumeBPB.BPB_BytePerSec);
+ *SectorOffset = ClusterOffset % (UINT32)Vol->VolumeBPB.BPB_BytePerSec;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ShrinkClusters
+//
+// Description: Reduces the number of clusters used by a file
+// (part of it deleted).
+//
+// Parameters:
+// IN VOLUME_INFO *Vol,
+// IN UINT32 StartCluster,
+// IN UINT32 ClusterCount
+//
+// Return value: EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+// ClusterCount : Total number of Final clusters starting from StartCluster
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+ShrinkClusters (
+ IN VOLUME_INFO *Vol,
+ IN UINT32 StartCluster,
+ IN UINT32 ClusterCount
+)
+{
+ EFI_STATUS Status;
+ UINT32 LastCluster, NextCluster = StartCluster;
+ UINT32 i;
+
+// Get to the particular Cluster#
+ for ( i = 0; i < ClusterCount; i++, StartCluster = NextCluster) {
+ LastCluster = StartCluster;
+ Status = ReadFatClusterNumber (Vol, StartCluster, 0, &NextCluster);
+
+ if (EFI_ERROR(Status)) return Status;
+ }
+
+// Truncate it
+ if (ClusterCount) {
+ for (i = 0; i < Vol->VolumeBPB.BPB_NumFATs; i++) {
+ Status = WriteFatClusterNumber(Vol, LastCluster, i, Vol->EOCMark);
+
+ if (EFI_ERROR(Status)) return Status;
+ }
+ }
+
+// Free Up the remaining
+ Status = UnlinkFat (Vol, NextCluster, &ClusterCount); // Unlink From this Cluster
+ return Status;
+
+}
+
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: GetFreeClusterCount
+//
+// Description: Gets the count of free clusters on a disk.
+//
+// Parameters:
+// IN VOLUME_INFO *Vol, The volume structure
+// OUT UINT32 *FreeClusters Free clusters on volume
+// OUT UINT32 *FreeClusterBlock First cluster in a block of free clusters
+// OUT UINT32 *FreeBlockCount Number of clusters in the free block.
+//
+// Return value:
+// EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+GetFreeClusterCount (
+ IN VOLUME_INFO *Vol,
+ OUT UINT32 *FreeClustersCount,
+ OUT UINT32 *FreeClusterBlock,
+ OUT UINT32 *FreeBlockCount
+)
+{
+ EFI_STATUS Status;
+ UINT32 Count = 0;
+ UINT32 FreeCount = 1;
+ UINT32 LastFree = 2;
+ UINT32 FreeBlock = 0;
+ UINT32 PrevFreeCount = 0, PrevFreeBlock;
+ UINT32 i,j;
+ UINT32 Value;
+ UINT8 *Buffer;
+ UINT32 BufferSize;
+ UINT32 BufferOffset = 0;
+ UINT32 FatSize;
+ UINT32 FatOffset;
+ UINT32 CountSize, CompareSize;
+ UINT32 TotalClusters;
+ UINT32 Sector;
+
+// Read in a maximum of 1 megabyte of the fat at a time for this calcuation
+ FatSize = Vol->FATSz * (UINT32)Vol->VolumeBPB.BPB_BytePerSec;
+
+ if (FatSize > 0xfffff) BufferSize = 0x100000;
+
+ else BufferSize = FatSize;
+
+ Status = fsAllocateMemory (Vol, BufferSize, &Buffer, FALSE);
+
+ if (EFI_ERROR(Status)) return EFI_NOT_FOUND;
+
+ TotalClusters = Vol->CountOfDataClusters;
+ j = i = 2; // For the first round start from Cluster 2
+
+ while (TotalClusters) {
+
+// Sector = Vol->FATSz + Vol->VolumeBPB.BPB_RsvdSecCnt + BufferOffset / (UINT32)Vol->VolumeBPB.BPB_BytePerSec;
+ Sector = Vol->VolumeBPB.BPB_RsvdSecCnt + BufferOffset / (UINT32)Vol->VolumeBPB.BPB_BytePerSec;
+ Status = FsReadMedia (Vol,
+ (UINT8 *)Buffer,
+ (UINT64)Sector,
+ 0,
+ BufferSize,
+ DATA_REGION);
+
+ if ( EFI_ERROR(Status)) goto GetFreeClusterCount_Error;
+
+// FAT12 or FAT16 will never have FAT size larger than 1MB
+// if (Vol->FatType != FAT32) CountSize = BufferSize/2; else CountSize = BufferSize/4;
+ if (BufferSize == FatSize) {
+ CountSize = TotalClusters;
+
+ } else {
+ CountSize = BufferSize / 4; // We could only have CountSize exceeding TotalClusters if FAT32
+ }
+
+// if (CountSize > TotalClusters) CountSize = TotalClusters;
+ if (i == 2) CompareSize = CountSize + 2;
+
+ else CompareSize = CountSize;
+
+ for (; i < CompareSize; i++, j++) {
+// Status = ReadFatClusterNumber(Vol, i, 0, &Value);
+ switch (Vol->FatType) {
+ case FAT12:
+ FatOffset = i + (i / 2);
+ (UINT16)Value = *(UINT16 *)((UINT8 *)Buffer + FatOffset);
+
+ if (i & 0x0001) Value >>= 4;
+
+ else Value &= 0x0fff;
+
+ break;
+ case FAT16:
+ FatOffset = i * 2;
+ (UINT16)Value = *(UINT16 *)((UINT8 *)Buffer + FatOffset);
+ Value &= 0x0ffff;
+ break;
+ case FAT32:
+ FatOffset = i * 4;
+ Value = *(UINT32 *)((UINT8 *)Buffer + FatOffset);
+ Value &= 0x0fffffff; // FAT32 actually uses 28 bits
+ break;
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ if (EFI_ERROR(Status)) goto GetFreeClusterCount_Error;
+
+ if (Value == 0) {
+ Count++;
+
+ if (j != (LastFree + 1)) {
+ if (FreeCount > PrevFreeCount) { // in case the last free block found is not the largest.
+ PrevFreeBlock = FreeBlock;
+ PrevFreeCount = FreeCount;
+ }
+
+ FreeBlock = j; // Reset free block if not contiguous
+ FreeCount = 0; // Restart free count
+ }
+
+ LastFree = j;
+ FreeCount++;
+ }
+ }
+
+ BufferOffset += BufferSize;
+ FatSize -= BufferSize;
+
+ if (FatSize > 0xfffff) BufferSize = 0x100000;
+
+ else BufferSize = FatSize;
+
+// Check for last group of clusters.
+ if (TotalClusters >= CountSize) {
+ TotalClusters -= CountSize;
+
+ } else {
+ CountSize = TotalClusters; // Adjust count size and buffer size if in last cluster group
+ BufferSize = TotalClusters * 4;
+ }
+
+// It's possible that the original Total Cluster count could have been incorrect.
+// Check that here.
+ if (TotalClusters && (BufferSize > FatSize)) {
+ TRACE((TRACE_ALWAYS, "TotalClusters was incorrect -- fixing it.\n"));
+ BufferSize = FatSize;
+ CountSize = TotalClusters = (BufferSize / 4);
+ TRACE((TRACE_ALWAYS, "Buffer adjusted to 0x%X bytes\n", BufferSize));
+ }
+
+ i = 0; // From Second round, start from Cluster 0
+ }
+
+ fsDeAllocateMemory (Vol, Buffer);
+
+ if (Count) {
+ *FreeClustersCount = Count;
+
+ if (FreeCount > PrevFreeCount) { // in case the last free block is not the largest.
+ *FreeClusterBlock = FreeBlock;
+ *FreeBlockCount = FreeCount;
+
+ } else {
+ *FreeClusterBlock = PrevFreeBlock;
+ *FreeBlockCount = PrevFreeCount;
+ }
+
+ return EFI_SUCCESS;
+
+ } else return EFI_NOT_FOUND;
+
+GetFreeClusterCount_Error:
+ fsDeAllocateMemory (Vol, Buffer);
+ return Status;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: ReturnFreeSpace
+//
+// Description: Returns the amount of free space (in clusters) on a volume
+//
+// Parameters:
+// IN VOLUME_INFO *vi - Volume info structure
+//
+// Return value: UINT32 - free space in clusters
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+UINT32
+ReturnFreeSpace (
+ IN VOLUME_INFO *vi
+)
+{
+
+ UINT32 FreeClusterCount, StartFreeClusterBlock, nClusterBlocks;
+
+ if (vi->FreeSpaceinClusters != -1 && vi->LastFreeCluster != -1) return vi->FreeSpaceinClusters;
+
+ GetFreeClusterCount(vi, &FreeClusterCount, &StartFreeClusterBlock, &nClusterBlocks);
+
+ if (FreeClusterCount > vi->CountOfDataClusters) FreeClusterCount = 0;
+
+ vi->FreeSpaceinClusters = FreeClusterCount;
+ vi->LastFreeCluster = StartFreeClusterBlock;
+ vi->FreeClusterBlocks = nClusterBlocks;
+ return vi->FreeSpaceinClusters;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: UpdateFreeSpace
+//
+// Description: Updates the volume info free space in clusters
+//
+// Parameters:
+// IN VOLUME_INFO *vi - Volume info structure
+//
+// Return value: EFI_STATUS
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+UpdateFreeSpace (
+ IN VOLUME_INFO *vi,
+ IN UINT32 Count,
+ IN BOOLEAN Add
+)
+{
+
+ UINT32 FreeClusters = vi->FreeSpaceinClusters;
+
+ if (vi->FreeSpaceinClusters == -1 ) FreeClusters = ReturnFreeSpace (vi);
+
+ if (Add) vi->FreeSpaceinClusters += Count;
+
+ else if (FreeClusters) vi->FreeSpaceinClusters -= Count;
+
+ return EFI_SUCCESS;
+
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------
+//
+// Procedure: MarkVolumeDirty
+//
+// Description: Marks a volume as dirty so that the OS will know to fix it.
+//
+// Parameters:
+// IN VOLUME_INFO *vi - Volume info structure
+//
+// Return value:
+//
+//
+// Modified:
+//
+// Referrals:
+//
+// Notes:
+//
+//----------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+MarkVolumeDirty (
+ IN VOLUME_INFO *vi
+)
+{
+ EFI_STATUS Status;
+ UINT32 Temp;
+
+ Status = ReadFatClusterNumber (vi, 1, 0, &Temp);
+
+ if (EFI_ERROR(Status)) return Status;
+
+ switch (vi->FatType) {
+ case FAT12:
+ return EFI_SUCCESS; // Not supported in FAT21 -- ignore.
+ case FAT16: {
+ Temp &= ~0x8000; // Set dirty bit in FAT header.
+ break;
+ }
+ case FAT32: {
+ Temp &= ~0x08000000;
+ break;
+ }
+ default:
+ return EFI_SUCCESS;
+ }
+
+ Status = WriteFatClusterNumber (vi, 1, 0, Temp);
+
+ if (EFI_ERROR(Status)) return Status;
+
+// We don't have to write the 2nd fat, since the volume is dirty anyway, and
+// Windows or DOS will fix it. This saves a little code.
+// Status = WriteFatClusterNumber (vi, 1, 1, Temp);
+// if (EFI_ERROR(Status)) return Status;
+ return EFI_SUCCESS;
+}
+
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2009, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************