From b7c51c9cf4864df6aabb99a1ae843becd577237c Mon Sep 17 00:00:00 2001 From: raywu Date: Fri, 15 Jun 2018 00:00:50 +0800 Subject: init. 1AQQW051 --- Core/EM/FileSystem/Open.c | 2601 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2601 insertions(+) create mode 100644 Core/EM/FileSystem/Open.c (limited to 'Core/EM/FileSystem/Open.c') 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 +// +// +// +//********************************************************************** + +// +//---------------------------------------------------------------------- +// +// Name: Open.c +// +// Description: Handles Opening File Handles. +// +//---------------------------------------------------------------------- +// + +//---------------------------------------------------------------------- + +#include "FileSystem.h" +#define EFI_TPL_CALLBACK TPL_CALLBACK +//---------------------------------------------------------------------- + +extern EFI_GUID gEfiFileSystemVolumeLabelGuid; +extern EFI_GUID gEfiFileInfoGuid; +extern EFI_GUID gEfiFileSystemInfoGuid; + +//---------------------------------------------------------------------- + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + + +// +//---------------------------------------------------------------------- +// +// 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 +// +//---------------------------------------------------------------------- +// + +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; +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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. +// +//---------------------------------------------------------------------- +// + +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= 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; + +} + +// +//---------------------------------------------------------------------- +// +// Procedure: AddToDirList +// +// Description: Adds a directory entry to DirList +// +// Parameters: +// IN FILE_HANDLE *fh - File Handle +// +// Return Value: +// EFI_STATUS +// +// Modified: +// +// Referrals: ReadAllDirectoryEntries +// +// Notes: +// +//---------------------------------------------------------------------- +// + +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; + +} + +// +//---------------------------------------------------------------------- +// +// 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 +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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 +} + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; +} + + +// +//---------------------------------------------------------------------- +// +// Procedure: CloseFileHandle +// +// Description: Closes an open file +// +// Parameters: +// IN EFI_FILE_PROTOCOL *This - File Protocol instance +// +// Return Value: +// EFI_STATUS +// +// Modified: +// +// Referrals: DeleteFileHandle +// +// Notes: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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 +// +//---------------------------------------------------------------------- +// + +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; +} + + +// +//---------------------------------------------------------------------- +// +// 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 +// +//---------------------------------------------------------------------- +// + +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; +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +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; + +} + + +// +//---------------------------------------------------------------------- +// +// 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: +// +//---------------------------------------------------------------------- +// + +VOID +GetTempBuffer ( + VOLUME_INFO *Vi, + VOID **Buffer +) +{ + + *Buffer = (UINT8 *)(Vi->TempBuffer); + Vi->TempBufferInUse = TRUE; + +} + + +// +//---------------------------------------------------------------------- +// +// Procedure: ReleaseTempBuffer +// +// Description: Releases a temporary buffer +// +// Parameters: +// VOLUME_INFO *Vi - Volume Info +// +// Return Value: +// EFI_STATUS +// +// Modified: +// +// Referrals: ProcessOpenFileHandle, ReadAllDirectoryEntries, CloseFileHandle +// +// Notes: +// +//---------------------------------------------------------------------- +// + +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 ** +//** ** +//********************************************************************** +//********************************************************************** -- cgit v1.2.3