diff options
author | Ruiyu Ni <ruiyu.ni@intel.com> | 2018-08-23 13:43:00 +0800 |
---|---|---|
committer | Ruiyu Ni <ruiyu.ni@intel.com> | 2018-08-27 15:20:58 +0800 |
commit | 56502bf1ad5e7d5da4c3e91e8590febdb63ab380 (patch) | |
tree | 8cebf65044e53c6433da2e28ed57d4be29a5485a /EmulatorPkg | |
parent | 07d8559c6bd8a8716e163a930a63f16e742aaa7a (diff) | |
download | edk2-56502bf1ad5e7d5da4c3e91e8590febdb63ab380.zip edk2-56502bf1ad5e7d5da4c3e91e8590febdb63ab380.tar.gz edk2-56502bf1ad5e7d5da4c3e91e8590febdb63ab380.tar.bz2 |
EmulatorPkg/Win: Add SimpleFileSystem support
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@apple.com>
Diffstat (limited to 'EmulatorPkg')
-rw-r--r-- | EmulatorPkg/Win/Host/WinFileSystem.c | 2409 | ||||
-rw-r--r-- | EmulatorPkg/Win/Host/WinHost.c | 1 | ||||
-rw-r--r-- | EmulatorPkg/Win/Host/WinHost.h | 5 | ||||
-rw-r--r-- | EmulatorPkg/Win/Host/WinHost.inf | 9 |
4 files changed, 2424 insertions, 0 deletions
diff --git a/EmulatorPkg/Win/Host/WinFileSystem.c b/EmulatorPkg/Win/Host/WinFileSystem.c new file mode 100644 index 0000000..0d43dda --- /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.<BR>
+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 f8d21d2..266ae59 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 3dc6a7e..3c7529f 100644 --- a/EmulatorPkg/Win/Host/WinHost.h +++ b/EmulatorPkg/Win/Host/WinHost.h @@ -26,8 +26,12 @@ Abstract: #include <PiPei.h>
#include <IndustryStandard/PeImage.h>
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
#include <Ppi/EmuThunk.h>
#include <Protocol/EmuThunk.h>
+#include <Protocol/SimpleFileSystem.h>
#include <Library/BaseLib.h>
@@ -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 b62791b..358d000 100644 --- a/EmulatorPkg/Win/Host/WinHost.inf +++ b/EmulatorPkg/Win/Host/WinHost.inf @@ -33,6 +33,7 @@ WinGopInput.c
WinGopScreen.c
WinGop.h
+ WinFileSystem.c
WinThunk.c
WinHost.h
WinHost.c
@@ -61,6 +62,13 @@ [Protocols]
gEmuIoThunkProtocolGuid
gEmuGraphicsWindowProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+
+[Guids]
+ gEfiFileSystemVolumeLabelInfoIdGuid # SOMETIMES_CONSUMED
+ gEfiFileInfoGuid # SOMETIMES_CONSUMED
+ gEfiFileSystemInfoGuid # SOMETIMES_CONSUMED
+
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdInitValueInTempStack
@@ -69,6 +77,7 @@ gEmulatorPkgTokenSpaceGuid.PcdEmuMemorySize
gEmulatorPkgTokenSpaceGuid.PcdEmuFdBaseAddress
gEmulatorPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"
+ gEmulatorPkgTokenSpaceGuid.PcdEmuFileSystem
gEmulatorPkgTokenSpaceGuid.PcdPeiServicesTablePage
[BuildOptions]
|