diff options
Diffstat (limited to 'Core/EM/FileSystem')
-rw-r--r-- | Core/EM/FileSystem/DirectoryHandler.c | 454 | ||||
-rw-r--r-- | Core/EM/FileSystem/FileFatHandler.c | 898 | ||||
-rw-r--r-- | Core/EM/FileSystem/FileSYstem.mak | 75 | ||||
-rw-r--r-- | Core/EM/FileSystem/FileSystem.c | 948 | ||||
-rw-r--r-- | Core/EM/FileSystem/FileSystem.chm | bin | 0 -> 118223 bytes | |||
-rw-r--r-- | Core/EM/FileSystem/FileSystem.cif | 19 | ||||
-rw-r--r-- | Core/EM/FileSystem/FileSystem.h | 1480 | ||||
-rw-r--r-- | Core/EM/FileSystem/FileSystem.sdl | 49 | ||||
-rw-r--r-- | Core/EM/FileSystem/FileSystemComponentName.c | 271 | ||||
-rw-r--r-- | Core/EM/FileSystem/Info.c | 1313 | ||||
-rw-r--r-- | Core/EM/FileSystem/MediaAccess.c | 1479 | ||||
-rw-r--r-- | Core/EM/FileSystem/Open.c | 2601 | ||||
-rw-r--r-- | Core/EM/FileSystem/VolFatHandler.c | 1419 |
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 Binary files differnew file mode 100644 index 0000000..d45524f --- /dev/null +++ b/Core/EM/FileSystem/FileSystem.chm 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 ** +//** ** +//********************************************************************** +//********************************************************************** |