public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Ruiyu Ni <ruiyu.ni@intel.com>
To: edk2-devel@lists.01.org
Cc: Hao Wu <hao.a.wu@intel.com>, Andrew Fish <afish@intel.com>
Subject: [PATCH 08/12] EmulatorPkg/Win: Add SimpleFileSystem support
Date: Thu, 23 Aug 2018 17:52:11 +0800	[thread overview]
Message-ID: <20180823095215.274248-9-ruiyu.ni@intel.com> (raw)
In-Reply-To: <20180823095215.274248-1-ruiyu.ni@intel.com>

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@intel.com>
---
 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.<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 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 <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 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



  parent reply	other threads:[~2018-08-23  9:51 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-23  9:52 [PATCH 00/12] Add WinHost support in EmulatorPkg Ruiyu Ni
2018-08-23  9:52 ` [PATCH 01/12] EmulatorPkg/ThunkProtocolList: Fix VS build failure Ruiyu Ni
2018-08-23  9:52 ` [PATCH 02/12] EmulatorPkg/Win: Add Windows host support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 03/12] EmulatorPkg/Win: Enable source level debugging Ruiyu Ni
2018-08-23  9:52 ` [PATCH 04/12] EmulatorPkg/Win: Enable native OS console as firmware console Ruiyu Ni
2018-08-23  9:52 ` [PATCH 05/12] EmulatorPkg/Win: Add input/output support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 06/12] EmulatorPkg/Win: Add timer and interrupt support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 07/12] EmulatorPkg/Win: Add RTC support Ruiyu Ni
2018-08-23  9:52 ` Ruiyu Ni [this message]
2018-08-23  9:52 ` [PATCH 09/12] EmulatorPkg/Win: Add BlockIo support Ruiyu Ni
2018-08-23  9:52 ` [PATCH 10/12] EmulatorPkg/PlatformBds: Signal EndOfDxe in platform BDS Ruiyu Ni
2018-08-23  9:52 ` [PATCH 11/12] EmulatorPkg/EmuFileSystem: Fix a bug that causes Close() assertion Ruiyu Ni
2018-08-23  9:52 ` [PATCH 12/12] EmulatorPkg/DSC: Remove FS mapping to EDK Shell bin directory Ruiyu Ni
2018-08-23  9:56 ` [PATCH 00/12] Add WinHost support in EmulatorPkg Ni, Ruiyu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180823095215.274248-9-ruiyu.ni@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox