]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/FileHandleWrappers.c
ShellPkg: Clean up source files
[mirror_edk2.git] / ShellPkg / Application / Shell / FileHandleWrappers.c
index c67ddfc2698f72e11df9e6f10bfa677ed60c6258..8c62eb58628c26489478d4f4f72224ecf5bf85ea 100644 (file)
@@ -2,8 +2,9 @@
   EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables,\r
   StdIn, StdOut, StdErr, etc...).\r
 \r
-  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
-  Copyright (c) 2013, Hewlett-Packard Development Company, L.P.\r
+  Copyright 2016 Dell Inc.\r
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
 #include "Shell.h"\r
 #include "FileHandleInternal.h"\r
 \r
+#define MEM_WRITE_REALLOC_OVERHEAD 1024\r
+\r
 /**\r
-  File style interface for console (Open).  \r
-  \r
+  File style interface for console (Open).\r
+\r
   @param[in] This       Ignored.\r
   @param[out] NewHandle Ignored.\r
   @param[in] FileName   Ignored.\r
   @param[in] OpenMode   Ignored.\r
   @param[in] Attributes Ignored.\r
-  \r
+\r
   @retval EFI_NOT_FOUND\r
 **/\r
 EFI_STATUS\r
@@ -43,9 +46,9 @@ FileInterfaceOpenNotFound(
 \r
 /**\r
   File style interface for console (Close, Delete, & Flush)\r
-  \r
+\r
   @param[in] This       Ignored.\r
-  \r
+\r
   @retval EFI_SUCCESS\r
 **/\r
 EFI_STATUS\r
@@ -62,7 +65,7 @@ FileInterfaceNopGeneric(
 \r
   @param[in] This       Ignored.\r
   @param[out] Position  Ignored.\r
-  \r
+\r
   @retval EFI_UNSUPPORTED\r
 **/\r
 EFI_STATUS\r
@@ -77,10 +80,10 @@ FileInterfaceNopGetPosition(
 \r
 /**\r
   File style interface for console (SetPosition).\r
-  \r
+\r
   @param[in] This       Ignored.\r
   @param[in] Position   Ignored.\r
-  \r
+\r
   @retval EFI_UNSUPPORTED\r
 **/\r
 EFI_STATUS\r
@@ -95,12 +98,12 @@ FileInterfaceNopSetPosition(
 \r
 /**\r
   File style interface for console (GetInfo).\r
-  \r
+\r
   @param[in] This              Ignored.\r
   @param[in] InformationType   Ignored.\r
   @param[in, out] BufferSize   Ignored.\r
   @param[out] Buffer           Ignored.\r
-  \r
+\r
   @retval EFI_UNSUPPORTED\r
 **/\r
 EFI_STATUS\r
@@ -117,12 +120,12 @@ FileInterfaceNopGetInfo(
 \r
 /**\r
   File style interface for console (SetInfo).\r
-  \r
+\r
   @param[in] This       Ignored.\r
   @param[in] InformationType   Ignored.\r
   @param[in] BufferSize Ignored.\r
   @param[in] Buffer     Ignored.\r
-  \r
+\r
   @retval EFI_UNSUPPORTED\r
 **/\r
 EFI_STATUS\r
@@ -141,11 +144,11 @@ FileInterfaceNopSetInfo(
   File style interface for StdOut (Write).\r
 \r
   Writes data to the screen.\r
-  \r
+\r
   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[in, out] BufferSize   Size in bytes of Buffer.\r
   @param[in] Buffer            The pointer to the buffer to write.\r
-  \r
+\r
   @retval EFI_UNSUPPORTED No output console is supported.\r
   @return A return value from gST->ConOut->OutputString.\r
 **/\r
@@ -159,18 +162,20 @@ FileInterfaceStdOutWrite(
 {\r
   if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {\r
     return (EFI_UNSUPPORTED);\r
-  } else {\r
-    return (gST->ConOut->OutputString(gST->ConOut, Buffer));\r
   }\r
+  if (*((CHAR16 *)Buffer) == gUnicodeFileTag) {\r
+    return (gST->ConOut->OutputString(gST->ConOut, (CHAR16 *)Buffer + 1));\r
+  }\r
+  return (gST->ConOut->OutputString(gST->ConOut, Buffer));\r
 }\r
 \r
 /**\r
   File style interface for StdIn (Write).\r
-  \r
+\r
   @param[in] This            Ignored.\r
   @param[in, out] BufferSize Ignored.\r
   @param[in] Buffer          Ignored.\r
-  \r
+\r
   @retval EFI_UNSUPPORTED\r
 **/\r
 EFI_STATUS\r
@@ -188,11 +193,11 @@ FileInterfaceStdInWrite(
   File style interface for console StdErr (Write).\r
 \r
   Writes error to the error output.\r
-  \r
+\r
   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[in, out] BufferSize   Size in bytes of Buffer.\r
   @param[in] Buffer            The pointer to the buffer to write.\r
-  \r
+\r
   @return A return value from gST->StdErr->OutputString.\r
 **/\r
 EFI_STATUS\r
@@ -208,11 +213,11 @@ FileInterfaceStdErrWrite(
 \r
 /**\r
   File style interface for console StdOut (Read).\r
-  \r
+\r
   @param[in] This              Ignored.\r
   @param[in, out] BufferSize   Ignored.\r
   @param[out] Buffer           Ignored.\r
-  \r
+\r
   @retval EFI_UNSUPPORTED\r
 **/\r
 EFI_STATUS\r
@@ -228,11 +233,11 @@ FileInterfaceStdOutRead(
 \r
 /**\r
   File style interface for console StdErr (Read).\r
-  \r
+\r
   @param[in] This              Ignored.\r
   @param[in, out] BufferSize   Ignored.\r
   @param[out] Buffer           Ignored.\r
-  \r
+\r
   @retval EFI_UNSUPPORTED Always.\r
 **/\r
 EFI_STATUS\r
@@ -248,11 +253,11 @@ FileInterfaceStdErrRead(
 \r
 /**\r
   File style interface for NUL file (Read).\r
-  \r
+\r
   @param[in] This              Ignored.\r
   @param[in, out] BufferSize   Poiner to 0 upon return.\r
   @param[out] Buffer           Ignored.\r
-  \r
+\r
   @retval EFI_SUCCESS Always.\r
 **/\r
 EFI_STATUS\r
@@ -269,11 +274,11 @@ FileInterfaceNulRead(
 \r
 /**\r
   File style interface for NUL file (Write).\r
-  \r
+\r
   @param[in] This              Ignored.\r
   @param[in, out] BufferSize   Ignored.\r
   @param[in] Buffer            Ignored.\r
-  \r
+\r
   @retval EFI_SUCCESS\r
 **/\r
 EFI_STATUS\r
@@ -287,6 +292,144 @@ FileInterfaceNulWrite(
   return (EFI_SUCCESS);\r
 }\r
 \r
+/**\r
+  Create the TAB completion list.\r
+\r
+  @param[in]  InputString       The command line to expand.\r
+  @param[in]  StringLen         Length of the command line.\r
+  @param[in]  BufferSize        Buffer size.\r
+  @param[in, out] TabCompletionList Return the TAB completion list.\r
+  @param[in, out] TabUpdatePos      Return the TAB update position.\r
+**/\r
+EFI_STATUS\r
+CreateTabCompletionList (\r
+  IN CONST CHAR16             *InputString,\r
+  IN CONST UINTN              StringLen,\r
+  IN CONST UINTN              BufferSize,\r
+  IN OUT EFI_SHELL_FILE_INFO  **TabCompletionList,\r
+  IN OUT   UINTN              *TabUpdatePos\r
+)\r
+{\r
+  BOOLEAN             InQuotation;\r
+  UINTN               TabPos;\r
+  UINTN               Index;\r
+  CONST CHAR16        *Cwd;\r
+  EFI_STATUS          Status;\r
+  CHAR16              *TabStr;\r
+  EFI_SHELL_FILE_INFO *FileList;\r
+  EFI_SHELL_FILE_INFO *FileInfo;\r
+  EFI_SHELL_FILE_INFO *TempFileInfo;\r
+\r
+  //\r
+  // Allocate buffers\r
+  //\r
+  TabStr = AllocateZeroPool (BufferSize);\r
+  if (TabStr == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // handle auto complete of file and directory names...\r
+  // E.g.: cd fs0:\EFI\Bo<TAB>\r
+  //          ^        ^\r
+  //          TabPos   TabUpdatePos\r
+  //\r
+  TabPos        = 0;\r
+  *TabUpdatePos = 0;\r
+  FileList      = NULL;\r
+  InQuotation   = FALSE;\r
+  for (Index = 0; Index < StringLen; Index++) {\r
+    switch (InputString[Index]) {\r
+    case L'\"':\r
+      InQuotation = (BOOLEAN) (!InQuotation);\r
+      break;\r
+\r
+    case L' ':\r
+      if (!InQuotation) {\r
+        TabPos = Index + 1;\r
+        *TabUpdatePos = TabPos;\r
+      }\r
+      break;\r
+\r
+    case L':':\r
+      //\r
+      // handle the case "fs0:<TAB>"\r
+      // Update the TabUpdatePos as well.\r
+      //\r
+    case L'\\':\r
+      *TabUpdatePos = Index + 1;\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (StrStr (InputString + TabPos, L":") == NULL) {\r
+    //\r
+    // If file path doesn't contain ":", ...\r
+    //\r
+    Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL);\r
+    if (Cwd != NULL) {\r
+      if (InputString[TabPos] != L'\\') {\r
+        //\r
+        // and it doesn't begin with "\\", it's a path relative to current directory.\r
+        // TabStr = "<cwd>\\"\r
+        //\r
+        StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1);\r
+        StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\");\r
+      } else {\r
+        //\r
+        // and it begins with "\\", it's a path pointing to root directory of current map.\r
+        // TabStr = "fsx:"\r
+        //\r
+        Index = StrStr (Cwd, L":") - Cwd + 1;\r
+        StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, Index);\r
+      }\r
+    }\r
+  }\r
+  StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), InputString + TabPos, StringLen - TabPos);\r
+  StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"*", (BufferSize) / sizeof (CHAR16) - 1 - StrLen (TabStr));\r
+  Status  = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FileList);\r
+\r
+  //\r
+  // Filter out the non-directory for "CD" command\r
+  // Filter "." and ".." for all\r
+  //\r
+  if (!EFI_ERROR (Status) && FileList != NULL) {\r
+    //\r
+    // Skip the spaces in the beginning\r
+    //\r
+    while (*InputString == L' ') {\r
+      InputString++;\r
+    }\r
+\r
+    for (FileInfo = (EFI_SHELL_FILE_INFO *) GetFirstNode (&FileList->Link); !IsNull (&FileList->Link, &FileInfo->Link); ) {\r
+      if (((StrCmp (FileInfo->FileName, L".") == 0) || (StrCmp (FileInfo->FileName, L"..") == 0)) ||\r
+          (((InputString[0] == L'c' || InputString[0] == L'C') && (InputString[1] == L'd' || InputString[1] == L'D')) &&\r
+           (ShellIsDirectory (FileInfo->FullName) != EFI_SUCCESS))) {\r
+        TempFileInfo = FileInfo;\r
+        FileInfo = (EFI_SHELL_FILE_INFO *) RemoveEntryList (&FileInfo->Link);\r
+        InternalFreeShellFileInfoNode (TempFileInfo);\r
+      } else {\r
+        FileInfo = (EFI_SHELL_FILE_INFO *) GetNextNode (&FileList->Link, &FileInfo->Link);\r
+      }\r
+    }\r
+  }\r
+\r
+  if (FileList != NULL && !IsListEmpty (&FileList->Link)) {\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList);\r
+    Status = EFI_NOT_FOUND;\r
+  }\r
+\r
+  FreePool (TabStr);\r
+\r
+  *TabCompletionList = FileList;\r
+  return Status;\r
+}\r
+\r
 /**\r
   File style interface for console (Read).\r
 \r
@@ -321,6 +464,7 @@ FileInterfaceStdInRead(
 {\r
   CHAR16              *CurrentString;\r
   BOOLEAN             Done;\r
+  UINTN               TabUpdatePos;   // Start index of the string updated by TAB stroke\r
   UINTN               Column;         // Column of current cursor\r
   UINTN               Row;            // Row of current cursor\r
   UINTN               StartColumn;    // Column at the beginning of the line\r
@@ -329,7 +473,6 @@ FileInterfaceStdInRead(
   UINTN               StringLen;      // Total length of the line\r
   UINTN               StringCurPos;   // Line index corresponding to the cursor\r
   UINTN               MaxStr;         // Maximum possible line length\r
-  UINTN               Index;\r
   UINTN               TotalColumn;     // Num of columns in the console\r
   UINTN               TotalRow;       // Num of rows in the console\r
   UINTN               SkipLength;\r
@@ -343,18 +486,10 @@ FileInterfaceStdInRead(
   BOOLEAN             InScrolling;\r
   EFI_STATUS          Status;\r
   BOOLEAN             InTabScrolling; // Whether in TAB-completion state\r
-  EFI_SHELL_FILE_INFO *FoundFileList;\r
-  EFI_SHELL_FILE_INFO *TabLinePos;\r
-  EFI_SHELL_FILE_INFO *TempPos;\r
-  CHAR16              *TabStr;\r
-  CHAR16              *TabOutputStr;\r
-  BOOLEAN             InQuotationMode;\r
-  CHAR16              *TempStr;\r
-  UINTN               TabPos;         // Start index of the string to search for TAB completion.\r
-  UINTN               TabUpdatePos;   // Start index of the string updated by TAB stroke\r
-//  UINTN               Count;\r
+  EFI_SHELL_FILE_INFO *TabCompleteList;\r
+  EFI_SHELL_FILE_INFO *TabCurrent;\r
   UINTN               EventIndex;\r
-  CONST CHAR16        *Cwd;\r
+  CHAR16              *TabOutputStr;\r
 \r
   //\r
   // If buffer is not large enough to hold a CHAR16, return minimum buffer size\r
@@ -375,24 +510,10 @@ FileInterfaceStdInRead(
   InScrolling       = FALSE;\r
   InTabScrolling    = FALSE;\r
   Status            = EFI_SUCCESS;\r
-  TabLinePos        = NULL;\r
-  FoundFileList     = NULL;\r
-  TempPos           = NULL;\r
-  TabPos            = 0;\r
+  TabOutputStr      = NULL;\r
   TabUpdatePos      = 0;\r
-\r
-  //\r
-  // Allocate buffers\r
-  //\r
-  TabStr            = AllocateZeroPool (*BufferSize);\r
-  if (TabStr == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-  TabOutputStr      = AllocateZeroPool (*BufferSize);\r
-  if (TabOutputStr == NULL) {\r
-    FreePool(TabStr);\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+  TabCompleteList   = NULL;\r
+  TabCurrent        = NULL;\r
 \r
   //\r
   // Get the screen setting and the current cursor location\r
@@ -417,7 +538,13 @@ FileInterfaceStdInRead(
     gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
     if (EFI_ERROR (Status)) {\r
-      continue;\r
+\r
+      if (Status == EFI_NOT_READY)\r
+        continue;\r
+\r
+      ZeroMem (CurrentString, MaxStr * sizeof(CHAR16));\r
+      StringLen = 0;\r
+      break;\r
     }\r
 \r
     //\r
@@ -443,11 +570,11 @@ FileInterfaceStdInRead(
     // If we are quitting TAB scrolling...\r
     //\r
     if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) {\r
-        if (FoundFileList != NULL) {\r
-          ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FoundFileList);\r
-          DEBUG_CODE(FoundFileList = NULL;);\r
-        }\r
-        InTabScrolling = FALSE;\r
+      if (TabCompleteList != NULL) {\r
+        ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);\r
+        DEBUG_CODE(TabCompleteList = NULL;);\r
+      }\r
+      InTabScrolling = FALSE;\r
     }\r
 \r
     switch (Key.UnicodeChar) {\r
@@ -480,92 +607,39 @@ FileInterfaceStdInRead(
       break;\r
 \r
     case CHAR_TAB:\r
-      //\r
-      // handle auto complete of file and directory names...\r
-      //\r
-      if (InTabScrolling) {\r
-        ASSERT(FoundFileList != NULL);\r
-        ASSERT(TabLinePos != NULL);\r
-        TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);\r
-        if (IsNull(&(FoundFileList->Link), &TabLinePos->Link)) {\r
-          TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);\r
-        }\r
-      } else {\r
-        TabPos          = 0;\r
-        TabUpdatePos    = 0;\r
-        InQuotationMode = FALSE;\r
-        for (Index = 0; Index < StringLen; Index++) {\r
-          if (CurrentString[Index] == L'\"') {\r
-            InQuotationMode = (BOOLEAN)(!InQuotationMode);\r
-          }\r
-          if (CurrentString[Index] == L' ' && !InQuotationMode) {\r
-            TabPos = Index + 1;\r
-            TabUpdatePos = Index + 1;\r
-          }\r
-          if (CurrentString[Index] == L'\\') {\r
-            TabUpdatePos = Index + 1;\r
-          }\r
+      if (!InTabScrolling) {\r
+        TabCurrent = NULL;\r
+        //\r
+        // Initialize a tab complete operation.\r
+        //\r
+        Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos);\r
+        if (!EFI_ERROR(Status)) {\r
+          InTabScrolling = TRUE;\r
         }\r
-        if (StrStr(CurrentString + TabPos, L":") == NULL) {\r
-          Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir(NULL);\r
-          if (Cwd != NULL) {\r
-            StrCpy(TabStr, Cwd);\r
-            if (TabStr[StrLen(TabStr)-1] == L'\\' && *(CurrentString + TabPos) == L'\\' ) {\r
-              TabStr[StrLen(TabStr)-1] = CHAR_NULL;\r
-            }\r
-            StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16));\r
-          } else {\r
-            StrCpy(TabStr, L"");\r
-            StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16));\r
-          }\r
+\r
+        //\r
+        // We do not set up the replacement.\r
+        // The next section will do that.\r
+        //\r
+      }\r
+\r
+      if (InTabScrolling) {\r
+        //\r
+        // We are in a tab complete operation.\r
+        // set up the next replacement.\r
+        //\r
+        ASSERT(TabCompleteList != NULL);\r
+        if (TabCurrent == NULL) {\r
+          TabCurrent = (EFI_SHELL_FILE_INFO*) GetFirstNode (&TabCompleteList->Link);\r
         } else {\r
-          StrCpy(TabStr, CurrentString + TabPos);\r
+          TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);\r
         }\r
-        StrCat(TabStr, L"*");\r
-        FoundFileList = NULL;\r
-//        TabStr = PathCleanUpDirectories(TabStr);\r
-        Status  = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FoundFileList);\r
-        for ( TempStr = CurrentString\r
-            ; *TempStr == L' '\r
-            ; TempStr++); // note the ';'... empty for loop\r
+\r
         //\r
-        // make sure we have a list before we do anything more...\r
+        // Skip over the empty list beginning node\r
         //\r
-        if (EFI_ERROR (Status) || FoundFileList == NULL) {\r
-          InTabScrolling = FALSE;\r
-          TabLinePos = NULL;\r
-          continue;\r
-        } else {\r
-          //\r
-          // enumerate through the list of files\r
-          //\r
-          for ( TempPos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(FoundFileList->Link))\r
-              ; !IsNull(&FoundFileList->Link, &TempPos->Link)\r
-              ; TempPos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &(TempPos->Link))\r
-             ){\r
-            //\r
-            // If "cd" is typed, only directory name will be auto-complete filled\r
-            // in either case . and .. will be removed.\r
-            //\r
-            if ((((TempStr[0] == L'c' || TempStr[0] == L'C') &&\r
-                (TempStr[1] == L'd' || TempStr[1] == L'D')\r
-               ) && ((ShellIsDirectory(TempPos->FullName) != EFI_SUCCESS)\r
-                ||(StrCmp(TempPos->FileName, L".") == 0)\r
-                ||(StrCmp(TempPos->FileName, L"..") == 0)\r
-               )) || ((StrCmp(TempPos->FileName, L".") == 0)\r
-                ||(StrCmp(TempPos->FileName, L"..") == 0))){\r
-                TabLinePos = TempPos;\r
-                TempPos = (EFI_SHELL_FILE_INFO*)(RemoveEntryList(&(TempPos->Link))->BackLink);\r
-                InternalFreeShellFileInfoNode(TabLinePos);\r
-            }\r
-          }\r
-          if (FoundFileList != NULL && !IsListEmpty(&FoundFileList->Link)) {\r
-            TabLinePos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FoundFileList->Link);\r
-            InTabScrolling = TRUE;\r
-          } else {\r
-            FreePool(FoundFileList);\r
-            FoundFileList = NULL;\r
-          }\r
+        if (IsNull(&TabCompleteList->Link, &TabCurrent->Link)) {\r
+          TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);\r
         }\r
       }\r
       break;\r
@@ -706,23 +780,31 @@ FileInterfaceStdInRead(
     // the next file or directory name\r
     //\r
     if (InTabScrolling) {\r
+      TabOutputStr = AllocateZeroPool (*BufferSize);\r
+      if (TabOutputStr == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+      }\r
+    }\r
+\r
+    if (InTabScrolling && TabOutputStr != NULL) {\r
+\r
       //\r
       // Adjust the column and row to the start of TAB-completion string.\r
       //\r
       Column = (StartColumn + TabUpdatePos) % TotalColumn;\r
       Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;\r
-      OutputLength = StrLen (TabLinePos->FileName);\r
+      OutputLength = StrLen (TabCurrent->FileName);\r
       //\r
       // if the output string contains  blank space, quotation marks L'\"'\r
       // should be added to the output.\r
       //\r
-      if (StrStr(TabLinePos->FileName, L" ") != NULL){\r
+      if (StrStr(TabCurrent->FileName, L" ") != NULL){\r
         TabOutputStr[0] = L'\"';\r
-        CopyMem (TabOutputStr + 1, TabLinePos->FileName, OutputLength * sizeof (CHAR16));\r
+        CopyMem (TabOutputStr + 1, TabCurrent->FileName, OutputLength * sizeof (CHAR16));\r
         TabOutputStr[OutputLength + 1] = L'\"';\r
         TabOutputStr[OutputLength + 2] = CHAR_NULL;\r
       } else {\r
-        CopyMem (TabOutputStr, TabLinePos->FileName, OutputLength * sizeof (CHAR16));\r
+        CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16));\r
         TabOutputStr[OutputLength] = CHAR_NULL;\r
       }\r
       OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;\r
@@ -733,6 +815,8 @@ FileInterfaceStdInRead(
       if (StringLen > TabUpdatePos + OutputLength) {\r
         Delete = StringLen - TabUpdatePos - OutputLength;\r
       }\r
+\r
+      FreePool(TabOutputStr);\r
     }\r
 \r
     //\r
@@ -836,8 +920,6 @@ FileInterfaceStdInRead(
     AddLineToCommandHistory(CurrentString);\r
   }\r
 \r
-  FreePool (TabStr);\r
-  FreePool (TabOutputStr);\r
   //\r
   // Return the data to the caller\r
   //\r
@@ -847,9 +929,12 @@ FileInterfaceStdInRead(
   // if this was used it should be deallocated by now...\r
   // prevent memory leaks...\r
   //\r
-  ASSERT(FoundFileList == NULL);\r
+  if (TabCompleteList != NULL) {\r
+    ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);\r
+  }\r
+  ASSERT(TabCompleteList == NULL);\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
 //\r
@@ -940,9 +1025,9 @@ typedef struct {
   File style interface for Environment Variable (Close).\r
 \r
   Frees the memory for this object.\r
-  \r
+\r
   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
-  \r
+\r
   @retval EFI_SUCCESS\r
 **/\r
 EFI_STATUS\r
@@ -954,42 +1039,81 @@ FileInterfaceEnvClose(
   VOID*       NewBuffer;\r
   UINTN       NewSize;\r
   EFI_STATUS  Status;\r
+  BOOLEAN     Volatile;\r
+  UINTN       TotalSize;\r
 \r
   //\r
-  // Most if not all UEFI commands will have an '\r\n' at the end of any output. \r
-  // Since the output was redirected to a variable, it does not make sense to \r
+  // Most if not all UEFI commands will have an '\r\n' at the end of any output.\r
+  // Since the output was redirected to a variable, it does not make sense to\r
   // keep this.  So, before closing, strip the trailing '\r\n' from the variable\r
   // if it exists.\r
   //\r
   NewBuffer   = NULL;\r
   NewSize     = 0;\r
+  TotalSize   = 0;\r
+\r
+  Status = IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &Volatile);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
   if (Status == EFI_BUFFER_TOO_SMALL) {\r
-    NewBuffer = AllocateZeroPool(NewSize + sizeof(CHAR16));\r
+    TotalSize = NewSize + sizeof (CHAR16);\r
+    NewBuffer = AllocateZeroPool (TotalSize);\r
     if (NewBuffer == NULL) {\r
       return EFI_OUT_OF_RESOURCES;\r
-    }  \r
+    }\r
     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
   }\r
-  \r
+\r
   if (!EFI_ERROR(Status) && NewBuffer != NULL) {\r
-    \r
-    if (StrSize(NewBuffer) > 6)\r
-    {\r
-      if ((((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 2] == CHAR_LINEFEED) \r
-           && (((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] == CHAR_CARRIAGE_RETURN)) {\r
-        ((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] = CHAR_NULL;   \r
+\r
+    if (TotalSize / sizeof (CHAR16) >= 3) {\r
+      if ( (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 2] == CHAR_LINEFEED) &&\r
+           (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] == CHAR_CARRIAGE_RETURN)\r
+         ) {\r
+        ((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] = CHAR_NULL;\r
+        //\r
+        // If the NewBuffer end with \r\n\0, We will repace '\r' by '\0' and then update TotalSize.\r
+        //\r
+        TotalSize -= sizeof(CHAR16) * 2;\r
       }\r
-    \r
-      if (IsVolatileEnv(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name)) {\r
-        Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
+\r
+      if (Volatile) {\r
+        Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (\r
+                   ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+                   TotalSize - sizeof (CHAR16),\r
+                   NewBuffer\r
+                   );\r
+\r
+        if (!EFI_ERROR(Status)) {\r
+          Status = ShellAddEnvVarToList (\r
+                     ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+                     NewBuffer,\r
+                     TotalSize,\r
+                     EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+                     );\r
+        }\r
       } else {\r
-        Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
+        Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (\r
+                   ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+                   TotalSize - sizeof (CHAR16),\r
+                   NewBuffer\r
+                   );\r
+\r
+        if (!EFI_ERROR(Status)) {\r
+          Status = ShellAddEnvVarToList (\r
+                     ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+                     NewBuffer,\r
+                     TotalSize,\r
+                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+                     );\r
+        }\r
       }\r
     }\r
-  } \r
-  \r
+  }\r
+\r
   SHELL_FREE_NON_NULL(NewBuffer);\r
   FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This);\r
   return (Status);\r
@@ -997,9 +1121,9 @@ FileInterfaceEnvClose(
 \r
 /**\r
   File style interface for Environment Variable (Delete).\r
-  \r
+\r
   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
-  \r
+\r
   @retval The return value from FileInterfaceEnvClose().\r
 **/\r
 EFI_STATUS\r
@@ -1014,11 +1138,11 @@ FileInterfaceEnvDelete(
 \r
 /**\r
   File style interface for Environment Variable (Read).\r
-  \r
+\r
   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[in, out] BufferSize   Size in bytes of Buffer.\r
   @param[out] Buffer           The pointer to the buffer to fill.\r
-  \r
+\r
   @retval EFI_SUCCESS   The data was read.\r
 **/\r
 EFI_STATUS\r
@@ -1037,12 +1161,14 @@ FileInterfaceEnvRead(
 \r
 /**\r
   File style interface for Volatile Environment Variable (Write).\r
-  \r
+  This function also caches the environment variable into gShellEnvVarList.\r
+\r
   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[in, out] BufferSize   Size in bytes of Buffer.\r
   @param[in] Buffer            The pointer to the buffer to write.\r
-  \r
-  @retval EFI_SUCCESS   The data was read.\r
+\r
+  @retval EFI_SUCCESS             The data was successfully write to variable.\r
+  @retval SHELL_OUT_OF_RESOURCES  A memory allocation failed.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -1055,41 +1181,71 @@ FileInterfaceEnvVolWrite(
   VOID*       NewBuffer;\r
   UINTN       NewSize;\r
   EFI_STATUS  Status;\r
+  UINTN       TotalSize;\r
 \r
   NewBuffer   = NULL;\r
   NewSize     = 0;\r
+  TotalSize   = 0;\r
 \r
   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
-  if (Status == EFI_BUFFER_TOO_SMALL){\r
-    NewBuffer = AllocateZeroPool(NewSize + *BufferSize + sizeof(CHAR16));\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    TotalSize = NewSize + *BufferSize + sizeof (CHAR16);\r
+  } else if (Status == EFI_NOT_FOUND) {\r
+    TotalSize = *BufferSize + sizeof(CHAR16);\r
+  } else {\r
+    return Status;\r
+  }\r
+\r
+  NewBuffer = AllocateZeroPool (TotalSize);\r
+  if (NewBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
   }\r
-  if (!EFI_ERROR(Status) && NewBuffer != NULL) {\r
-    while (((CHAR16*)NewBuffer)[NewSize/2] == CHAR_NULL) {\r
-      //\r
-      // We want to overwrite the CHAR_NULL\r
-      //\r
-      NewSize -= 2;\r
-    }\r
-    CopyMem((UINT8*)NewBuffer + NewSize + 2, Buffer, *BufferSize);\r
-    Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
-    FreePool(NewBuffer);\r
-    return (Status);\r
-  } else {\r
-    SHELL_FREE_NON_NULL(NewBuffer);\r
-    return (SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, *BufferSize, Buffer));\r
+\r
+  if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {\r
+    FreePool (NewBuffer);\r
+    return Status;\r
+  }\r
+\r
+  CopyMem ((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);\r
+  Status = ShellAddEnvVarToList (\r
+             ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+             NewBuffer,\r
+             TotalSize,\r
+             EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool (NewBuffer);\r
+    return Status;\r
   }\r
+\r
+  Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (\r
+             ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+             TotalSize - sizeof (CHAR16),\r
+             NewBuffer\r
+             );\r
+  if (EFI_ERROR(Status)) {\r
+    ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);\r
+  }\r
+\r
+  FreePool (NewBuffer);\r
+  return Status;\r
 }\r
 \r
 \r
 /**\r
   File style interface for Non Volatile Environment Variable (Write).\r
-  \r
+  This function also caches the environment variable into gShellEnvVarList.\r
+\r
   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[in, out] BufferSize   Size in bytes of Buffer.\r
   @param[in] Buffer            The pointer to the buffer to write.\r
-  \r
-  @retval EFI_SUCCESS   The data was read.\r
+\r
+  @retval EFI_SUCCESS             The data was successfully write to variable.\r
+  @retval SHELL_OUT_OF_RESOURCES  A memory allocation failed.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -1102,27 +1258,58 @@ FileInterfaceEnvNonVolWrite(
   VOID*       NewBuffer;\r
   UINTN       NewSize;\r
   EFI_STATUS  Status;\r
+  UINTN       TotalSize;\r
 \r
   NewBuffer   = NULL;\r
   NewSize     = 0;\r
+  TotalSize   = 0;\r
 \r
   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
-  if (Status == EFI_BUFFER_TOO_SMALL){\r
-    NewBuffer = AllocateZeroPool(NewSize + *BufferSize);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    TotalSize = NewSize + *BufferSize + sizeof (CHAR16);\r
+  } else if (Status == EFI_NOT_FOUND) {\r
+    TotalSize = *BufferSize + sizeof (CHAR16);\r
+  } else {\r
+    return Status;\r
+  }\r
+\r
+  NewBuffer = AllocateZeroPool (TotalSize);\r
+  if (NewBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
   }\r
-  if (!EFI_ERROR(Status)) {\r
-    CopyMem((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);\r
-    return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(\r
-    ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
-    NewSize + *BufferSize,\r
-    NewBuffer));\r
-  } else {\r
-    return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(\r
-    ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
-    *BufferSize,\r
-    Buffer));\r
+\r
+  if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {\r
+    FreePool (NewBuffer);\r
+    return Status;\r
+  }\r
+\r
+  CopyMem ((UINT8*) NewBuffer + NewSize, Buffer, *BufferSize);\r
+  Status = ShellAddEnvVarToList (\r
+             ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+             NewBuffer,\r
+             TotalSize,\r
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (NewBuffer);\r
+    return Status;\r
   }\r
+\r
+  Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (\r
+             ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+             TotalSize - sizeof (CHAR16),\r
+             NewBuffer\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);\r
+  }\r
+\r
+  FreePool (NewBuffer);\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -1135,21 +1322,29 @@ FileInterfaceEnvNonVolWrite(
   @return other     a pointer to an EFI_FILE_PROTOCOL structure\r
 **/\r
 EFI_FILE_PROTOCOL*\r
-EFIAPI\r
 CreateFileInterfaceEnv(\r
   IN CONST CHAR16 *EnvName\r
   )\r
 {\r
+  EFI_STATUS                     Status;\r
   EFI_FILE_PROTOCOL_ENVIRONMENT  *EnvFileInterface;\r
+  UINTN                          EnvNameSize;\r
+  BOOLEAN                        Volatile;\r
 \r
   if (EnvName == NULL) {\r
     return (NULL);\r
   }\r
 \r
+  Status = IsVolatileEnv (EnvName, &Volatile);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
   //\r
   // Get some memory\r
   //\r
-  EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+StrSize(EnvName));\r
+  EnvNameSize = StrSize(EnvName);\r
+  EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize);\r
   if (EnvFileInterface == NULL){\r
     return (NULL);\r
   }\r
@@ -1168,12 +1363,12 @@ CreateFileInterfaceEnv(
   EnvFileInterface->Delete      = FileInterfaceEnvDelete;\r
   EnvFileInterface->Read        = FileInterfaceEnvRead;\r
 \r
-  StrCpy(EnvFileInterface->Name, EnvName);\r
+  CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize);\r
 \r
   //\r
   // Assign the different members for Volatile and Non-Volatile variables\r
   //\r
-  if (IsVolatileEnv(EnvName)) {\r
+  if (Volatile) {\r
     EnvFileInterface->Write       = FileInterfaceEnvVolWrite;\r
   } else {\r
     EnvFileInterface->Write       = FileInterfaceEnvNonVolWrite;\r
@@ -1189,7 +1384,6 @@ CreateFileInterfaceEnv(
   @param[in, out] Row         Current row of the cursor position\r
 **/\r
 VOID\r
-EFIAPI\r
 MoveCursorBackward (\r
   IN     UINTN                   LineLength,\r
   IN OUT UINTN                   *Column,\r
@@ -1219,7 +1413,6 @@ MoveCursorBackward (
   @param[in, out] Row         Current row of the cursor position\r
 **/\r
 VOID\r
-EFIAPI\r
 MoveCursorForward (\r
   IN     UINTN                   LineLength,\r
   IN     UINTN                   TotalRow,\r
@@ -1251,7 +1444,6 @@ MoveCursorForward (
   @param[in] StartColumn  which column to start at\r
 **/\r
 VOID\r
-EFIAPI\r
 PrintCommandHistory (\r
   IN CONST UINTN TotalCols,\r
   IN CONST UINTN TotalRows,\r
@@ -1316,14 +1508,15 @@ typedef struct {
   UINT64                Position;\r
   UINT64                BufferSize;\r
   BOOLEAN               Unicode;\r
+  UINT64                FileSize;\r
 } EFI_FILE_PROTOCOL_MEM;\r
 \r
 /**\r
   File style interface for Mem (SetPosition).\r
-  \r
+\r
   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[out] Position  The position to set.\r
-  \r
+\r
   @retval EFI_SUCCESS             The position was successfully changed.\r
   @retval EFI_INVALID_PARAMETER   The Position was invalid.\r
 **/\r
@@ -1334,7 +1527,7 @@ FileInterfaceMemSetPosition(
   OUT UINT64 Position\r
   )\r
 {\r
-  if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) {\r
+  if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize) {\r
     ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position;\r
     return (EFI_SUCCESS);\r
   } else {\r
@@ -1344,12 +1537,12 @@ FileInterfaceMemSetPosition(
 \r
 /**\r
   File style interface for Mem (GetPosition).\r
-  \r
+\r
   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[out] Position  The pointer to the position.\r
-  \r
+\r
   @retval EFI_SUCCESS   The position was retrieved.\r
-**/ \r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 FileInterfaceMemGetPosition(\r
@@ -1361,13 +1554,61 @@ FileInterfaceMemGetPosition(
   return (EFI_SUCCESS);\r
 }\r
 \r
+/**\r
+  File style interface for Mem (GetInfo).\r
+\r
+  @param  This            Protocol instance pointer.\r
+  @param  InformationType Type of information to return in Buffer.\r
+  @param  BufferSize      On input size of buffer, on output amount of data in buffer.\r
+  @param  Buffer          The buffer to return data.\r
+\r
+  @retval EFI_SUCCESS          Data was returned.\r
+  @retval EFI_UNSUPPORT        InformationType is not supported.\r
+  @retval EFI_NO_MEDIA         The device has no media.\r
+  @retval EFI_DEVICE_ERROR     The device reported an error.\r
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+  @retval EFI_WRITE_PROTECTED  The device is write protected.\r
+  @retval EFI_ACCESS_DENIED    The file was open for read only.\r
+  @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileInterfaceMemGetInfo(\r
+  IN EFI_FILE_PROTOCOL        *This,\r
+  IN EFI_GUID                 *InformationType,\r
+  IN OUT UINTN                *BufferSize,\r
+  OUT VOID                    *Buffer\r
+  )\r
+{\r
+  EFI_FILE_INFO               *FileInfo;\r
+\r
+  if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
+    if (*BufferSize < sizeof (EFI_FILE_INFO)) {\r
+      *BufferSize = sizeof (EFI_FILE_INFO);\r
+      return EFI_BUFFER_TOO_SMALL;\r
+    }\r
+    if (Buffer == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    FileInfo = (EFI_FILE_INFO *)Buffer;\r
+    FileInfo->Size = sizeof (*FileInfo);\r
+    ZeroMem (FileInfo, sizeof (*FileInfo));\r
+    FileInfo->FileSize = ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize;\r
+    FileInfo->PhysicalSize = FileInfo->FileSize;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
 /**\r
   File style interface for Mem (Write).\r
-  \r
+\r
   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[in, out] BufferSize   Size in bytes of Buffer.\r
   @param[in] Buffer            The pointer to the buffer to write.\r
-  \r
+\r
   @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.\r
   @retval EFI_SUCCESS          The data was written.\r
 **/\r
@@ -1379,17 +1620,21 @@ FileInterfaceMemWrite(
   IN VOID *Buffer\r
   )\r
 {\r
-  CHAR8 *AsciiBuffer;\r
-  if (((EFI_FILE_PROTOCOL_MEM*)This)->Unicode) {\r
+  CHAR8                  *AsciiBuffer;\r
+  EFI_FILE_PROTOCOL_MEM  *MemFile;\r
+\r
+  MemFile = (EFI_FILE_PROTOCOL_MEM *) This;\r
+  if (MemFile->Unicode) {\r
     //\r
     // Unicode\r
     //\r
-    if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) {\r
-      ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer = ReallocatePool((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize), (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) + (*BufferSize) + 10, ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);\r
-      ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += (*BufferSize) + 10;\r
+    if ((UINTN)(MemFile->Position + (*BufferSize)) > (UINTN)(MemFile->BufferSize)) {\r
+      MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);\r
+      MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD;\r
     }\r
-    CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, Buffer, *BufferSize);\r
-    ((EFI_FILE_PROTOCOL_MEM*)This)->Position += (*BufferSize);\r
+    CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize);\r
+    MemFile->Position += (*BufferSize);\r
+    MemFile->FileSize = MemFile->Position;\r
     return (EFI_SUCCESS);\r
   } else {\r
     //\r
@@ -1400,12 +1645,13 @@ FileInterfaceMemWrite(
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
     AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);\r
-    if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) {\r
-      ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer = ReallocatePool((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize), (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) + AsciiStrSize(AsciiBuffer) + 10, ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);\r
-      ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += AsciiStrSize(AsciiBuffer) + 10;\r
+    if ((UINTN)(MemFile->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(MemFile->BufferSize)) {\r
+      MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);\r
+      MemFile->BufferSize += AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD;\r
     }\r
-    CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));\r
-    ((EFI_FILE_PROTOCOL_MEM*)This)->Position += AsciiStrSize(AsciiBuffer);\r
+    CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));\r
+    MemFile->Position += (*BufferSize / sizeof(CHAR16));\r
+    MemFile->FileSize = MemFile->Position;\r
     FreePool(AsciiBuffer);\r
     return (EFI_SUCCESS);\r
   }\r
@@ -1413,11 +1659,11 @@ FileInterfaceMemWrite(
 \r
 /**\r
   File style interface for Mem (Read).\r
-  \r
+\r
   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[in, out] BufferSize   Size in bytes of Buffer.\r
   @param[in] Buffer            The pointer to the buffer to fill.\r
-  \r
+\r
   @retval EFI_SUCCESS   The data was read.\r
 **/\r
 EFI_STATUS\r
@@ -1428,11 +1674,14 @@ FileInterfaceMemRead(
   IN VOID *Buffer\r
   )\r
 {\r
-  if (*BufferSize > (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position))) {\r
-    (*BufferSize) = (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position));\r
+  EFI_FILE_PROTOCOL_MEM  *MemFile;\r
+\r
+  MemFile = (EFI_FILE_PROTOCOL_MEM *) This;\r
+  if (*BufferSize > (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position))) {\r
+    (*BufferSize) = (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position));\r
   }\r
-  CopyMem(Buffer, ((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, (*BufferSize));\r
-  ((EFI_FILE_PROTOCOL_MEM*)This)->Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize);\r
+  CopyMem(Buffer, ((UINT8*)MemFile->Buffer) + MemFile->Position, (*BufferSize));\r
+  MemFile->Position = MemFile->Position + (*BufferSize);\r
   return (EFI_SUCCESS);\r
 }\r
 \r
@@ -1440,11 +1689,11 @@ FileInterfaceMemRead(
   File style interface for Mem (Close).\r
 \r
   Frees all memory associated with this object.\r
-  \r
+\r
   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
-  \r
+\r
   @retval EFI_SUCCESS   The 'file' was closed.\r
-**/ \r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 FileInterfaceMemClose(\r
@@ -1466,7 +1715,6 @@ FileInterfaceMemClose(
   @return other     A pointer to an EFI_FILE_PROTOCOL structure.\r
 **/\r
 EFI_FILE_PROTOCOL*\r
-EFIAPI\r
 CreateFileInterfaceMem(\r
   IN CONST BOOLEAN Unicode\r
   )\r
@@ -1489,7 +1737,7 @@ CreateFileInterfaceMem(
   FileInterface->Close       = FileInterfaceMemClose;\r
   FileInterface->GetPosition = FileInterfaceMemGetPosition;\r
   FileInterface->SetPosition = FileInterfaceMemSetPosition;\r
-  FileInterface->GetInfo     = FileInterfaceNopGetInfo;\r
+  FileInterface->GetInfo     = FileInterfaceMemGetInfo;\r
   FileInterface->SetInfo     = FileInterfaceNopSetInfo;\r
   FileInterface->Flush       = FileInterfaceNopGeneric;\r
   FileInterface->Delete      = FileInterfaceNopGeneric;\r
@@ -1501,6 +1749,17 @@ CreateFileInterfaceMem(
   ASSERT(FileInterface->BufferSize  == 0);\r
   ASSERT(FileInterface->Position    == 0);\r
 \r
+  if (Unicode) {\r
+    FileInterface->Buffer = AllocateZeroPool(sizeof(gUnicodeFileTag));\r
+    if (FileInterface->Buffer == NULL) {\r
+      FreePool (FileInterface);\r
+      return NULL;\r
+    }\r
+    *((CHAR16 *) (FileInterface->Buffer)) = EFI_UNICODE_BYTE_ORDER_MARK;\r
+    FileInterface->BufferSize = 2;\r
+    FileInterface->Position = 2;\r
+  }\r
+\r
   return ((EFI_FILE_PROTOCOL *)FileInterface);\r
 }\r
 \r
@@ -1525,7 +1784,7 @@ typedef struct {
 \r
   @param  This            Protocol instance pointer.\r
   @param  Position        Byte position from the start of the file.\r
-                          \r
+\r
   @retval EFI_SUCCESS     Data was written.\r
   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.\r
 \r
@@ -1545,7 +1804,7 @@ FileInterfaceFileSetPosition(
 \r
   @param  This            Protocol instance pointer.\r
   @param  Position        Byte position from the start of the file.\r
-                          \r
+\r
   @retval EFI_SUCCESS     Data was written.\r
   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..\r
 \r
@@ -1665,8 +1924,10 @@ FileInterfaceFileRead(
   OUT VOID                    *Buffer\r
   )\r
 {\r
-  CHAR8       *AsciiBuffer;\r
+  CHAR8       *AsciiStrBuffer;\r
+  CHAR16      *UscStrBuffer;\r
   UINTN       Size;\r
+  UINTN       CharNum;\r
   EFI_STATUS  Status;\r
   if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {\r
     //\r
@@ -1677,10 +1938,27 @@ FileInterfaceFileRead(
     //\r
     // Ascii\r
     //\r
-    AsciiBuffer = AllocateZeroPool((Size = *BufferSize));\r
-    Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));\r
-    UnicodeSPrint(Buffer, *BufferSize, L"%a", AsciiBuffer);\r
-    FreePool(AsciiBuffer);\r
+    Size  = (*BufferSize) / sizeof(CHAR16);\r
+    AsciiStrBuffer = AllocateZeroPool(Size + sizeof(CHAR8));\r
+    if (AsciiStrBuffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    UscStrBuffer = AllocateZeroPool(*BufferSize + sizeof(CHAR16));\r
+    if (UscStrBuffer== NULL) {\r
+      SHELL_FREE_NON_NULL(AsciiStrBuffer);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiStrBuffer));\r
+    if (!EFI_ERROR(Status)) {\r
+      CharNum = UnicodeSPrint(UscStrBuffer, *BufferSize + sizeof(CHAR16), L"%a", AsciiStrBuffer);\r
+      if (CharNum == Size) {\r
+        CopyMem (Buffer, UscStrBuffer, *BufferSize);\r
+      } else {\r
+        Status = EFI_UNSUPPORTED;\r
+      }\r
+    }\r
+    SHELL_FREE_NON_NULL(AsciiStrBuffer);\r
+    SHELL_FREE_NON_NULL(UscStrBuffer);\r
     return (Status);\r
   }\r
 }\r
@@ -1721,7 +1999,7 @@ FileInterfaceFileOpen (
   Close and delete the file handle.\r
 \r
   @param  This                     Protocol instance pointer.\r
-                                   \r
+\r
   @retval EFI_SUCCESS              The device was opened.\r
   @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not deleted.\r
 \r
@@ -1740,9 +2018,9 @@ FileInterfaceFileDelete(
 \r
 /**\r
   File style interface for File (Close).\r
-  \r
+\r
   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.\r
-  \r
+\r
   @retval EFI_SUCCESS   The file was closed.\r
 **/\r
 EFI_STATUS\r
@@ -1760,13 +2038,13 @@ FileInterfaceFileClose(
 /**\r
   File style interface for File (Write).\r
 \r
-  If the file was opened with ASCII mode the data will be processed through \r
+  If the file was opened with ASCII mode the data will be processed through\r
   AsciiSPrint before writing.\r
-  \r
+\r
   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.\r
   @param[in, out] BufferSize   Size in bytes of Buffer.\r
   @param[in] Buffer            The pointer to the buffer to write.\r
-  \r
+\r
   @retval EFI_SUCCESS   The data was written.\r
 **/\r
 EFI_STATUS\r
@@ -1803,10 +2081,10 @@ FileInterfaceFileWrite(
 \r
   This will create a new EFI_FILE_PROTOCOL identical to the Templace\r
   except that the new one has Unicode and Ascii knowledge.\r
-  \r
+\r
   @param[in] Template   A pointer to the EFI_FILE_PROTOCOL object.\r
   @param[in] Unicode    TRUE for UCS-2, FALSE for ASCII.\r
-  \r
+\r
   @return a new EFI_FILE_PROTOCOL object to be used instead of the template.\r
 **/\r
 EFI_FILE_PROTOCOL*\r