From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.120; helo=mga04.intel.com; envelope-from=ruiyu.ni@intel.com; receiver=edk2-devel@lists.01.org Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 7FC3421103997 for ; Thu, 23 Aug 2018 02:55:49 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 23 Aug 2018 02:55:49 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.53,278,1531810800"; d="scan'208";a="85741600" Received: from ray-dev.ccr.corp.intel.com ([10.239.9.8]) by orsmga002.jf.intel.com with ESMTP; 23 Aug 2018 02:55:47 -0700 From: Ruiyu Ni To: edk2-devel@lists.01.org Cc: Hao Wu , Andrew Fish Date: Thu, 23 Aug 2018 17:56:16 +0800 Message-Id: <20180823095620.280996-9-ruiyu.ni@intel.com> X-Mailer: git-send-email 2.16.1.windows.1 In-Reply-To: <20180823095620.280996-1-ruiyu.ni@intel.com> References: <20180823095620.280996-1-ruiyu.ni@intel.com> Subject: [PATCH v2 08/12] EmulatorPkg/Win: Add SimpleFileSystem support X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 23 Aug 2018 09:55:49 -0000 Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ruiyu Ni Cc: Hao Wu Cc: Andrew Fish --- EmulatorPkg/Win/Host/WinFileSystem.c | 2409 ++++++++++++++++++++++++++++++++++ EmulatorPkg/Win/Host/WinHost.c | 1 + EmulatorPkg/Win/Host/WinHost.h | 5 + EmulatorPkg/Win/Host/WinHost.inf | 9 + 4 files changed, 2424 insertions(+) create mode 100644 EmulatorPkg/Win/Host/WinFileSystem.c diff --git a/EmulatorPkg/Win/Host/WinFileSystem.c b/EmulatorPkg/Win/Host/WinFileSystem.c new file mode 100644 index 0000000000..0d43ddaae3 --- /dev/null +++ b/EmulatorPkg/Win/Host/WinFileSystem.c @@ -0,0 +1,2409 @@ +/*++ @file + Support OS native directory access. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +**/ + +#include "WinHost.h" + + +#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('N', 'T', 'f', 's') + +typedef struct { + UINTN Signature; + EMU_IO_THUNK_PROTOCOL *Thunk; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem; + CHAR16 *FilePath; + CHAR16 *VolumeLabel; +} WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE; + +#define WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE, \ + SimpleFileSystem, \ + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \ + ) + + +#define WIN_NT_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('l', 'o', 'f', 's') + +typedef struct { + UINTN Signature; + EMU_IO_THUNK_PROTOCOL *Thunk; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + EFI_FILE_PROTOCOL EfiFile; + HANDLE LHandle; + HANDLE DirHandle; + BOOLEAN IsRootDirectory; + BOOLEAN IsDirectoryPath; + BOOLEAN IsOpenedByRead; + CHAR16 *FilePath; + WCHAR *FileName; + BOOLEAN IsValidFindBuf; + WIN32_FIND_DATA FindBuf; +} WIN_NT_EFI_FILE_PRIVATE; + +#define WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + WIN_NT_EFI_FILE_PRIVATE, \ + EfiFile, \ + WIN_NT_EFI_FILE_PRIVATE_SIGNATURE \ + ) + +extern EFI_FILE_PROTOCOL gWinNtFileProtocol; +extern EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gWinNtFileSystemProtocol; + +EFI_STATUS +WinNtFileGetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +EFI_STATUS +WinNtFileSetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ); + + + +CHAR16 * +EfiStrChr ( + IN CHAR16 *Str, + IN CHAR16 Chr +) +/*++ + +Routine Description: + + Locate the first occurance of a character in a string. + +Arguments: + + Str - Pointer to NULL terminated unicode string. + Chr - Character to locate. + +Returns: + + If Str is NULL, then NULL is returned. + If Chr is not contained in Str, then NULL is returned. + If Chr is contained in Str, then a pointer to the first occurance of Chr in Str is returned. + +--*/ +{ + if (Str == NULL) { + return Str; + } + + while (*Str != '\0' && *Str != Chr) { + ++Str; + } + + return (*Str == Chr) ? Str : NULL; +} + + + +BOOLEAN +IsZero ( + IN VOID *Buffer, + IN UINTN Length + ) +{ + if (Buffer == NULL || Length == 0) { + return FALSE; + } + + if (*(UINT8 *) Buffer != 0) { + return FALSE; + } + + if (Length > 1) { + if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) { + return FALSE; + } + } + + return TRUE; +} + +VOID +CutPrefix ( + IN CHAR16 *Str, + IN UINTN Count + ) +{ + CHAR16 *Pointer; + + if (StrLen (Str) < Count) { + ASSERT (0); + } + + if (Count != 0) { + for (Pointer = Str; *(Pointer + Count); Pointer++) { + *Pointer = *(Pointer + Count); + } + + *Pointer = *(Pointer + Count); + } +} +/** + Open the root directory on a volume. + + @param This Protocol instance pointer. + @param Root Returns an Open file handle for the root directory + + @retval EFI_SUCCESS The device was opened. + @retval EFI_UNSUPPORTED This volume does not support the file system. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. + +**/ +EFI_STATUS +WinNtOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **Root + ) +{ + EFI_STATUS Status; + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + CHAR16 *TempFileName; + UINTN Size; + + if (This == NULL || Root == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This); + + PrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE)); + if (PrivateFile == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + PrivateFile->FileName = AllocatePool (StrSize (Private->FilePath)); + if (PrivateFile->FileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + PrivateFile->FilePath = AllocatePool (StrSize (Private->FilePath)); + if (PrivateFile->FilePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (PrivateFile->FilePath, Private->FilePath); + StrCpy (PrivateFile->FileName, PrivateFile->FilePath); + PrivateFile->Signature = WIN_NT_EFI_FILE_PRIVATE_SIGNATURE; + PrivateFile->Thunk = Private->Thunk; + PrivateFile->SimpleFileSystem = This; + PrivateFile->IsRootDirectory = TRUE; + PrivateFile->IsDirectoryPath = TRUE; + PrivateFile->IsOpenedByRead = TRUE; + CopyMem (&PrivateFile->EfiFile, &gWinNtFileProtocol, sizeof (gWinNtFileProtocol)); + PrivateFile->IsValidFindBuf = FALSE; + + // + // Set DirHandle + // + PrivateFile->DirHandle = CreateFile ( + PrivateFile->FilePath, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + if (PrivateFile->DirHandle == INVALID_HANDLE_VALUE) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Find the first file under it + // + Size = StrSize (PrivateFile->FilePath); + Size += StrSize (L"\\*"); + TempFileName = AllocatePool (Size); + if (TempFileName == NULL) { + goto Done; + } + StrCpy (TempFileName, PrivateFile->FilePath); + StrCat (TempFileName, L"\\*"); + + PrivateFile->LHandle = FindFirstFile (TempFileName, &PrivateFile->FindBuf); + FreePool (TempFileName); + + if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { + PrivateFile->IsValidFindBuf = FALSE; + } else { + PrivateFile->IsValidFindBuf = TRUE; + } + *Root = &PrivateFile->EfiFile; + + Status = EFI_SUCCESS; + +Done: + if (EFI_ERROR (Status)) { + if (PrivateFile) { + if (PrivateFile->FileName) { + FreePool (PrivateFile->FileName); + } + + if (PrivateFile->FilePath) { + FreePool (PrivateFile->FilePath); + } + + FreePool (PrivateFile); + } + } + + return Status; +} + +/** + Count the number of Leading Dot in FileNameToken. + + @param FileNameToken A string representing a token in the path name. + + @return UINTN The number of leading dot in the name. + +**/ +UINTN +CountLeadingDots ( + IN CONST CHAR16 * FileNameToken +) +{ + UINTN Num; + + Num = 0; + while (*FileNameToken == L'.') { + Num++; + FileNameToken++; + } + + return Num; +} + + +BOOLEAN +IsFileNameTokenValid ( + IN CONST CHAR16 * FileNameToken +) +{ + UINTN Num; + if (StrStr (FileNameToken, L"/") != NULL) { + // + // No L'/' in file name. + // + return FALSE; + } else { + // + // If Token has all dot, the number should not exceed 2 + // + Num = CountLeadingDots (FileNameToken); + + if (Num == StrLen (FileNameToken)) { + // + // If the FileNameToken only contains a number of L'.'. + // + if (Num > 2) { + return FALSE; + } + } + } + + return TRUE; +} + + +/** + Return the first string token found in the indirect pointer a String named by FileName. + + On input, FileName is a indirect pointer pointing to a String. + On output, FileName is a updated to point to the next character after the first + found L"\" or NULL if there is no L"\" found. + + @param FileName A indirect pointer pointing to a FileName. + + @return Token The first string token found before a L"\". + +**/ +CHAR16 * +GetNextFileNameToken ( + IN OUT CONST CHAR16 ** FileName +) +{ + CHAR16 *SlashPos; + CHAR16 *Token; + UINTN Offset; + ASSERT (**FileName != L'\\'); + ASSERT (**FileName != L'\0'); + + SlashPos = StrStr (*FileName, L"\\"); + if (SlashPos == NULL) { + Token = AllocateCopyPool (StrSize (*FileName), *FileName); + *FileName = NULL; + } else { + Offset = SlashPos - *FileName; + Token = AllocateZeroPool ((Offset + 1) * sizeof (CHAR16)); + StrnCpy (Token, *FileName, Offset); + // + // Point *FileName to the next character after L'\'. + // + *FileName = *FileName + Offset + 1; + // + // If *FileName is an empty string, then set *FileName to NULL + // + if (**FileName == L'\0') { + *FileName = NULL; + } + } + + return Token; +} + + +/** + Check if a FileName contains only Valid Characters. + + If FileName contains only a single L'\', return TRUE. + If FileName contains two adjacent L'\', return FALSE. + If FileName conatins L'/' , return FALSE. + If FielName contains more than two dots seperated with other FileName characters + by L'\', return FALSE. For example, L'.\...\filename.txt' is invalid path name. But L'..TwoDots\filename.txt' is valid path name. + + @param FileName The File Name String to check. + + @return TRUE FileName only contains valid characters. + @return FALSE FileName contains at least one invalid character. + +**/ + +BOOLEAN +IsFileNameValid ( + IN CONST CHAR16 *FileName + ) +{ + CHAR16 *Token; + BOOLEAN Valid; + + // + // If FileName is just L'\', then it is a valid pathname. + // + if (StrCmp (FileName, L"\\") == 0) { + return TRUE; + } + // + // We don't support two or more adjacent L'\'. + // + if (StrStr (FileName, L"\\\\") != NULL) { + return FALSE; + } + + // + // Is FileName has a leading L"\", skip to next character. + // + if (FileName [0] == L'\\') { + FileName++; + } + + do { + Token = GetNextFileNameToken (&FileName); + Valid = IsFileNameTokenValid (Token); + FreePool (Token); + + if (!Valid) + return FALSE; + } while (FileName != NULL); + + return TRUE; +} + + +/** + Opens a new file relative to the source file's location. + + @param This The protocol instance pointer. + @param NewHandle Returns File Handle for FileName. + @param FileName Null terminated string. "\", ".", and ".." are supported. + @param OpenMode Open mode for file. + @param Attributes Only used for EFI_FILE_MODE_CREATE. + + @retval EFI_SUCCESS The device was opened. + @retval EFI_NOT_FOUND The specified file could not be found on the device. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_MEDIA_CHANGED The media has changed. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +WinNtFileOpen ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + WIN_NT_EFI_FILE_PRIVATE *NewPrivateFile; + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; + EFI_STATUS Status; + CHAR16 *RealFileName; + CHAR16 *TempFileName; + CHAR16 *ParseFileName; + CHAR16 *GuardPointer; + CHAR16 TempChar; + DWORD LastError; + UINTN Count; + BOOLEAN LoopFinish; + UINTN InfoSize; + EFI_FILE_INFO *Info; + UINTN Size; + + + // + // Init local variables + // + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); + NewPrivateFile = NULL; + + // + // Allocate buffer for FileName as the passed in FileName may be read only + // + TempFileName = AllocatePool (StrSize (FileName)); + if (TempFileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + StrCpy (TempFileName, FileName); + FileName = TempFileName; + + if (FileName[StrLen (FileName) - 1] == L'\\') { + FileName[StrLen (FileName) - 1] = 0; + } + + // + // If file name does not equal to "." or ".." and not trailed with "\..", + // then we trim the leading/trailing blanks and trailing dots + // + if (StrCmp (FileName, L".") != 0 && StrCmp (FileName, L"..") != 0 && + ((StrLen (FileName) >= 3) ? (StrCmp (&FileName[StrLen (FileName) - 3], L"\\..") != 0) : TRUE)) { + // + // Trim leading blanks + // + Count = 0; + for (TempFileName = FileName; + *TempFileName != 0 && *TempFileName == L' '; + TempFileName++) { + Count++; + } + CutPrefix (FileName, Count); + // + // Trim trailing blanks + // + for (TempFileName = FileName + StrLen (FileName) - 1; + TempFileName >= FileName && (*TempFileName == L' '); + TempFileName--) { + ; + } + *(TempFileName + 1) = 0; + } + + // + // Attempt to open the file + // + NewPrivateFile = AllocatePool (sizeof (WIN_NT_EFI_FILE_PRIVATE)); + if (NewPrivateFile == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + CopyMem (NewPrivateFile, PrivateFile, sizeof (WIN_NT_EFI_FILE_PRIVATE)); + + NewPrivateFile->FilePath = AllocatePool (StrSize (PrivateFile->FileName)); + if (NewPrivateFile->FilePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + if (PrivateFile->IsDirectoryPath) { + StrCpy (NewPrivateFile->FilePath, PrivateFile->FileName); + } else { + StrCpy (NewPrivateFile->FilePath, PrivateFile->FilePath); + } + + Size = StrSize (NewPrivateFile->FilePath); + Size += StrSize (L"\\"); + Size += StrSize (FileName); + NewPrivateFile->FileName = AllocatePool (Size); + if (NewPrivateFile->FileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + if (*FileName == L'\\') { + StrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath); + StrCat (NewPrivateFile->FileName, L"\\"); + StrCat (NewPrivateFile->FileName, FileName + 1); + } else { + StrCpy (NewPrivateFile->FileName, NewPrivateFile->FilePath); + if (StrCmp (FileName, L"") != 0) { + // + // In case the filename becomes empty, especially after trimming dots and blanks + // + StrCat (NewPrivateFile->FileName, L"\\"); + StrCat (NewPrivateFile->FileName, FileName); + } + } + + if (!IsFileNameValid (NewPrivateFile->FileName)) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Get rid of . and .., except leading . or .. + // + + // + // GuardPointer protect simplefilesystem root path not be destroyed + // + GuardPointer = NewPrivateFile->FileName + StrLen (PrivateRoot->FilePath); + + LoopFinish = FALSE; + + while (!LoopFinish) { + + LoopFinish = TRUE; + + for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) { + if (*ParseFileName == L'.' && + (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == L'\\') && + *(ParseFileName - 1) == L'\\' + ) { + + // + // cut \. + // + CutPrefix (ParseFileName - 1, 2); + LoopFinish = FALSE; + break; + } + + if (*ParseFileName == L'.' && + *(ParseFileName + 1) == L'.' && + (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == L'\\') && + *(ParseFileName - 1) == L'\\' + ) { + + ParseFileName--; + Count = 3; + + while (ParseFileName != GuardPointer) { + ParseFileName--; + Count++; + if (*ParseFileName == L'\\') { + break; + } + } + + // + // cut \.. and its left directory + // + CutPrefix (ParseFileName, Count); + LoopFinish = FALSE; + break; + } + } + } + + RealFileName = NewPrivateFile->FileName; + while (EfiStrChr (RealFileName, L'\\') != NULL) { + RealFileName = EfiStrChr (RealFileName, L'\\') + 1; + } + + TempChar = 0; + if (RealFileName != NewPrivateFile->FileName) { + TempChar = *(RealFileName - 1); + *(RealFileName - 1) = 0; + } + + FreePool (NewPrivateFile->FilePath); + NewPrivateFile->FilePath = NULL; + NewPrivateFile->FilePath = AllocatePool (StrSize (NewPrivateFile->FileName)); + if (NewPrivateFile->FilePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (NewPrivateFile->FilePath, NewPrivateFile->FileName); + if (TempChar != 0) { + *(RealFileName - 1) = TempChar; + } + + NewPrivateFile->IsRootDirectory = FALSE; + + // + // Test whether file or directory + // + if (OpenMode & EFI_FILE_MODE_CREATE) { + if (Attributes & EFI_FILE_DIRECTORY) { + NewPrivateFile->IsDirectoryPath = TRUE; + } else { + NewPrivateFile->IsDirectoryPath = FALSE; + } + } else { + NewPrivateFile->LHandle = CreateFile ( + NewPrivateFile->FileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if (NewPrivateFile->LHandle != INVALID_HANDLE_VALUE) { + NewPrivateFile->IsDirectoryPath = FALSE; + CloseHandle (NewPrivateFile->LHandle); + } else { + NewPrivateFile->IsDirectoryPath = TRUE; + } + + NewPrivateFile->LHandle = INVALID_HANDLE_VALUE; + } + + if (OpenMode & EFI_FILE_MODE_WRITE) { + NewPrivateFile->IsOpenedByRead = FALSE; + } else { + NewPrivateFile->IsOpenedByRead = TRUE; + } + + Status = EFI_SUCCESS; + + // + // deal with directory + // + if (NewPrivateFile->IsDirectoryPath) { + + Size = StrSize (NewPrivateFile->FileName); + Size += StrSize (L"\\*"); + TempFileName = AllocatePool (Size); + if (TempFileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (TempFileName, NewPrivateFile->FileName); + + if ((OpenMode & EFI_FILE_MODE_CREATE)) { + // + // Create a directory + // + if (!CreateDirectory (TempFileName, NULL)) { + + LastError = GetLastError (); + if (LastError != ERROR_ALREADY_EXISTS) { + FreePool (TempFileName); + Status = EFI_ACCESS_DENIED; + goto Done; + } + } + } + + NewPrivateFile->DirHandle = CreateFile ( + TempFileName, + NewPrivateFile->IsOpenedByRead ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE), + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + if (NewPrivateFile->DirHandle == INVALID_HANDLE_VALUE) { + + NewPrivateFile->DirHandle = CreateFile ( + TempFileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + if (NewPrivateFile->DirHandle != INVALID_HANDLE_VALUE) { + CloseHandle (NewPrivateFile->DirHandle); + NewPrivateFile->DirHandle = INVALID_HANDLE_VALUE; + Status = EFI_ACCESS_DENIED; + } else { + Status = EFI_NOT_FOUND; + } + + FreePool (TempFileName); + goto Done; + } + + // + // Find the first file under it + // + StrCat (TempFileName, L"\\*"); + NewPrivateFile->LHandle = FindFirstFile (TempFileName, &NewPrivateFile->FindBuf); + FreePool (TempFileName); + + if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { + NewPrivateFile->IsValidFindBuf = FALSE; + } else { + NewPrivateFile->IsValidFindBuf = TRUE; + } + } else { + // + // deal with file + // + if (!NewPrivateFile->IsOpenedByRead) { + NewPrivateFile->LHandle = CreateFile ( + NewPrivateFile->FileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + (OpenMode & EFI_FILE_MODE_CREATE) ? OPEN_ALWAYS : OPEN_EXISTING, + 0, + NULL + ); + + if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { + NewPrivateFile->LHandle = CreateFile ( + NewPrivateFile->FileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { + Status = EFI_NOT_FOUND; + } else { + Status = EFI_ACCESS_DENIED; + CloseHandle (NewPrivateFile->LHandle); + NewPrivateFile->LHandle = INVALID_HANDLE_VALUE; + } + } + } else { + NewPrivateFile->LHandle = CreateFile ( + NewPrivateFile->FileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + if (NewPrivateFile->LHandle == INVALID_HANDLE_VALUE) { + Status = EFI_NOT_FOUND; + } + } + } + + if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) { + // + // Set the attribute + // + InfoSize = 0; + Info = NULL; + + Status = WinNtFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); + + if (Status != EFI_BUFFER_TOO_SMALL) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + Info = AllocatePool (InfoSize); + if (Info == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = WinNtFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); + + if (EFI_ERROR (Status)) { + FreePool (Info); + goto Done; + } + + Info->Attribute = Attributes; + + WinNtFileSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info); + FreePool (Info); + } + +Done: + FreePool (FileName); + + if (EFI_ERROR (Status)) { + if (NewPrivateFile) { + if (NewPrivateFile->FileName) { + FreePool (NewPrivateFile->FileName); + } + + if (NewPrivateFile->FilePath) { + FreePool (NewPrivateFile->FilePath); + } + + FreePool (NewPrivateFile); + } + } else { + *NewHandle = &NewPrivateFile->EfiFile; + if (StrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) { + NewPrivateFile->IsRootDirectory = TRUE; + } + } + + return Status; +} + + + +/** + Close the file handle + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The device was opened. + +**/ +EFI_STATUS +WinNtFileClose ( + IN EFI_FILE_PROTOCOL *This + ) +{ + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { + if (PrivateFile->IsDirectoryPath) { + FindClose (PrivateFile->LHandle); + } else { + CloseHandle (PrivateFile->LHandle); + } + + PrivateFile->LHandle = INVALID_HANDLE_VALUE; + } + + if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) { + CloseHandle (PrivateFile->DirHandle); + PrivateFile->DirHandle = INVALID_HANDLE_VALUE; + } + + if (PrivateFile->FileName) { + FreePool (PrivateFile->FileName); + } + + if (PrivateFile->FilePath) { + FreePool (PrivateFile->FilePath); + } + + FreePool (PrivateFile); + + return EFI_SUCCESS; + +} + + +/** + Close and delete the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The device was opened. + @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. + +**/ +EFI_STATUS +WinNtFileDelete ( + IN EFI_FILE_PROTOCOL *This + ) +{ + EFI_STATUS Status; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + Status = EFI_WARN_DELETE_FAILURE; + + if (PrivateFile->IsDirectoryPath) { + if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { + FindClose (PrivateFile->LHandle); + } + + if (PrivateFile->DirHandle != INVALID_HANDLE_VALUE) { + CloseHandle (PrivateFile->DirHandle); + PrivateFile->DirHandle = INVALID_HANDLE_VALUE; + } + + if (RemoveDirectory (PrivateFile->FileName)) { + Status = EFI_SUCCESS; + } + } else { + CloseHandle (PrivateFile->LHandle); + PrivateFile->LHandle = INVALID_HANDLE_VALUE; + + if (!PrivateFile->IsOpenedByRead) { + if (DeleteFile (PrivateFile->FileName)) { + Status = EFI_SUCCESS; + } + } + } + + FreePool (PrivateFile->FileName); + FreePool (PrivateFile->FilePath); + FreePool (PrivateFile); + + return Status; +} + +VOID +WinNtSystemTimeToEfiTime ( + IN SYSTEMTIME *SystemTime, + IN TIME_ZONE_INFORMATION *TimeZone, + OUT EFI_TIME *Time +) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + SystemTime - TODO: add argument description + TimeZone - TODO: add argument description + Time - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + Time->Year = (UINT16)SystemTime->wYear; + Time->Month = (UINT8)SystemTime->wMonth; + Time->Day = (UINT8)SystemTime->wDay; + Time->Hour = (UINT8)SystemTime->wHour; + Time->Minute = (UINT8)SystemTime->wMinute; + Time->Second = (UINT8)SystemTime->wSecond; + Time->Nanosecond = (UINT32)SystemTime->wMilliseconds * 1000000; + Time->TimeZone = (INT16)TimeZone->Bias; + + if (TimeZone->StandardDate.wMonth) { + Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT; + } +} + +/** + Convert the FileTime to EfiTime. + + @param PrivateFile Pointer to WIN_NT_EFI_FILE_PRIVATE. + @param TimeZone Pointer to the current time zone. + @param FileTime Pointer to file time. + @param EfiTime Pointer to EFI time. +**/ +VOID +WinNtFileTimeToEfiTime ( + IN CONST WIN_NT_EFI_FILE_PRIVATE *PrivateFile, + IN TIME_ZONE_INFORMATION *TimeZone, + IN CONST FILETIME *FileTime, + OUT EFI_TIME *EfiTime +) +{ + FILETIME TempFileTime; + SYSTEMTIME SystemTime; + + FileTimeToLocalFileTime (FileTime, &TempFileTime); + FileTimeToSystemTime (&TempFileTime, &SystemTime); + WinNtSystemTimeToEfiTime (&SystemTime, TimeZone, EfiTime); +} + + +/** + Read data from the file. + + @param This Protocol instance pointer. + @param BufferSize On input size of buffer, on output amount of data in buffer. + @param Buffer The buffer in which data is read. + + @retval EFI_SUCCESS Data was read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size. + +**/ +EFI_STATUS +WinNtFileRead ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + EFI_STATUS Status; + UINTN Size; + UINTN NameSize; + UINTN ResultSize; + UINTN Index; + EFI_FILE_INFO *Info; + WCHAR *pw; + TIME_ZONE_INFORMATION TimeZone; + EFI_FILE_INFO *FileInfo; + UINT64 Pos; + UINT64 FileSize; + UINTN FileInfoSize; + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (!PrivateFile->IsDirectoryPath) { + + if (This->GetPosition (This, &Pos) != EFI_SUCCESS) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + FileInfoSize = SIZE_OF_EFI_FILE_SYSTEM_INFO; + FileInfo = AllocatePool (FileInfoSize); + + Status = This->GetInfo ( + This, + &gEfiFileInfoGuid, + &FileInfoSize, + FileInfo + ); + + if (Status == EFI_BUFFER_TOO_SMALL) { + FreePool (FileInfo); + FileInfo = AllocatePool (FileInfoSize); + Status = This->GetInfo ( + This, + &gEfiFileInfoGuid, + &FileInfoSize, + FileInfo + ); + } + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + FileSize = FileInfo->FileSize; + + FreePool (FileInfo); + + if (Pos >= FileSize) { + *BufferSize = 0; + if (Pos == FileSize) { + Status = EFI_SUCCESS; + goto Done; + } else { + Status = EFI_DEVICE_ERROR; + goto Done; + } + } + + Status = ReadFile ( + PrivateFile->LHandle, + Buffer, + (DWORD)*BufferSize, + (LPDWORD)BufferSize, + NULL + ) ? EFI_SUCCESS : EFI_DEVICE_ERROR; + goto Done; + } + + // + // Read on a directory. Perform a find next + // + if (!PrivateFile->IsValidFindBuf) { + *BufferSize = 0; + Status = EFI_SUCCESS; + goto Done; + } + + Size = SIZE_OF_EFI_FILE_INFO; + + NameSize = StrSize (PrivateFile->FindBuf.cFileName); + + ResultSize = Size + NameSize; + + Status = EFI_BUFFER_TOO_SMALL; + + if (*BufferSize >= ResultSize) { + Status = EFI_SUCCESS; + + Info = Buffer; + ZeroMem (Info, ResultSize); + + Info->Size = ResultSize; + + GetTimeZoneInformation (&TimeZone); + WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftCreationTime, &Info->CreateTime); + WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftLastAccessTime, &Info->LastAccessTime); + WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &PrivateFile->FindBuf.ftLastWriteTime, &Info->ModificationTime); + + Info->FileSize = PrivateFile->FindBuf.nFileSizeLow; + + Info->PhysicalSize = PrivateFile->FindBuf.nFileSizeLow; + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) { + Info->Attribute |= EFI_FILE_ARCHIVE; + } + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) { + Info->Attribute |= EFI_FILE_HIDDEN; + } + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) { + Info->Attribute |= EFI_FILE_SYSTEM; + } + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + Info->Attribute |= EFI_FILE_READ_ONLY; + } + + if (PrivateFile->FindBuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + Info->Attribute |= EFI_FILE_DIRECTORY; + } + + NameSize = NameSize / sizeof (WCHAR); + + pw = (WCHAR *)(((CHAR8 *)Buffer) + Size); + + for (Index = 0; Index < NameSize; Index++) { + pw[Index] = PrivateFile->FindBuf.cFileName[Index]; + } + + if (FindNextFile (PrivateFile->LHandle, &PrivateFile->FindBuf)) { + PrivateFile->IsValidFindBuf = TRUE; + } else { + PrivateFile->IsValidFindBuf = FALSE; + } + } + + *BufferSize = ResultSize; + +Done: + return Status; +} + + + +/** + Write data to a file. + + @param This Protocol instance pointer. + @param BufferSize On input size of buffer, on output amount of data in buffer. + @param Buffer The buffer in which data to write. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to Open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +WinNtFileWrite ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + EFI_STATUS Status; + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (PrivateFile->IsDirectoryPath) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + if (PrivateFile->IsOpenedByRead) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + Status = WriteFile ( + PrivateFile->LHandle, + Buffer, + (DWORD)*BufferSize, + (LPDWORD)BufferSize, + NULL + ) ? EFI_SUCCESS : EFI_DEVICE_ERROR; + +Done: + return Status; + + // + // bugbug: need to access windows error reporting + // +} + + + +/** + Set a files current position + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. + +**/ +EFI_STATUS +WinNtFileSetPossition ( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ) +{ + EFI_STATUS Status; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + UINT32 PosLow; + UINT32 PosHigh; + CHAR16 *FileName; + UINTN Size; + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->IsDirectoryPath) { + if (Position != 0) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + Size = StrSize (PrivateFile->FileName); + Size += StrSize (L"\\*"); + FileName = AllocatePool (Size); + if (FileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (FileName, PrivateFile->FileName); + StrCat (FileName, L"\\*"); + + if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { + FindClose (PrivateFile->LHandle); + } + + PrivateFile->LHandle = FindFirstFile (FileName, &PrivateFile->FindBuf); + + if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { + PrivateFile->IsValidFindBuf = FALSE; + } else { + PrivateFile->IsValidFindBuf = TRUE; + } + + FreePool (FileName); + + Status = (PrivateFile->LHandle == INVALID_HANDLE_VALUE) ? EFI_DEVICE_ERROR : EFI_SUCCESS; + } else { + if (Position == (UINT64)-1) { + PosLow = SetFilePointer (PrivateFile->LHandle, (ULONG)0, NULL, FILE_END); + } else { + PosHigh = (UINT32)RShiftU64 (Position, 32); + + PosLow = SetFilePointer (PrivateFile->LHandle, (ULONG)Position, (PLONG)&PosHigh, FILE_BEGIN); + } + + Status = (PosLow == 0xFFFFFFFF) ? EFI_DEVICE_ERROR : EFI_SUCCESS; + } + +Done: + return Status; +} + + + +/** + Get a file's current position + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.. + +**/ +EFI_STATUS +WinNtFileGetPossition ( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +{ + EFI_STATUS Status; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + INT32 PositionHigh; + UINT64 PosHigh64; + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + PositionHigh = 0; + PosHigh64 = 0; + + if (PrivateFile->IsDirectoryPath) { + + Status = EFI_UNSUPPORTED; + goto Done; + + } else { + + PositionHigh = 0; + *Position = SetFilePointer ( + PrivateFile->LHandle, + 0, + (PLONG)&PositionHigh, + FILE_CURRENT + ); + + Status = *Position == 0xffffffff ? EFI_DEVICE_ERROR : EFI_SUCCESS; + if (EFI_ERROR (Status)) { + goto Done; + } + + PosHigh64 = PositionHigh; + *Position += LShiftU64 (PosHigh64, 32); + } + +Done: + return Status; +} + + +EFI_STATUS +WinNtSimpleFileSystemFileInfo ( + IN WIN_NT_EFI_FILE_PRIVATE *PrivateFile, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer +) +/*++ + +Routine Description: + + TODO: Add function description + +Arguments: + + PrivateFile - TODO: add argument description + BufferSize - TODO: add argument description + Buffer - TODO: add argument description + +Returns: + + TODO: add return values + +--*/ +{ + EFI_STATUS Status; + UINTN Size; + UINTN NameSize; + UINTN ResultSize; + EFI_FILE_INFO *Info; + BY_HANDLE_FILE_INFORMATION FileInfo; + CHAR16 *RealFileName; + CHAR16 *TempPointer; + TIME_ZONE_INFORMATION TimeZone; + + Size = SIZE_OF_EFI_FILE_INFO; + + RealFileName = PrivateFile->FileName; + TempPointer = RealFileName; + while (*TempPointer) { + if (*TempPointer == '\\') { + RealFileName = TempPointer + 1; + } + + TempPointer++; + } + NameSize = StrSize (RealFileName); + + ResultSize = Size + NameSize; + + Status = EFI_BUFFER_TOO_SMALL; + if (*BufferSize >= ResultSize) { + Status = EFI_SUCCESS; + + Info = Buffer; + ZeroMem (Info, ResultSize); + + Info->Size = ResultSize; + GetFileInformationByHandle ( + PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle, + &FileInfo + ); + Info->FileSize = FileInfo.nFileSizeLow; + Info->PhysicalSize = Info->FileSize; + + GetTimeZoneInformation (&TimeZone); + WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftCreationTime, &Info->CreateTime); + WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftLastAccessTime, &Info->LastAccessTime); + WinNtFileTimeToEfiTime (PrivateFile, &TimeZone, &FileInfo.ftLastWriteTime, &Info->ModificationTime); + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) { + Info->Attribute |= EFI_FILE_ARCHIVE; + } + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) { + Info->Attribute |= EFI_FILE_HIDDEN; + } + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + Info->Attribute |= EFI_FILE_READ_ONLY; + } + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) { + Info->Attribute |= EFI_FILE_SYSTEM; + } + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + Info->Attribute |= EFI_FILE_DIRECTORY; + } + + if (PrivateFile->IsDirectoryPath) { + Info->Attribute |= EFI_FILE_DIRECTORY; + } + + if (PrivateFile->IsRootDirectory) { + *((CHAR8 *)Buffer + Size) = 0; + } else { + CopyMem ((CHAR8 *)Buffer + Size, RealFileName, NameSize); + } + } + + *BufferSize = ResultSize; + return Status; +} + +/** + Get information about a file. + + @param This Protocol instance pointer. + @param InformationType Type of information to return in Buffer. + @param BufferSize On input size of buffer, on output amount of data in buffer. + @param Buffer The buffer to return data. + + @retval EFI_SUCCESS Data was returned. + @retval EFI_UNSUPPORTED InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. + +**/ +EFI_STATUS +WinNtFileGetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer; + UINT32 SectorsPerCluster; + UINT32 BytesPerSector; + UINT32 FreeClusters; + UINT32 TotalClusters; + UINT32 BytesPerCluster; + CHAR16 *DriveName; + BOOLEAN DriveNameFound; + BOOL NtStatus; + UINTN Index; + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; + + if (This == NULL || InformationType == NULL || BufferSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); + + Status = EFI_UNSUPPORTED; + + if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { + Status = WinNtSimpleFileSystemFileInfo (PrivateFile, BufferSize, Buffer); + } + + if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { + if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) { + *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *)Buffer; + FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); + FileSystemInfoBuffer->ReadOnly = FALSE; + + // + // Try to get the drive name + // + DriveNameFound = FALSE; + DriveName = AllocatePool (StrSize (PrivateFile->FilePath) + 1); + if (DriveName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (DriveName, PrivateFile->FilePath); + for (Index = 0; DriveName[Index] != 0 && DriveName[Index] != ':'; Index++) { + ; + } + + if (DriveName[Index] == ':') { + DriveName[Index + 1] = '\\'; + DriveName[Index + 2] = 0; + DriveNameFound = TRUE; + } else if (DriveName[0] == '\\' && DriveName[1] == '\\') { + for (Index = 2; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) { + ; + } + + if (DriveName[Index] == '\\') { + DriveNameFound = TRUE; + for (Index++; DriveName[Index] != 0 && DriveName[Index] != '\\'; Index++) { + ; + } + + DriveName[Index] = '\\'; + DriveName[Index + 1] = 0; + } + } + + // + // Try GetDiskFreeSpace first + // + NtStatus = GetDiskFreeSpace ( + DriveNameFound ? DriveName : NULL, + (LPDWORD)&SectorsPerCluster, + (LPDWORD)&BytesPerSector, + (LPDWORD)&FreeClusters, + (LPDWORD)&TotalClusters + ); + if (DriveName) { + FreePool (DriveName); + } + + if (NtStatus) { + // + // Succeeded + // + BytesPerCluster = BytesPerSector * SectorsPerCluster; + FileSystemInfoBuffer->VolumeSize = MultU64x32 (TotalClusters, BytesPerCluster); + FileSystemInfoBuffer->FreeSpace = MultU64x32 (FreeClusters, BytesPerCluster); + FileSystemInfoBuffer->BlockSize = BytesPerCluster; + + } else { + // + // try GetDiskFreeSpaceEx then + // + FileSystemInfoBuffer->BlockSize = 0; + NtStatus = GetDiskFreeSpaceEx ( + PrivateFile->FilePath, + (PULARGE_INTEGER)(&FileSystemInfoBuffer->FreeSpace), + (PULARGE_INTEGER)(&FileSystemInfoBuffer->VolumeSize), + NULL + ); + if (!NtStatus) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + } + + StrCpy ((CHAR16 *)FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel); + *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); + Status = EFI_SUCCESS; + } + + if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { + if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) { + *BufferSize = StrSize (PrivateRoot->VolumeLabel); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + StrCpy ((CHAR16 *)Buffer, PrivateRoot->VolumeLabel); + *BufferSize = StrSize (PrivateRoot->VolumeLabel); + Status = EFI_SUCCESS; + } + +Done: + return Status; +} + + +/** + Set information about a file + + @param File Protocol instance pointer. + @param InformationType Type of information in Buffer. + @param BufferSize Size of buffer. + @param Buffer The data to write. + + @retval EFI_SUCCESS Data was returned. + @retval EFI_UNSUPPORTED InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + +**/ +EFI_STATUS +WinNtFileSetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + EFI_FILE_INFO *OldFileInfo; + EFI_FILE_INFO *NewFileInfo; + EFI_STATUS Status; + UINTN OldInfoSize; + INTN NtStatus; + UINT32 NewAttr; + UINT32 OldAttr; + CHAR16 *OldFileName; + CHAR16 *NewFileName; + CHAR16 *TempFileName; + CHAR16 *CharPointer; + BOOLEAN AttrChangeFlag; + BOOLEAN NameChangeFlag; + BOOLEAN SizeChangeFlag; + BOOLEAN TimeChangeFlag; + UINT64 CurPos; + SYSTEMTIME NewCreationSystemTime; + SYSTEMTIME NewLastAccessSystemTime; + SYSTEMTIME NewLastWriteSystemTime; + FILETIME NewCreationFileTime; + FILETIME NewLastAccessFileTime; + FILETIME NewLastWriteFileTime; + WIN32_FIND_DATA FindBuf; + EFI_FILE_SYSTEM_INFO *NewFileSystemInfo; + UINTN Size; + + // + // Initialise locals. + // + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + PrivateRoot = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); + + Status = EFI_UNSUPPORTED; + OldFileInfo = NewFileInfo = NULL; + OldFileName = NewFileName = NULL; + AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE; + + // + // Set file system information. + // + if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { + NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer; + if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (NewFileSystemInfo->VolumeLabel)) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + + FreePool (PrivateRoot->VolumeLabel); + PrivateRoot->VolumeLabel = AllocatePool (StrSize (NewFileSystemInfo->VolumeLabel)); + if (PrivateRoot->VolumeLabel == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel); + + Status = EFI_SUCCESS; + goto Done; + } + + // + // Set volume label information. + // + if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { + if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *)Buffer); + + Status = EFI_SUCCESS; + goto Done; + } + + if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + if (BufferSize < SIZE_OF_EFI_FILE_INFO) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + // + // Set file/directory information. + // + + // + // Check for invalid set file information parameters. + // + NewFileInfo = (EFI_FILE_INFO *)Buffer; + + if ((NewFileInfo->Size <= SIZE_OF_EFI_FILE_INFO) || + (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) || + (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF) + ) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // bugbug: - This is not safe. We need something like EfiStrMaxSize() + // that would have an additional parameter that would be the size + // of the string array just in case there are no NULL characters in + // the string array. + // + // + // Get current file information so we can determine what kind + // of change request this is. + // + OldInfoSize = 0; + Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, NULL); + + if (Status != EFI_BUFFER_TOO_SMALL) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + OldFileInfo = AllocatePool (OldInfoSize); + if (OldFileInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = WinNtSimpleFileSystemFileInfo (PrivateFile, &OldInfoSize, OldFileInfo); + + if (EFI_ERROR (Status)) { + goto Done; + } + + OldFileName = AllocatePool (StrSize (PrivateFile->FileName)); + if (OldFileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (OldFileName, PrivateFile->FileName); + + // + // Make full pathname from new filename and rootpath. + // + if (NewFileInfo->FileName[0] == '\\') { + Size = StrSize (PrivateRoot->FilePath); + Size += StrSize (L"\\"); + Size += StrSize (NewFileInfo->FileName); + NewFileName = AllocatePool (Size); + if (NewFileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (NewFileName, PrivateRoot->FilePath); + StrCat (NewFileName, L"\\"); + StrCat (NewFileName, NewFileInfo->FileName + 1); + } else { + Size = StrSize (PrivateFile->FilePath); + Size += StrSize (L"\\"); + Size += StrSize (NewFileInfo->FileName); + NewFileName = AllocatePool (Size); + if (NewFileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (NewFileName, PrivateFile->FilePath); + StrCat (NewFileName, L"\\"); + StrCat (NewFileName, NewFileInfo->FileName); + } + + // + // Is there an attribute change request? + // + if (NewFileInfo->Attribute != OldFileInfo->Attribute) { + if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + AttrChangeFlag = TRUE; + } + + // + // Is there a name change request? + // bugbug: - Need EfiStrCaseCmp() + // + if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) { + NameChangeFlag = TRUE; + } + + // + // Is there a size change request? + // + if (NewFileInfo->FileSize != OldFileInfo->FileSize) { + SizeChangeFlag = TRUE; + } + + // + // Is there a time stamp change request? + // + if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) && + CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME)) + ) { + TimeChangeFlag = TRUE; + } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) && + CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME)) + ) { + TimeChangeFlag = TRUE; + } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) && + CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME)) + ) { + TimeChangeFlag = TRUE; + } + + // + // All done if there are no change requests being made. + // + if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) { + Status = EFI_SUCCESS; + goto Done; + } + + // + // Set file or directory information. + // + OldAttr = GetFileAttributes (OldFileName); + + // + // Name change. + // + if (NameChangeFlag) { + // + // Close the handles first + // + if (PrivateFile->IsOpenedByRead) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) { + } + + if (*CharPointer != 0) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + if (PrivateFile->LHandle != INVALID_HANDLE_VALUE) { + if (PrivateFile->IsDirectoryPath) { + FindClose (PrivateFile->LHandle); + } else { + CloseHandle (PrivateFile->LHandle); + PrivateFile->LHandle = INVALID_HANDLE_VALUE; + } + } + + if (PrivateFile->IsDirectoryPath && PrivateFile->DirHandle != INVALID_HANDLE_VALUE) { + CloseHandle (PrivateFile->DirHandle); + PrivateFile->DirHandle = INVALID_HANDLE_VALUE; + } + + NtStatus = MoveFile (OldFileName, NewFileName); + + if (NtStatus) { + // + // modify file name + // + FreePool (PrivateFile->FileName); + + PrivateFile->FileName = AllocatePool (StrSize (NewFileName)); + if (PrivateFile->FileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + StrCpy (PrivateFile->FileName, NewFileName); + + Size = StrSize (NewFileName); + Size += StrSize (L"\\*"); + TempFileName = AllocatePool (Size); + + StrCpy (TempFileName, NewFileName); + + if (!PrivateFile->IsDirectoryPath) { + PrivateFile->LHandle = CreateFile ( + TempFileName, + PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + + FreePool (TempFileName); + + // + // Flush buffers just in case + // + if (FlushFileBuffers (PrivateFile->LHandle) == 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + } else { + PrivateFile->DirHandle = CreateFile ( + TempFileName, + PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + StrCat (TempFileName, L"\\*"); + PrivateFile->LHandle = FindFirstFile (TempFileName, &FindBuf); + + FreePool (TempFileName); + } + } else { + Status = EFI_ACCESS_DENIED; + Reopen:; + + NtStatus = SetFileAttributes (OldFileName, OldAttr); + + if (!NtStatus) { + goto Done; + } + + Size = StrSize (OldFileName); + Size += StrSize (L"\\*"); + TempFileName = AllocatePool (Size); + + StrCpy (TempFileName, OldFileName); + + if (!PrivateFile->IsDirectoryPath) { + PrivateFile->LHandle = CreateFile ( + TempFileName, + PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + } else { + PrivateFile->DirHandle = CreateFile ( + TempFileName, + PrivateFile->IsOpenedByRead ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL + ); + + StrCat (TempFileName, L"\\*"); + PrivateFile->LHandle = FindFirstFile (TempFileName, &FindBuf); + } + + FreePool (TempFileName); + + goto Done; + + } + } + + // + // Size change + // + if (SizeChangeFlag) { + if (PrivateFile->IsDirectoryPath) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + Status = This->GetPosition (This, &CurPos); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = This->SetPosition (This, NewFileInfo->FileSize); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (SetEndOfFile (PrivateFile->LHandle) == 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + Status = This->SetPosition (This, CurPos); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // Time change + // + if (TimeChangeFlag) { + + NewCreationSystemTime.wYear = NewFileInfo->CreateTime.Year; + NewCreationSystemTime.wMonth = NewFileInfo->CreateTime.Month; + NewCreationSystemTime.wDay = NewFileInfo->CreateTime.Day; + NewCreationSystemTime.wHour = NewFileInfo->CreateTime.Hour; + NewCreationSystemTime.wMinute = NewFileInfo->CreateTime.Minute; + NewCreationSystemTime.wSecond = NewFileInfo->CreateTime.Second; + NewCreationSystemTime.wMilliseconds = 0; + + if (!SystemTimeToFileTime ( + &NewCreationSystemTime, + &NewCreationFileTime + )) { + goto Done; + } + + if (!LocalFileTimeToFileTime ( + &NewCreationFileTime, + &NewCreationFileTime + )) { + goto Done; + } + + NewLastAccessSystemTime.wYear = NewFileInfo->LastAccessTime.Year; + NewLastAccessSystemTime.wMonth = NewFileInfo->LastAccessTime.Month; + NewLastAccessSystemTime.wDay = NewFileInfo->LastAccessTime.Day; + NewLastAccessSystemTime.wHour = NewFileInfo->LastAccessTime.Hour; + NewLastAccessSystemTime.wMinute = NewFileInfo->LastAccessTime.Minute; + NewLastAccessSystemTime.wSecond = NewFileInfo->LastAccessTime.Second; + NewLastAccessSystemTime.wMilliseconds = 0; + + if (!SystemTimeToFileTime ( + &NewLastAccessSystemTime, + &NewLastAccessFileTime + )) { + goto Done; + } + + if (!LocalFileTimeToFileTime ( + &NewLastAccessFileTime, + &NewLastAccessFileTime + )) { + goto Done; + } + + NewLastWriteSystemTime.wYear = NewFileInfo->ModificationTime.Year; + NewLastWriteSystemTime.wMonth = NewFileInfo->ModificationTime.Month; + NewLastWriteSystemTime.wDay = NewFileInfo->ModificationTime.Day; + NewLastWriteSystemTime.wHour = NewFileInfo->ModificationTime.Hour; + NewLastWriteSystemTime.wMinute = NewFileInfo->ModificationTime.Minute; + NewLastWriteSystemTime.wSecond = NewFileInfo->ModificationTime.Second; + NewLastWriteSystemTime.wMilliseconds = 0; + + if (!SystemTimeToFileTime ( + &NewLastWriteSystemTime, + &NewLastWriteFileTime + )) { + goto Done; + } + + if (!LocalFileTimeToFileTime ( + &NewLastWriteFileTime, + &NewLastWriteFileTime + )) { + goto Done; + } + + if (!SetFileTime ( + PrivateFile->IsDirectoryPath ? PrivateFile->DirHandle : PrivateFile->LHandle, + &NewCreationFileTime, + &NewLastAccessFileTime, + &NewLastWriteFileTime + )) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + } + + // + // No matter about AttrChangeFlag, Attribute must be set. + // Because operation before may cause attribute change. + // + NewAttr = OldAttr; + + if (NewFileInfo->Attribute & EFI_FILE_ARCHIVE) { + NewAttr |= FILE_ATTRIBUTE_ARCHIVE; + } else { + NewAttr &= ~FILE_ATTRIBUTE_ARCHIVE; + } + + if (NewFileInfo->Attribute & EFI_FILE_HIDDEN) { + NewAttr |= FILE_ATTRIBUTE_HIDDEN; + } else { + NewAttr &= ~FILE_ATTRIBUTE_HIDDEN; + } + + if (NewFileInfo->Attribute & EFI_FILE_SYSTEM) { + NewAttr |= FILE_ATTRIBUTE_SYSTEM; + } else { + NewAttr &= ~FILE_ATTRIBUTE_SYSTEM; + } + + if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) { + NewAttr |= FILE_ATTRIBUTE_READONLY; + } else { + NewAttr &= ~FILE_ATTRIBUTE_READONLY; + } + + NtStatus = SetFileAttributes (NewFileName, NewAttr); + + if (!NtStatus) { + Status = EFI_DEVICE_ERROR; + goto Reopen; + } + +Done: + if (OldFileInfo != NULL) { + FreePool (OldFileInfo); + } + + if (OldFileName != NULL) { + FreePool (OldFileName); + } + + if (NewFileName != NULL) { + FreePool (NewFileName); + } + + return Status; +} + + +/** + Flush data back for the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to Open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +WinNtFileFlush ( + IN EFI_FILE_PROTOCOL *This + ) +{ + BY_HANDLE_FILE_INFORMATION FileInfo; + WIN_NT_EFI_FILE_PRIVATE *PrivateFile; + EFI_STATUS Status; + + PrivateFile = WIN_NT_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->LHandle == INVALID_HANDLE_VALUE) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (PrivateFile->IsDirectoryPath) { + Status = EFI_SUCCESS; + goto Done; + } + + if (PrivateFile->IsOpenedByRead) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + GetFileInformationByHandle (PrivateFile->LHandle, &FileInfo); + + if (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + Status = FlushFileBuffers (PrivateFile->LHandle) ? EFI_SUCCESS : EFI_DEVICE_ERROR; + +Done: + return Status; + // + // bugbug: - Use Windows error reporting. + // + +} + + + +EFI_STATUS +WinNtFileSystmeThunkOpen ( + IN EMU_IO_THUNK_PROTOCOL *This + ) +{ + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + + Private = AllocateZeroPool (sizeof (*Private)); + if (Private == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->FilePath = AllocateCopyPool (StrSize (This->ConfigString), This->ConfigString); + if (Private->FilePath == NULL) { + FreePool (Private); + return EFI_OUT_OF_RESOURCES; + } + + Private->VolumeLabel = AllocateCopyPool (StrSize (L"EFI_EMULATED"), L"EFI_EMULATED"); + if (Private->VolumeLabel == NULL) { + FreePool (Private->FilePath); + FreePool (Private); + return EFI_OUT_OF_RESOURCES; + } + + Private->Signature = WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE; + Private->Thunk = This; + CopyMem (&Private->SimpleFileSystem, &gWinNtFileSystemProtocol, sizeof (Private->SimpleFileSystem)); + + This->Interface = &Private->SimpleFileSystem; + This->Private = Private; + return EFI_SUCCESS; +} + + +EFI_STATUS +WinNtFileSystmeThunkClose ( + IN EMU_IO_THUNK_PROTOCOL *This + ) +{ + WIN_NT_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + + Private = This->Private; + ASSERT (Private != NULL); + + if (Private->VolumeLabel != NULL) { + FreePool (Private->VolumeLabel); + } + if (Private->FilePath != NULL) { + FreePool (Private->FilePath); + } + FreePool (Private); + return EFI_SUCCESS; +} + + +EFI_FILE_PROTOCOL gWinNtFileProtocol = { + EFI_FILE_REVISION, + WinNtFileOpen, + WinNtFileClose, + WinNtFileDelete, + WinNtFileRead, + WinNtFileWrite, + WinNtFileGetPossition, + WinNtFileSetPossition, + WinNtFileGetInfo, + WinNtFileSetInfo, + WinNtFileFlush +}; + +EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gWinNtFileSystemProtocol = { + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION, + WinNtOpenVolume +}; + + +EMU_IO_THUNK_PROTOCOL mWinNtFileSystemThunkIo = { + &gEfiSimpleFileSystemProtocolGuid, + NULL, + NULL, + 0, + WinNtFileSystmeThunkOpen, + WinNtFileSystmeThunkClose, + NULL +}; + + diff --git a/EmulatorPkg/Win/Host/WinHost.c b/EmulatorPkg/Win/Host/WinHost.c index f8d21d26d9..266ae59382 100644 --- a/EmulatorPkg/Win/Host/WinHost.c +++ b/EmulatorPkg/Win/Host/WinHost.c @@ -428,6 +428,7 @@ Returns: // Emulator Bus Driver Thunks // AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE); + AddThunkProtocol (&mWinNtFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE); // // Allocate space for gSystemMemory Array diff --git a/EmulatorPkg/Win/Host/WinHost.h b/EmulatorPkg/Win/Host/WinHost.h index 3dc6a7e641..3c7529fa91 100644 --- a/EmulatorPkg/Win/Host/WinHost.h +++ b/EmulatorPkg/Win/Host/WinHost.h @@ -26,8 +26,12 @@ Abstract: #include #include +#include +#include +#include #include #include +#include #include @@ -198,4 +202,5 @@ SecInitializeThunk ( ); extern EMU_THUNK_PROTOCOL gEmuThunkProtocol; extern EMU_IO_THUNK_PROTOCOL mWinNtWndThunkIo; +extern EMU_IO_THUNK_PROTOCOL mWinNtFileSystemThunkIo; #endif \ No newline at end of file diff --git a/EmulatorPkg/Win/Host/WinHost.inf b/EmulatorPkg/Win/Host/WinHost.inf index b62791bcfa..358d000857 100644 --- a/EmulatorPkg/Win/Host/WinHost.inf +++ b/EmulatorPkg/Win/Host/WinHost.inf @@ -33,6 +33,7 @@ [Sources] WinGopInput.c WinGopScreen.c WinGop.h + WinFileSystem.c WinThunk.c WinHost.h WinHost.c @@ -61,6 +62,13 @@ [Ppis] [Protocols] gEmuIoThunkProtocolGuid gEmuGraphicsWindowProtocolGuid + gEfiSimpleFileSystemProtocolGuid + +[Guids] + gEfiFileSystemVolumeLabelInfoIdGuid # SOMETIMES_CONSUMED + gEfiFileInfoGuid # SOMETIMES_CONSUMED + gEfiFileSystemInfoGuid # SOMETIMES_CONSUMED + [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack @@ -69,6 +77,7 @@ [Pcd] gEmulatorPkgTokenSpaceGuid.PcdEmuMemorySize gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window" + gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage [BuildOptions] -- 2.16.1.windows.1