]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellProtocol.c
ShellPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
index d9293b6aba733800d5fa725e7917d61fe9b2f813..5e529b6568a9fcfdea2057efc67b54bd9bda817c 100644 (file)
@@ -2,19 +2,16 @@
   Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
   manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
 \r
-  Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<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
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
+  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
+  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "Shell.h"\r
-#include <Library/FileHandleLib.h>\r
+\r
+#define INIT_NAME_BUFFER_SIZE  128\r
 \r
 /**\r
   Close an open file handle.\r
@@ -47,7 +44,6 @@ EfiShellClose (
   @retval FALSE     gEfiBlockIoProtocolGuid was not found.\r
 **/\r
 BOOLEAN\r
-EFIAPI\r
 InternalShellProtocolIsBlockIoPresent(\r
   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
   )\r
@@ -77,7 +73,6 @@ InternalShellProtocolIsBlockIoPresent(
   @retval FALSE     gEfiSimpleFileSystemProtocolGuid was not found.\r
 **/\r
 BOOLEAN\r
-EFIAPI\r
 InternalShellProtocolIsSimpleFileSystemPresent(\r
   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
   )\r
@@ -97,49 +92,6 @@ InternalShellProtocolIsSimpleFileSystemPresent(
   return (FALSE);\r
 }\r
 \r
-/**\r
-  Internal worker debug helper function to print out maps as they are added.\r
-\r
-  @param[in] Mapping        string mapping that has been added\r
-  @param[in] DevicePath     pointer to device path that has been mapped.\r
-\r
-  @retval EFI_SUCCESS   the operation was successful.\r
-  @return other         an error ocurred\r
-\r
-  @sa LocateHandle\r
-  @sa OpenProtocol\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InternalShellProtocolDebugPrintMessage (\r
-  IN CONST CHAR16                   *Mapping,\r
-  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
-  )\r
-{\r
-  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevicePathToText;\r
-  EFI_STATUS                        Status;\r
-  CHAR16                            *Temp;\r
-\r
-  Status = EFI_SUCCESS;\r
-  DEBUG_CODE_BEGIN();\r
-  DevicePathToText = NULL;\r
-\r
-  Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid,\r
-                               NULL,\r
-                               (VOID**)&DevicePathToText);\r
-  if (Mapping != NULL) {\r
-    DEBUG((EFI_D_INFO, "Added new map item:\"%S\"\r\n", Mapping));\r
-  }\r
-  if (!EFI_ERROR(Status)) {\r
-    if (DevicePath != NULL) {\r
-      Temp = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
-      DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp));\r
-      FreePool(Temp);\r
-    }\r
-  }\r
-  DEBUG_CODE_END();\r
-  return (Status);\r
-}\r
 \r
 /**\r
   This function creates a mapping for a device path.\r
@@ -191,6 +143,9 @@ EfiShellSetMap(
        ){\r
           if (StringNoCaseCompare(&MapListNode->MapName, &Mapping) == 0) {\r
             RemoveEntryList(&MapListNode->Link);\r
+            SHELL_FREE_NON_NULL(MapListNode->DevicePath);\r
+            SHELL_FREE_NON_NULL(MapListNode->MapName);\r
+            SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);\r
             FreePool(MapListNode);\r
             return (EFI_SUCCESS);\r
           }\r
@@ -455,24 +410,40 @@ EfiShellGetFilePathFromDevicePath(
           ; FilePath = (FILEPATH_DEVICE_PATH*)NextDevicePathNode (&FilePath->Header)\r
          ){\r
         //\r
-        // all the rest should be file path nodes\r
+        // If any node is not a file path node, then the conversion can not be completed\r
         //\r
         if ((DevicePathType(&FilePath->Header) != MEDIA_DEVICE_PATH) ||\r
             (DevicePathSubType(&FilePath->Header) != MEDIA_FILEPATH_DP)) {\r
           FreePool(PathForReturn);\r
-          PathForReturn = NULL;\r
-          ASSERT(FALSE);\r
-        } else {\r
-          //\r
-          // append the path part onto the filepath.\r
-          //\r
-          ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
-          PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L"\\", 1);\r
+          return NULL;\r
+        }\r
 \r
-          AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath);\r
-          PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0);\r
-          FreePool(AlignedNode);\r
+        //\r
+        // append the path part onto the filepath.\r
+        //\r
+        ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
+\r
+        AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath);\r
+        if (AlignedNode == NULL) {\r
+          FreePool (PathForReturn);\r
+          return NULL;\r
+        }\r
+\r
+        // File Path Device Path Nodes 'can optionally add a "\" separator to\r
+        //  the beginning and/or the end of the Path Name string.'\r
+        // (UEFI Spec 2.4 section 9.3.6.4).\r
+        // If necessary, add a "\", but otherwise don't\r
+        // (This is specified in the above section, and also implied by the\r
+        //  UEFI Shell spec section 3.7)\r
+        if ((PathSize != 0)                        &&\r
+            (PathForReturn != NULL)                &&\r
+            (PathForReturn[PathSize / sizeof (CHAR16) - 1] != L'\\') &&\r
+            (AlignedNode->PathName[0]    != L'\\')) {\r
+          PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1);\r
         }\r
+\r
+        PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0);\r
+        FreePool(AlignedNode);\r
       } // for loop of remaining nodes\r
     }\r
     if (PathForReturn != NULL) {\r
@@ -524,18 +495,18 @@ EfiShellGetDevicePathFromFilePath(
     if (Cwd == NULL) {\r
       return (NULL);\r
     }\r
-    Size = StrSize(Cwd);\r
-    Size += StrSize(Path);\r
+    Size = StrSize(Cwd) + StrSize(Path);\r
     NewPath = AllocateZeroPool(Size);\r
     if (NewPath == NULL) {\r
       return (NULL);\r
     }\r
-    StrCpy(NewPath, Cwd);\r
+    StrCpyS(NewPath, Size/sizeof(CHAR16), Cwd);\r
+    StrCatS(NewPath, Size/sizeof(CHAR16), L"\\");\r
     if (*Path == L'\\') {\r
       Path++;\r
       while (PathRemoveLastItem(NewPath)) ;\r
     }\r
-    StrCat(NewPath, Path);\r
+    StrCatS(NewPath, Size/sizeof(CHAR16), Path);\r
     DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath);\r
     FreePool(NewPath);\r
     return (DevicePathForReturn);\r
@@ -587,7 +558,8 @@ EfiShellGetDevicePathFromFilePath(
   //\r
   // build the full device path\r
   //\r
-  if (*(Path+StrLen(MapName)+1) == CHAR_NULL) {\r
+  if ((*(Path+StrLen(MapName)) != CHAR_NULL) &&\r
+      (*(Path+StrLen(MapName)+1) == CHAR_NULL)) {\r
     DevicePathForReturn = FileDevicePath(Handle, L"\\");\r
   } else {\r
     DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName));\r
@@ -648,15 +620,12 @@ EfiShellGetDeviceName(
 {\r
   EFI_STATUS                        Status;\r
   EFI_COMPONENT_NAME2_PROTOCOL      *CompName2;\r
-  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevicePathToText;\r
   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;\r
   EFI_HANDLE                        *HandleList;\r
   UINTN                             HandleCount;\r
   UINTN                             LoopVar;\r
   CHAR16                            *DeviceNameToReturn;\r
   CHAR8                             *Lang;\r
-  CHAR8                             *TempChar;\r
-\r
   UINTN                             ParentControllerCount;\r
   EFI_HANDLE                        *ParentControllerBuffer;\r
   UINTN                             ParentDriverCount;\r
@@ -713,23 +682,7 @@ EfiShellGetDeviceName(
       if (EFI_ERROR(Status)) {\r
         continue;\r
       }\r
-      if (Language == NULL) {\r
-        Lang = AllocateZeroPool(AsciiStrSize(CompName2->SupportedLanguages));\r
-        if (Lang == NULL) {\r
-          return (EFI_OUT_OF_RESOURCES);\r
-        }\r
-        AsciiStrCpy(Lang, CompName2->SupportedLanguages);\r
-        TempChar = AsciiStrStr(Lang, ";");\r
-        if (TempChar != NULL){\r
-          *TempChar = CHAR_NULL;\r
-        }\r
-      } else {\r
-        Lang = AllocateZeroPool(AsciiStrSize(Language));\r
-        if (Lang == NULL) {\r
-          return (EFI_OUT_OF_RESOURCES);\r
-        }\r
-        AsciiStrCpy(Lang, Language);\r
-      }\r
+      Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);\r
       Status = CompName2->GetControllerName(CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn);\r
       FreePool(Lang);\r
       Lang = NULL;\r
@@ -772,23 +725,7 @@ EfiShellGetDeviceName(
           if (EFI_ERROR(Status)) {\r
             continue;\r
           }\r
-          if (Language == NULL) {\r
-            Lang = AllocateZeroPool(AsciiStrSize(CompName2->SupportedLanguages));\r
-            if (Lang == NULL) {\r
-              return (EFI_OUT_OF_RESOURCES);\r
-            }\r
-            AsciiStrCpy(Lang, CompName2->SupportedLanguages);\r
-            TempChar = AsciiStrStr(Lang, ";");\r
-            if (TempChar != NULL){\r
-              *TempChar = CHAR_NULL;\r
-            }\r
-          } else {\r
-            Lang = AllocateZeroPool(AsciiStrSize(Language));\r
-            if (Lang == NULL) {\r
-              return (EFI_OUT_OF_RESOURCES);\r
-            }\r
-            AsciiStrCpy(Lang, Language);\r
-          }\r
+          Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);\r
           Status = CompName2->GetControllerName(CompName2, ParentControllerBuffer[LoopVar], DeviceHandle, Lang, &DeviceNameToReturn);\r
           FreePool(Lang);\r
           Lang = NULL;\r
@@ -816,28 +753,19 @@ EfiShellGetDeviceName(
     }\r
   }\r
   if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) {\r
-    Status = gBS->LocateProtocol(\r
-      &gEfiDevicePathToTextProtocolGuid,\r
+    Status = gBS->OpenProtocol(\r
+      DeviceHandle,\r
+      &gEfiDevicePathProtocolGuid,\r
+      (VOID**)&DevicePath,\r
+      gImageHandle,\r
       NULL,\r
-      (VOID**)&DevicePathToText);\r
-    //\r
-    // we now have the device path to text protocol\r
-    //\r
+      EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
     if (!EFI_ERROR(Status)) {\r
-      Status = gBS->OpenProtocol(\r
-        DeviceHandle,\r
-        &gEfiDevicePathProtocolGuid,\r
-        (VOID**)&DevicePath,\r
-        gImageHandle,\r
-        NULL,\r
-        EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
-      if (!EFI_ERROR(Status)) {\r
-        //\r
-        // use device path to text on the device path\r
-        //\r
-        *BestDeviceName = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
-        return (EFI_SUCCESS);\r
-      }\r
+      //\r
+      // use device path to text on the device path\r
+      //\r
+      *BestDeviceName = ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
+      return (EFI_SUCCESS);\r
     }\r
   }\r
   //\r
@@ -859,7 +787,8 @@ EfiShellGetDeviceName(
   @retval EFI_NOT_FOUND         EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory\r
                                 could not be opened.\r
   @retval EFI_VOLUME_CORRUPTED  The data structures in the volume were corrupted.\r
-  @retval EFI_DEVICE_ERROR      The device had an error\r
+  @retval EFI_DEVICE_ERROR      The device had an error.\r
+  @retval Others                Error status returned from EFI_SIMPLE_FILE_SYSTEM_PROTOCOL->OpenVolume().\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -899,8 +828,12 @@ EfiShellOpenRootByHandle(
   // Open the root volume now...\r
   //\r
   Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &RealFileHandle);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
   *FileHandle = ConvertEfiFileProtocolToShellHandle(RealFileHandle, EfiShellGetMapFromDevicePath(&DevPath));\r
-  return (Status);\r
+  return (EFI_SUCCESS);\r
 }\r
 \r
 /**\r
@@ -981,7 +914,6 @@ EfiShellBatchIsActive (
   @retval other                   an error ocurred.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 InternalOpenFileDevicePath(\r
   IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
   OUT SHELL_FILE_HANDLE           *FileHandle,\r
@@ -995,7 +927,6 @@ InternalOpenFileDevicePath(
   SHELL_FILE_HANDLE               ShellHandle;\r
   EFI_FILE_PROTOCOL               *Handle1;\r
   EFI_FILE_PROTOCOL               *Handle2;\r
-  EFI_DEVICE_PATH_PROTOCOL        *DpCopy;\r
   FILEPATH_DEVICE_PATH            *AlignedNode;\r
 \r
   if (FileHandle == NULL) {\r
@@ -1005,7 +936,6 @@ InternalOpenFileDevicePath(
   Handle1       = NULL;\r
   Handle2       = NULL;\r
   Handle        = NULL;\r
-  DpCopy        = DevicePath;\r
   ShellHandle   = NULL;\r
   FilePathNode  = NULL;\r
   AlignedNode   = NULL;\r
@@ -1165,13 +1095,18 @@ EfiShellCreateFile(
 {\r
   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
   EFI_STATUS                Status;\r
+  BOOLEAN                   Volatile;\r
 \r
   //\r
   // Is this for an environment variable\r
   // do we start with >v\r
   //\r
   if (StrStr(FileName, L">v") == FileName) {\r
-    if (!IsVolatileEnv(FileName+2)) {\r
+    Status = IsVolatileEnv (FileName + 2, &Volatile);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    if (!Volatile) {\r
       return (EFI_INVALID_PARAMETER);\r
     }\r
     *FileHandle = CreateFileInterfaceEnv(FileName+2);\r
@@ -1186,12 +1121,39 @@ EfiShellCreateFile(
     return (EFI_NOT_FOUND);\r
   }\r
 \r
-  Status = InternalOpenFileDevicePath(DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs); // 0 = no specific file attributes\r
+  Status = InternalOpenFileDevicePath(DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs);\r
   FreePool(DevicePath);\r
 \r
   return(Status);\r
 }\r
 \r
+/**\r
+  Register a GUID and a localized human readable name for it.\r
+\r
+  If Guid is not assigned a name, then assign GuidName to Guid.  This list of GUID\r
+  names must be used whenever a shell command outputs GUID information.\r
+\r
+  This function is only available when the major and minor versions in the\r
+  EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
+\r
+  @param[in] Guid       A pointer to the GUID being registered.\r
+  @param[in] GuidName   A pointer to the localized name for the GUID being registered.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_INVALID_PARAMETER   Guid was NULL.\r
+  @retval EFI_INVALID_PARAMETER   GuidName was NULL.\r
+  @retval EFI_ACCESS_DENIED       Guid already is assigned a name.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellRegisterGuidName(\r
+  IN CONST EFI_GUID *Guid,\r
+  IN CONST CHAR16   *GuidName\r
+  )\r
+{\r
+  return (AddNewGuidNameMapping(Guid, GuidName, NULL));\r
+}\r
+\r
 /**\r
   Opens a file or a directory by file name.\r
 \r
@@ -1254,6 +1216,7 @@ EfiShellOpenFileByName(
 {\r
   EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
   EFI_STATUS                      Status;\r
+  BOOLEAN                         Volatile;\r
 \r
   *FileHandle = NULL;\r
 \r
@@ -1287,9 +1250,10 @@ EfiShellOpenFileByName(
   }\r
 \r
   //\r
-  // Is this for NUL file\r
+  // Is this for NUL / NULL file\r
   //\r
-  if (StrCmp(FileName, L"NUL") == 0) {\r
+  if ((gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16*)FileName, L"NUL") == 0) ||\r
+      (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16*)FileName, L"NULL") == 0)) {\r
     *FileHandle = &FileInterfaceNulFile;\r
     return (EFI_SUCCESS);\r
   }\r
@@ -1313,7 +1277,11 @@ EfiShellOpenFileByName(
   // do we start with >v\r
   //\r
   if (StrStr(FileName, L">v") == FileName) {\r
-    if (!IsVolatileEnv(FileName+2) &&\r
+    Status = IsVolatileEnv (FileName + 2, &Volatile);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    if (!Volatile &&\r
         ((OpenMode & EFI_FILE_MODE_WRITE) != 0)) {\r
       return (EFI_INVALID_PARAMETER);\r
     }\r
@@ -1325,7 +1293,7 @@ EfiShellOpenFileByName(
   // We are opening a regular file.\r
   //\r
   DevicePath = EfiShellGetDevicePathFromFilePath(FileName);\r
-//  DEBUG_CODE(InternalShellProtocolDebugPrintMessage (NULL, DevicePath););\r
+\r
   if (DevicePath == NULL) {\r
     return (EFI_NOT_FOUND);\r
   }\r
@@ -1359,6 +1327,8 @@ EfiShellDeleteFileByName(
   SHELL_FILE_HANDLE FileHandle;\r
   EFI_STATUS        Status;\r
 \r
+  FileHandle = NULL;\r
+\r
   //\r
   // get a handle to the file\r
   //\r
@@ -1371,6 +1341,7 @@ EfiShellDeleteFileByName(
   //\r
   // now delete the file\r
   //\r
+  ShellFileHandleRemove(FileHandle);\r
   return (ShellInfoObject.NewEfiShellProtocol->DeleteFile(FileHandle));\r
 }\r
 \r
@@ -1401,17 +1372,18 @@ EfiShellEnablePageBreak (
 /**\r
   internal worker function to load and run an image via device path.\r
 \r
-  @param ParentImageHandle  A handle of the image that is executing the specified\r
-                            command line.\r
-  @param DevicePath         device path of the file to execute\r
-  @param CommandLine        Points to the NULL-terminated UCS-2 encoded string\r
-                            containing the command line. If NULL then the command-\r
-                            line will be empty.\r
-  @param Environment        Points to a NULL-terminated array of environment\r
-                            variables with the format 'x=y', where x is the\r
-                            environment variable name and y is the value. If this\r
-                            is NULL, then the current shell environment is used.\r
-  @param StatusCode         Points to the status code returned by the command.\r
+  @param ParentImageHandle      A handle of the image that is executing the specified\r
+                                command line.\r
+  @param DevicePath             device path of the file to execute\r
+  @param CommandLine            Points to the NULL-terminated UCS-2 encoded string\r
+                                containing the command line. If NULL then the command-\r
+                                line will be empty.\r
+  @param Environment            Points to a NULL-terminated array of environment\r
+                                variables with the format 'x=y', where x is the\r
+                                environment variable name and y is the value. If this\r
+                                is NULL, then the current shell environment is used.\r
+\r
+  @param[out] StartImageStatus  Returned status from gBS->StartImage.\r
 \r
   @retval EFI_SUCCESS       The command executed successfully. The  status code\r
                             returned by the command is pointed to by StatusCode.\r
@@ -1420,29 +1392,46 @@ EfiShellEnablePageBreak (
   @retval EFI_UNSUPPORTED   Nested shell invocations are not allowed.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 InternalShellExecuteDevicePath(\r
   IN CONST EFI_HANDLE               *ParentImageHandle,\r
   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
   IN CONST CHAR16                   *CommandLine OPTIONAL,\r
   IN CONST CHAR16                   **Environment OPTIONAL,\r
-  OUT EFI_STATUS                    *StatusCode OPTIONAL\r
+  OUT EFI_STATUS                    *StartImageStatus OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
+  EFI_STATUS                    StartStatus;\r
+  EFI_STATUS                    CleanupStatus;\r
   EFI_HANDLE                    NewHandle;\r
   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;\r
   LIST_ENTRY                    OrigEnvs;\r
   EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;\r
+  CHAR16                        *ImagePath;\r
+  UINTN                         Index;\r
+  CHAR16                        *Walker;\r
+  CHAR16                        *NewCmdLine;\r
 \r
   if (ParentImageHandle == NULL) {\r
     return (EFI_INVALID_PARAMETER);\r
   }\r
 \r
   InitializeListHead(&OrigEnvs);\r
+  ZeroMem(&ShellParamsProtocol, sizeof(EFI_SHELL_PARAMETERS_PROTOCOL));\r
 \r
   NewHandle = NULL;\r
 \r
+  NewCmdLine = AllocateCopyPool (StrSize (CommandLine), CommandLine);\r
+  if (NewCmdLine == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {\r
+    if (*Walker == L'^' && *(Walker+1) == L'#') {\r
+      CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));\r
+    }\r
+  }\r
+\r
   //\r
   // Load the image with:\r
   // FALSE - not from boot manager and NULL, 0 being not already in memory\r
@@ -1459,6 +1448,7 @@ InternalShellExecuteDevicePath(
     if (NewHandle != NULL) {\r
       gBS->UnloadImage(NewHandle);\r
     }\r
+    FreePool (NewCmdLine);\r
     return (Status);\r
   }\r
   Status = gBS->OpenProtocol(\r
@@ -1470,10 +1460,24 @@ InternalShellExecuteDevicePath(
     EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
 \r
   if (!EFI_ERROR(Status)) {\r
+    //\r
+    // If the image is not an app abort it.\r
+    //\r
+    if (LoadedImage->ImageCodeType != EfiLoaderCode){\r
+      ShellPrintHiiEx(\r
+        -1,\r
+        -1,\r
+        NULL,\r
+        STRING_TOKEN (STR_SHELL_IMAGE_NOT_APP),\r
+        ShellInfoObject.HiiHandle\r
+      );\r
+      goto UnloadImage;\r
+    }\r
+\r
     ASSERT(LoadedImage->LoadOptionsSize == 0);\r
-    if (CommandLine != NULL) {\r
-      LoadedImage->LoadOptionsSize  = (UINT32)StrSize(CommandLine);\r
-      LoadedImage->LoadOptions      = (VOID*)CommandLine;\r
+    if (NewCmdLine != NULL) {\r
+      LoadedImage->LoadOptionsSize  = (UINT32)StrSize(NewCmdLine);\r
+      LoadedImage->LoadOptions      = (VOID*)NewCmdLine;\r
     }\r
 \r
     //\r
@@ -1492,8 +1496,35 @@ InternalShellExecuteDevicePath(
     ShellParamsProtocol.StdIn   = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
     ShellParamsProtocol.StdOut  = ShellInfoObject.NewShellParametersProtocol->StdOut;\r
     ShellParamsProtocol.StdErr  = ShellInfoObject.NewShellParametersProtocol->StdErr;\r
-    Status = UpdateArgcArgv(&ShellParamsProtocol, CommandLine, NULL, NULL);\r
+    Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, Efi_Application, NULL, NULL);\r
     ASSERT_EFI_ERROR(Status);\r
+    //\r
+    // Replace Argv[0] with the full path of the binary we're executing:\r
+    // If the command line was "foo", the binary might be called "foo.efi".\r
+    // "The first entry in [Argv] is always the full file path of the\r
+    //  executable" - UEFI Shell Spec section 2.3\r
+    //\r
+    ImagePath = EfiShellGetFilePathFromDevicePath (DevicePath);\r
+    // The image we're executing isn't necessarily in a filesystem - it might\r
+    // be memory mapped. In this case EfiShellGetFilePathFromDevicePath will\r
+    // return NULL, and we'll leave Argv[0] as UpdateArgcArgv set it.\r
+    if (ImagePath != NULL) {\r
+      if (ShellParamsProtocol.Argv == NULL) {\r
+        // Command line was empty or null.\r
+        // (UpdateArgcArgv sets Argv to NULL when CommandLine is "" or NULL)\r
+        ShellParamsProtocol.Argv = AllocatePool (sizeof (CHAR16 *));\r
+        if (ShellParamsProtocol.Argv == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          goto UnloadImage;\r
+        }\r
+        ShellParamsProtocol.Argc = 1;\r
+      } else {\r
+        // Free the string UpdateArgcArgv put in Argv[0];\r
+        FreePool (ShellParamsProtocol.Argv[0]);\r
+      }\r
+      ShellParamsProtocol.Argv[0] = ImagePath;\r
+    }\r
+\r
     Status = gBS->InstallProtocolInterface(&NewHandle, &gEfiShellParametersProtocolGuid, EFI_NATIVE_INTERFACE, &ShellParamsProtocol);\r
     ASSERT_EFI_ERROR(Status);\r
 \r
@@ -1503,34 +1534,153 @@ InternalShellExecuteDevicePath(
     // now start the image and if the caller wanted the return code pass it to them...\r
     //\r
     if (!EFI_ERROR(Status)) {\r
-      if (StatusCode != NULL) {\r
-        *StatusCode = gBS->StartImage(NewHandle, NULL, NULL);\r
-      } else {\r
-        Status      = gBS->StartImage(NewHandle, NULL, NULL);\r
+      StartStatus      = gBS->StartImage(\r
+                          NewHandle,\r
+                          0,\r
+                          NULL\r
+                          );\r
+      if (StartImageStatus != NULL) {\r
+        *StartImageStatus = StartStatus;\r
       }\r
+\r
+      CleanupStatus = gBS->UninstallProtocolInterface(\r
+                            NewHandle,\r
+                            &gEfiShellParametersProtocolGuid,\r
+                            &ShellParamsProtocol\r
+                            );\r
+      ASSERT_EFI_ERROR(CleanupStatus);\r
+\r
+      goto FreeAlloc;\r
     }\r
 \r
-    //\r
-    // Cleanup (and dont overwrite errors)\r
-    //\r
-    if (EFI_ERROR(Status)) {\r
-      gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
-    } else {\r
-      Status = gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
-      ASSERT_EFI_ERROR(Status);\r
+UnloadImage:\r
+    // Unload image - We should only get here if we didn't call StartImage\r
+    gBS->UnloadImage (NewHandle);\r
+\r
+FreeAlloc:\r
+    // Free Argv (Allocated in UpdateArgcArgv)\r
+    if (ShellParamsProtocol.Argv != NULL) {\r
+      for (Index = 0; Index < ShellParamsProtocol.Argc; Index++) {\r
+        if (ShellParamsProtocol.Argv[Index] != NULL) {\r
+          FreePool (ShellParamsProtocol.Argv[Index]);\r
+        }\r
+      }\r
+      FreePool (ShellParamsProtocol.Argv);\r
     }\r
   }\r
 \r
+  // Restore environment variables\r
   if (!IsListEmpty(&OrigEnvs)) {\r
-    if (EFI_ERROR(Status)) {\r
-      SetEnvironmentVariableList(&OrigEnvs);\r
+    CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
+    ASSERT_EFI_ERROR (CleanupStatus);\r
+  }\r
+\r
+  FreePool (NewCmdLine);\r
+\r
+  return(Status);\r
+}\r
+\r
+/**\r
+  internal worker function to load and run an image in the current shell.\r
+\r
+  @param CommandLine            Points to the NULL-terminated UCS-2 encoded string\r
+                                containing the command line. If NULL then the command-\r
+                                line will be empty.\r
+  @param Environment            Points to a NULL-terminated array of environment\r
+                                variables with the format 'x=y', where x is the\r
+                                environment variable name and y is the value. If this\r
+                                is NULL, then the current shell environment is used.\r
+\r
+  @param[out] StartImageStatus  Returned status from the command line.\r
+\r
+  @retval EFI_SUCCESS       The command executed successfully. The  status code\r
+                            returned by the command is pointed to by StatusCode.\r
+  @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES Out of resources.\r
+  @retval EFI_UNSUPPORTED   Nested shell invocations are not allowed.\r
+**/\r
+EFI_STATUS\r
+InternalShellExecute(\r
+  IN CONST CHAR16                   *CommandLine OPTIONAL,\r
+  IN CONST CHAR16                   **Environment OPTIONAL,\r
+  OUT EFI_STATUS                    *StartImageStatus OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_STATUS                    CleanupStatus;\r
+  LIST_ENTRY                    OrigEnvs;\r
+\r
+  InitializeListHead(&OrigEnvs);\r
+\r
+  //\r
+  // Save our current environment settings for later restoration if necessary\r
+  //\r
+  if (Environment != NULL) {\r
+    Status = GetEnvironmentVariableList(&OrigEnvs);\r
+    if (!EFI_ERROR(Status)) {\r
+      Status = SetEnvironmentVariables(Environment);\r
     } else {\r
-      Status = SetEnvironmentVariableList(&OrigEnvs);\r
+      return Status;\r
     }\r
   }\r
 \r
+  Status = RunShellCommand(CommandLine, StartImageStatus);\r
+\r
+  // Restore environment variables\r
+  if (!IsListEmpty(&OrigEnvs)) {\r
+    CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
+    ASSERT_EFI_ERROR (CleanupStatus);\r
+  }\r
+\r
   return(Status);\r
 }\r
+\r
+/**\r
+  Determine if the UEFI Shell is currently running with nesting enabled or disabled.\r
+\r
+  @retval FALSE   nesting is required\r
+  @retval other   nesting is enabled\r
+**/\r
+STATIC\r
+BOOLEAN\r
+NestingEnabled(\r
+  VOID\r
+)\r
+{\r
+  EFI_STATUS  Status;\r
+  CHAR16      *Temp;\r
+  CHAR16      *Temp2;\r
+  UINTN       TempSize;\r
+  BOOLEAN     RetVal;\r
+\r
+  RetVal = TRUE;\r
+  Temp   = NULL;\r
+  Temp2  = NULL;\r
+\r
+  if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) {\r
+    TempSize = 0;\r
+    Temp     = NULL;\r
+    Status = SHELL_GET_ENVIRONMENT_VARIABLE(mNoNestingEnvVarName, &TempSize, Temp);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      Temp = AllocateZeroPool(TempSize + sizeof(CHAR16));\r
+      if (Temp != NULL) {\r
+        Status = SHELL_GET_ENVIRONMENT_VARIABLE(mNoNestingEnvVarName, &TempSize, Temp);\r
+      }\r
+    }\r
+    Temp2 = StrnCatGrow(&Temp2, NULL, mNoNestingTrue, 0);\r
+    if (Temp != NULL && Temp2 != NULL && StringNoCaseCompare(&Temp, &Temp2) == 0) {\r
+      //\r
+      // Use the no nesting method.\r
+      //\r
+      RetVal = FALSE;\r
+    }\r
+  }\r
+\r
+  SHELL_FREE_NON_NULL(Temp);\r
+  SHELL_FREE_NON_NULL(Temp2);\r
+  return (RetVal);\r
+}\r
+\r
 /**\r
   Execute the command line.\r
 \r
@@ -1554,7 +1704,7 @@ InternalShellExecuteDevicePath(
                             variables with the format 'x=y', where x is the\r
                             environment variable name and y is the value. If this\r
                             is NULL, then the current shell environment is used.\r
-  @param StatusCode         Points to the status code returned by the command.\r
+  @param StatusCode         Points to the status code returned by the CommandLine.\r
 \r
   @retval EFI_SUCCESS       The command executed successfully. The  status code\r
                             returned by the command is pointed to by StatusCode.\r
@@ -1583,35 +1733,43 @@ EfiShellExecute(
     return (EFI_UNSUPPORTED);\r
   }\r
 \r
-  DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
+  if (NestingEnabled()) {\r
+    DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
 \r
-  DEBUG_CODE_BEGIN();\r
-  Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
-  FreePool(Temp);\r
-  Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
-  FreePool(Temp);\r
-  Temp = gDevPathToText->ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
-  FreePool(Temp);\r
-  DEBUG_CODE_END();\r
+    DEBUG_CODE_BEGIN();\r
+    Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
+    FreePool(Temp);\r
+    Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
+    FreePool(Temp);\r
+    Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
+    FreePool(Temp);\r
+    DEBUG_CODE_END();\r
 \r
-  Temp = NULL;\r
-  Size = 0;\r
-  ASSERT((Temp == NULL && Size == 0) || (Temp != NULL));\r
-  StrnCatGrow(&Temp, &Size, L"Shell.efi ", 0);\r
-  StrnCatGrow(&Temp, &Size, CommandLine, 0);\r
+    Temp = NULL;\r
+    Size = 0;\r
+    ASSERT((Temp == NULL && Size == 0) || (Temp != NULL));\r
+    StrnCatGrow(&Temp, &Size, L"Shell.efi -exit ", 0);\r
+    StrnCatGrow(&Temp, &Size, CommandLine, 0);\r
 \r
-  Status = InternalShellExecuteDevicePath(\r
-    ParentImageHandle,\r
-    DevPath,\r
-    Temp,\r
-    (CONST CHAR16**)Environment,\r
-    StatusCode);\r
+    Status = InternalShellExecuteDevicePath(\r
+      ParentImageHandle,\r
+      DevPath,\r
+      Temp,\r
+      (CONST CHAR16**)Environment,\r
+      StatusCode);\r
+\r
+    //\r
+    // de-allocate and return\r
+    //\r
+    FreePool(DevPath);\r
+    FreePool(Temp);\r
+  } else {\r
+    Status = InternalShellExecute(\r
+      (CONST CHAR16*)CommandLine,\r
+      (CONST CHAR16**)Environment,\r
+      StatusCode);\r
+  }\r
 \r
-  //\r
-  // de-allocate and return\r
-  //\r
-  FreePool(DevPath);\r
-  FreePool(Temp);\r
   return(Status);\r
 }\r
 \r
@@ -1624,7 +1782,6 @@ EfiShellExecute(
   @param FileListNode     pointer to the list node to free\r
 **/\r
 VOID\r
-EFIAPI\r
 InternalFreeShellFileInfoNode(\r
   IN EFI_SHELL_FILE_INFO *FileListNode\r
   )\r
@@ -1674,6 +1831,8 @@ EfiShellFreeFileList(
     RemoveEntryList(&ShellFileListItem->Link);\r
     InternalFreeShellFileInfoNode(ShellFileListItem);\r
   }\r
+  InternalFreeShellFileInfoNode(*FileList);\r
+  *FileList = NULL;\r
   return(EFI_SUCCESS);\r
 }\r
 \r
@@ -1695,6 +1854,7 @@ EfiShellRemoveDupInFileList(
 {\r
   EFI_SHELL_FILE_INFO *ShellFileListItem;\r
   EFI_SHELL_FILE_INFO *ShellFileListItem2;\r
+  EFI_SHELL_FILE_INFO *TempNode;\r
 \r
   if (FileList == NULL || *FileList == NULL) {\r
     return (EFI_INVALID_PARAMETER);\r
@@ -1712,13 +1872,33 @@ EfiShellRemoveDupInFileList(
             (CHAR16*)ShellFileListItem->FullName,\r
             (CHAR16*)ShellFileListItem2->FullName) == 0\r
          ){\r
+        TempNode = (EFI_SHELL_FILE_INFO *)GetPreviousNode(\r
+                                            &(*FileList)->Link,\r
+                                            &ShellFileListItem2->Link\r
+                                            );\r
         RemoveEntryList(&ShellFileListItem2->Link);\r
         InternalFreeShellFileInfoNode(ShellFileListItem2);\r
+        // Set ShellFileListItem2 to PreviousNode so we don't access Freed\r
+        // memory in GetNextNode in the loop expression above.\r
+        ShellFileListItem2 = TempNode;\r
       }\r
     }\r
   }\r
   return (EFI_SUCCESS);\r
 }\r
+\r
+//\r
+// This is the same structure as the external version, but it has no CONST qualifiers.\r
+//\r
+typedef struct {\r
+  LIST_ENTRY        Link;       ///< Linked list members.\r
+  EFI_STATUS        Status;     ///< Status of opening the file.  Valid only if Handle != NULL.\r
+        CHAR16      *FullName;  ///< Fully qualified filename.\r
+        CHAR16      *FileName;  ///< name of this file.\r
+  SHELL_FILE_HANDLE Handle;     ///< Handle for interacting with the opened file or NULL if closed.\r
+  EFI_FILE_INFO     *Info;      ///< Pointer to the FileInfo struct for this file or NULL.\r
+} EFI_SHELL_FILE_INFO_NO_CONST;\r
+\r
 /**\r
   Allocates and duplicates a EFI_SHELL_FILE_INFO node.\r
 \r
@@ -1729,26 +1909,33 @@ EfiShellRemoveDupInFileList(
   @return != NULL     a pointer to the new node\r
 **/\r
 EFI_SHELL_FILE_INFO*\r
-EFIAPI\r
 InternalDuplicateShellFileInfo(\r
   IN       EFI_SHELL_FILE_INFO *Node,\r
   IN BOOLEAN                   Save\r
   )\r
 {\r
-  EFI_SHELL_FILE_INFO *NewNode;\r
+  EFI_SHELL_FILE_INFO_NO_CONST *NewNode;\r
+\r
+  //\r
+  // try to confirm that the objects are in sync\r
+  //\r
+  ASSERT(sizeof(EFI_SHELL_FILE_INFO_NO_CONST) == sizeof(EFI_SHELL_FILE_INFO));\r
 \r
   NewNode = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
   if (NewNode == NULL) {\r
     return (NULL);\r
   }\r
-  NewNode->FullName = AllocateZeroPool(StrSize(Node->FullName));\r
-\r
-  NewNode->FileName = AllocateZeroPool(StrSize(Node->FileName));\r
-  NewNode->Info     = AllocateZeroPool((UINTN)Node->Info->Size);\r
+  NewNode->FullName = AllocateCopyPool(StrSize(Node->FullName), Node->FullName);\r
+  NewNode->FileName = AllocateCopyPool(StrSize(Node->FileName), Node->FileName);\r
+  NewNode->Info     = AllocateCopyPool((UINTN)Node->Info->Size, Node->Info);\r
   if ( NewNode->FullName == NULL\r
     || NewNode->FileName == NULL\r
     || NewNode->Info == NULL\r
-   ){\r
+  ){\r
+    SHELL_FREE_NON_NULL(NewNode->FullName);\r
+    SHELL_FREE_NON_NULL(NewNode->FileName);\r
+    SHELL_FREE_NON_NULL(NewNode->Info);\r
+    SHELL_FREE_NON_NULL(NewNode);\r
     return(NULL);\r
   }\r
   NewNode->Status = Node->Status;\r
@@ -1756,11 +1943,8 @@ InternalDuplicateShellFileInfo(
   if (!Save) {\r
     Node->Handle = NULL;\r
   }\r
-  StrCpy((CHAR16*)NewNode->FullName, Node->FullName);\r
-  StrCpy((CHAR16*)NewNode->FileName, Node->FileName);\r
-  CopyMem(NewNode->Info, Node->Info, (UINTN)Node->Info->Size);\r
 \r
-  return(NewNode);\r
+  return((EFI_SHELL_FILE_INFO*)NewNode);\r
 }\r
 \r
 /**\r
@@ -1769,7 +1953,6 @@ InternalDuplicateShellFileInfo(
 \r
   @param[in] BasePath         the Path to prepend onto filename for FullPath\r
   @param[in] Status           Status member initial value.\r
-  @param[in] FullName         FullName member initial value.\r
   @param[in] FileName         FileName member initial value.\r
   @param[in] Handle           Handle member initial value.\r
   @param[in] Info             Info struct to copy.\r
@@ -1778,11 +1961,9 @@ InternalDuplicateShellFileInfo(
   @return                     a pointer to the newly allocated structure.\r
 **/\r
 EFI_SHELL_FILE_INFO *\r
-EFIAPI\r
 CreateAndPopulateShellFileInfo(\r
   IN CONST CHAR16 *BasePath,\r
   IN CONST EFI_STATUS Status,\r
-  IN CONST CHAR16 *FullName,\r
   IN CONST CHAR16 *FileName,\r
   IN CONST SHELL_FILE_HANDLE Handle,\r
   IN CONST EFI_FILE_INFO *Info\r
@@ -1827,7 +2008,7 @@ CreateAndPopulateShellFileInfo(
     TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
     if (TempString == NULL) {\r
       FreePool((VOID*)ShellFileListItem->FileName);\r
-      FreePool(ShellFileListItem->Info);\r
+      SHELL_FREE_NON_NULL(ShellFileListItem->Info);\r
       FreePool(ShellFileListItem);\r
       return (NULL);\r
     }\r
@@ -1843,6 +2024,8 @@ CreateAndPopulateShellFileInfo(
     }\r
   }\r
 \r
+  TempString = PathCleanUpDirectories(TempString);\r
+\r
   ShellFileListItem->FullName = TempString;\r
   ShellFileListItem->Status   = Status;\r
   ShellFileListItem->Handle   = Handle;\r
@@ -1881,6 +2064,7 @@ EfiShellFindFilesInDir(
   UINTN                     Size;\r
   CHAR16                    *TempSpot;\r
 \r
+  BasePath = NULL;\r
   Status = FileHandleGetFileName(FileDirHandle, &BasePath);\r
   if (EFI_ERROR(Status)) {\r
     return (Status);\r
@@ -1891,6 +2075,7 @@ EfiShellFindFilesInDir(
     Size              = 0;\r
     TempString        = StrnCatGrow(&TempString, &Size, ShellFileHandleGetPath(FileDirHandle), 0);\r
     if (TempString == NULL) {\r
+      SHELL_FREE_NON_NULL(BasePath);\r
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
     TempSpot          = StrStr(TempString, L";");\r
@@ -1901,8 +2086,10 @@ EfiShellFindFilesInDir(
 \r
     TempString        = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
     if (TempString == NULL) {\r
+      SHELL_FREE_NON_NULL(BasePath);\r
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
+    SHELL_FREE_NON_NULL(BasePath);\r
     BasePath          = TempString;\r
   }\r
 \r
@@ -1917,26 +2104,29 @@ EfiShellFindFilesInDir(
       ; !EFI_ERROR(Status) && !NoFile\r
       ; Status = FileHandleFindNextFile(FileDirHandle, FileInfo, &NoFile)\r
      ){\r
-    TempString  = NULL;\r
-    Size        = 0;\r
+    if (ShellFileList == NULL) {\r
+      ShellFileList = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
+      if (ShellFileList == NULL) {\r
+        SHELL_FREE_NON_NULL (BasePath);\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      InitializeListHead(&ShellFileList->Link);\r
+    }\r
     //\r
     // allocate a new EFI_SHELL_FILE_INFO and populate it...\r
     //\r
-    ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
-    TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
-    TempString = StrnCatGrow(&TempString, &Size, FileInfo->FileName, 0);\r
     ShellFileListItem = CreateAndPopulateShellFileInfo(\r
       BasePath,\r
-      EFI_SUCCESS, // success since we didnt fail to open it...\r
-      TempString,\r
+      EFI_SUCCESS,  // success since we didnt fail to open it...\r
       FileInfo->FileName,\r
-      NULL, // no handle since not open\r
+      NULL,         // no handle since not open\r
       FileInfo);\r
-\r
-    if (ShellFileList == NULL) {\r
-      ShellFileList = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
-      ASSERT(ShellFileList != NULL);\r
-      InitializeListHead(&ShellFileList->Link);\r
+    if (ShellFileListItem == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      //\r
+      // Free resources outside the loop.\r
+      //\r
+      break;\r
     }\r
     InsertTailList(&ShellFileList->Link, &ShellFileListItem->Link);\r
   }\r
@@ -1951,53 +2141,88 @@ EfiShellFindFilesInDir(
 }\r
 \r
 /**\r
-  Updates a file name to be preceeded by the mapped drive name\r
+  Get the GUID value from a human readable name.\r
+\r
+  If GuidName is a known GUID name, then update Guid to have the correct value for\r
+  that GUID.\r
 \r
-  @param[in] BasePath      the Mapped drive name to prepend\r
-  @param[in, out] Path     pointer to pointer to the file name to update.\r
+  This function is only available when the major and minor versions in the\r
+  EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
 \r
-  @retval EFI_SUCCESS\r
-  @retval EFI_OUT_OF_RESOURCES\r
+  @param[in]  GuidName   A pointer to the localized name for the GUID being queried.\r
+  @param[out] Guid       A pointer to the GUID structure to be filled in.\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_INVALID_PARAMETER   Guid was NULL.\r
+  @retval EFI_INVALID_PARAMETER   GuidName was NULL.\r
+  @retval EFI_NOT_FOUND           GuidName is not a known GUID Name.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-UpdateFileName(\r
-  IN CONST CHAR16 *BasePath,\r
-  IN OUT CHAR16   **Path\r
+EfiShellGetGuidFromName(\r
+  IN  CONST CHAR16   *GuidName,\r
+  OUT       EFI_GUID *Guid\r
   )\r
 {\r
-  CHAR16              *Path2;\r
-  UINTN               Path2Size;\r
+  EFI_GUID    *NewGuid;\r
+  EFI_STATUS  Status;\r
 \r
-  Path2Size = 0;\r
-  Path2 = NULL;\r
+  if (Guid == NULL || GuidName == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
 \r
-  ASSERT(Path      != NULL);\r
-  ASSERT(*Path     != NULL);\r
-  ASSERT(BasePath  != NULL);\r
+  Status = GetGuidFromStringName(GuidName, NULL, &NewGuid);\r
 \r
-  //\r
-  // convert a local path to an absolute path\r
-  //\r
-  if (StrStr(*Path, L":") == NULL) {\r
-    ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
-    StrnCatGrow(&Path2, &Path2Size, BasePath, 0);\r
-    if (Path2 == NULL) {\r
-      return (EFI_OUT_OF_RESOURCES);\r
-    }\r
-    ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
-    StrnCatGrow(&Path2, &Path2Size, (*Path)[0] == L'\\'?(*Path) + 1 :*Path, 0);\r
-    if (Path2 == NULL) {\r
-      return (EFI_OUT_OF_RESOURCES);\r
-    }\r
+  if (!EFI_ERROR(Status)) {\r
+    CopyGuid(Guid, NewGuid);\r
   }\r
 \r
-  FreePool(*Path);\r
-  (*Path) = Path2;\r
+  return (Status);\r
+}\r
+\r
+/**\r
+  Get the human readable name for a GUID from the value.\r
+\r
+  If Guid is assigned a name, then update *GuidName to point to the name. The callee\r
+  should not modify the value.\r
+\r
+  This function is only available when the major and minor versions in the\r
+  EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
+\r
+  @param[in]  Guid       A pointer to the GUID being queried.\r
+  @param[out] GuidName   A pointer to a pointer the localized to name for the GUID being requested\r
+\r
+  @retval EFI_SUCCESS             The operation was successful.\r
+  @retval EFI_INVALID_PARAMETER   Guid was NULL.\r
+  @retval EFI_INVALID_PARAMETER   GuidName was NULL.\r
+  @retval EFI_NOT_FOUND           Guid is not assigned a name.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellGetGuidName(\r
+  IN  CONST EFI_GUID *Guid,\r
+  OUT CONST CHAR16   **GuidName\r
+  )\r
+{\r
+  CHAR16   *Name;\r
+\r
+  if (Guid == NULL || GuidName == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  Name = GetStringNameFromGuid(Guid, NULL);\r
+  if (Name == NULL || StrLen(Name) == 0) {\r
+    SHELL_FREE_NON_NULL(Name);\r
+    return (EFI_NOT_FOUND);\r
+  }\r
+\r
+  *GuidName = AddBufferToFreeList(Name);\r
 \r
   return (EFI_SUCCESS);\r
 }\r
 \r
+\r
+\r
 /**\r
   If FileHandle is a directory then the function reads from FileHandle and reads in\r
   each of the FileInfo structures.  If one of them matches the Pattern's first\r
@@ -2021,7 +2246,6 @@ UpdateFileName(
   @retval EFI_OUT_OF_RESOURCES  a memory allocation failed\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ShellSearchHandle(\r
   IN     CONST CHAR16                         *FilePattern,\r
   IN           EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation,\r
@@ -2037,6 +2261,7 @@ ShellSearchHandle(
   EFI_SHELL_FILE_INFO *ShellInfo;\r
   EFI_SHELL_FILE_INFO *ShellInfoNode;\r
   EFI_SHELL_FILE_INFO *NewShellNode;\r
+  EFI_FILE_INFO       *FileInfo;\r
   BOOLEAN             Directory;\r
   CHAR16              *NewFullName;\r
   UINTN               Size;\r
@@ -2059,35 +2284,52 @@ ShellSearchHandle(
      ; NextFilePatternStart++);\r
 \r
   CurrentFilePattern = AllocateZeroPool((NextFilePatternStart-FilePattern+1)*sizeof(CHAR16));\r
-  ASSERT(CurrentFilePattern != NULL);\r
-  StrnCpy(CurrentFilePattern, FilePattern, NextFilePatternStart-FilePattern);\r
+  if (CurrentFilePattern == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  StrnCpyS(CurrentFilePattern, NextFilePatternStart-FilePattern+1, FilePattern, NextFilePatternStart-FilePattern);\r
 \r
   if (CurrentFilePattern[0]   == CHAR_NULL\r
     &&NextFilePatternStart[0] == CHAR_NULL\r
-   ){\r
+    ){\r
     //\r
-    // Add the current parameter FileHandle to the list, then end...\r
+    // we want the parent or root node (if no parent)\r
     //\r
     if (ParentNode == NULL) {\r
-      Status = EFI_INVALID_PARAMETER;\r
+      //\r
+      // We want the root node.  create the node.\r
+      //\r
+      FileInfo = FileHandleGetInfo(FileHandle);\r
+      NewShellNode = CreateAndPopulateShellFileInfo(\r
+        MapName,\r
+        EFI_SUCCESS,\r
+        L"\\",\r
+        FileHandle,\r
+        FileInfo\r
+        );\r
+      SHELL_FREE_NON_NULL(FileInfo);\r
     } else {\r
+      //\r
+      // Add the current parameter FileHandle to the list, then end...\r
+      //\r
       NewShellNode = InternalDuplicateShellFileInfo((EFI_SHELL_FILE_INFO*)ParentNode, TRUE);\r
-      if (NewShellNode == NULL) {\r
-        Status = EFI_OUT_OF_RESOURCES;\r
-      } else {\r
-        NewShellNode->Handle = NULL;\r
-        if (*FileList == NULL) {\r
-          *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
-          InitializeListHead(&((*FileList)->Link));\r
-        }\r
+    }\r
+    if (NewShellNode == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+    } else {\r
+      NewShellNode->Handle = NULL;\r
+      if (*FileList == NULL) {\r
+        *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
+        InitializeListHead(&((*FileList)->Link));\r
+      }\r
 \r
-        //\r
-        // Add to the returning to use list\r
-        //\r
-        InsertTailList(&(*FileList)->Link, &NewShellNode->Link);\r
+      //\r
+      // Add to the returning to use list\r
+      //\r
+      InsertTailList(&(*FileList)->Link, &NewShellNode->Link);\r
 \r
-        Status = EFI_SUCCESS;\r
-      }\r
+      Status = EFI_SUCCESS;\r
     }\r
   } else {\r
     Status = EfiShellFindFilesInDir(FileHandle, &ShellInfo);\r
@@ -2104,15 +2346,14 @@ ShellSearchHandle(
          ){\r
         if (UnicodeCollation->MetaiMatch(UnicodeCollation, (CHAR16*)ShellInfoNode->FileName, CurrentFilePattern)){\r
           if (ShellInfoNode->FullName != NULL && StrStr(ShellInfoNode->FullName, L":") == NULL) {\r
-            Size = StrSize(ShellInfoNode->FullName);\r
-            Size += StrSize(MapName) + sizeof(CHAR16);\r
+            Size = StrSize (ShellInfoNode->FullName) + StrSize (MapName);\r
             NewFullName = AllocateZeroPool(Size);\r
             if (NewFullName == NULL) {\r
               Status = EFI_OUT_OF_RESOURCES;\r
             } else {\r
-              StrCpy(NewFullName, MapName);\r
-              StrCat(NewFullName, ShellInfoNode->FullName+1);\r
-              FreePool((VOID*)ShellInfoNode->FullName);\r
+              StrCpyS(NewFullName, Size / sizeof(CHAR16), MapName);\r
+              StrCatS(NewFullName, Size / sizeof(CHAR16), ShellInfoNode->FullName);\r
+              FreePool ((VOID *) ShellInfoNode->FullName);\r
               ShellInfoNode->FullName = NewFullName;\r
             }\r
           }\r
@@ -2142,6 +2383,8 @@ ShellSearchHandle(
               // recurse with the next part of the pattern\r
               //\r
               Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode, MapName);\r
+              EfiShellClose(ShellInfoNode->Handle);\r
+              ShellInfoNode->Handle = NULL;\r
             }\r
           } else if (!EFI_ERROR(Status)) {\r
             //\r
@@ -2152,7 +2395,6 @@ ShellSearchHandle(
             // copy the information we need into a new Node\r
             //\r
             NewShellNode = InternalDuplicateShellFileInfo(ShellInfoNode, FALSE);\r
-            ASSERT(NewShellNode != NULL);\r
             if (NewShellNode == NULL) {\r
               Status = EFI_OUT_OF_RESOURCES;\r
             }\r
@@ -2179,6 +2421,10 @@ ShellSearchHandle(
     }\r
   }\r
 \r
+  if (*FileList == NULL || (*FileList != NULL && IsListEmpty(&(*FileList)->Link))) {\r
+    Status = EFI_NOT_FOUND;\r
+  }\r
+\r
   FreePool(CurrentFilePattern);\r
   return (Status);\r
 }\r
@@ -2234,16 +2480,15 @@ EfiShellFindFiles(
   RootDevicePath = NULL;\r
   RootFileHandle = NULL;\r
   MapName        = NULL;\r
-  PatternCopy = AllocateZeroPool(StrSize(FilePattern));\r
+  PatternCopy = AllocateCopyPool(StrSize(FilePattern), FilePattern);\r
   if (PatternCopy == NULL) {\r
     return (EFI_OUT_OF_RESOURCES);\r
   }\r
-  StrCpy(PatternCopy, FilePattern);\r
 \r
   PatternCopy = PathCleanUpDirectories(PatternCopy);\r
 \r
-  Count = StrStr(PatternCopy, L":") - PatternCopy;\r
-  Count += 2;\r
+  Count = StrStr(PatternCopy, L":") - PatternCopy + 1;\r
+  ASSERT (Count <= StrLen (PatternCopy));\r
 \r
   ASSERT(MapName == NULL);\r
   MapName = StrnCatGrow(&MapName, NULL, PatternCopy, Count);\r
@@ -2261,6 +2506,7 @@ EfiShellFindFiles(
             ; PatternCurrentLocation++);\r
         PatternCurrentLocation++;\r
         Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL, MapName);\r
+        EfiShellClose(RootFileHandle);\r
       }\r
       FreePool(RootDevicePath);\r
     }\r
@@ -2322,6 +2568,7 @@ EfiShellOpenFileList(
     CurDir = EfiShellGetCurDir(NULL);\r
     ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
     StrnCatGrow(&Path2, &Path2Size, CurDir, 0);\r
+    StrnCatGrow(&Path2, &Path2Size, L"\\", 0);\r
     if (*Path == L'\\') {\r
       Path++;\r
       while (PathRemoveLastItem(Path2)) ;\r
@@ -2367,40 +2614,37 @@ EfiShellOpenFileList(
 }\r
 \r
 /**\r
-  This function updated with errata.\r
-\r
-  Gets either a single or list of environment variables.\r
-\r
-  If name is not NULL then this function returns the current value of the specified\r
-  environment variable.\r
-\r
-  If Name is NULL, then a list of all environment variable names is returned.  Each is a\r
-  NULL terminated string with a double NULL terminating the list.\r
-\r
-  @param Name                   A pointer to the environment variable name.  If\r
-                                Name is NULL, then the function will return all\r
-                                of the defined shell environment variables.  In\r
-                                the case where multiple environment variables are\r
-                                being returned, each variable will be terminated by\r
-                                a NULL, and the list will be terminated by a double\r
-                                NULL.\r
-\r
-  @return !=NULL                A pointer to the returned string.\r
-                                The returned pointer does not need to be freed by the caller.\r
-\r
-  @retval NULL                  The environment variable doesn't exist or there are\r
-                                no environment variables.\r
+  Gets the environment variable and Attributes, or list of environment variables.  Can be\r
+  used instead of GetEnv().\r
+\r
+  This function returns the current value of the specified environment variable and\r
+  the Attributes. If no variable name was specified, then all of the known\r
+  variables will be returned.\r
+\r
+  @param[in] Name               A pointer to the environment variable name. If Name is NULL,\r
+                                then the function will return all of the defined shell\r
+                                environment variables. In the case where multiple environment\r
+                                variables are being returned, each variable will be terminated\r
+                                by a NULL, and the list will be terminated by a double NULL.\r
+  @param[out] Attributes        If not NULL, a pointer to the returned attributes bitmask for\r
+                                the environment variable. In the case where Name is NULL, and\r
+                                multiple environment variables are being returned, Attributes\r
+                                is undefined.\r
+\r
+  @retval NULL                  The environment variable doesn't exist.\r
+  @return                       A non-NULL value points to the variable's value. The returned\r
+                                pointer does not need to be freed by the caller.\r
 **/\r
 CONST CHAR16 *\r
 EFIAPI\r
-EfiShellGetEnv(\r
-  IN CONST CHAR16 *Name\r
+EfiShellGetEnvEx(\r
+  IN  CONST CHAR16 *Name,\r
+  OUT       UINT32 *Attributes OPTIONAL\r
   )\r
 {\r
   EFI_STATUS  Status;\r
   VOID        *Buffer;\r
   UINTN       Size;\r
-  LIST_ENTRY  List;\r
   ENV_VAR_LIST *Node;\r
   CHAR16      *CurrentWriteLocation;\r
 \r
@@ -2408,21 +2652,13 @@ EfiShellGetEnv(
   Buffer = NULL;\r
 \r
   if (Name == NULL) {\r
-    //\r
-    // Get all our environment variables\r
-    //\r
-    InitializeListHead(&List);\r
-    Status = GetEnvironmentVariableList(&List);\r
-    if (EFI_ERROR(Status)){\r
-      return (NULL);\r
-    }\r
 \r
     //\r
     // Build the semi-colon delimited list. (2 passes)\r
     //\r
-    for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List)\r
-      ; !IsNull(&List, &Node->Link)\r
-      ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)\r
+    for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
+      ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
+      ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
      ){\r
       ASSERT(Node->Key != NULL);\r
       Size += StrSize(Node->Key);\r
@@ -2432,54 +2668,59 @@ EfiShellGetEnv(
 \r
     Buffer = AllocateZeroPool(Size);\r
     if (Buffer == NULL) {\r
-      if (!IsListEmpty (&List)) {\r
-        FreeEnvironmentVariableList(&List);\r
-      }\r
       return (NULL);\r
     }\r
     CurrentWriteLocation = (CHAR16*)Buffer;\r
 \r
-    for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List)\r
-      ; !IsNull(&List, &Node->Link)\r
-      ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)\r
+    for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
+      ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
+      ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
      ){\r
       ASSERT(Node->Key != NULL);\r
-      StrCpy(CurrentWriteLocation, Node->Key);\r
+      StrCpyS( CurrentWriteLocation,\r
+                (Size)/sizeof(CHAR16) - (CurrentWriteLocation - ((CHAR16*)Buffer)),\r
+                Node->Key\r
+                );\r
       CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1;\r
     }\r
 \r
-    //\r
-    // Free the list...\r
-    //\r
-    if (!IsListEmpty (&List)) {\r
-      FreeEnvironmentVariableList(&List);\r
-    }\r
   } else {\r
     //\r
     // We are doing a specific environment variable\r
     //\r
+    Status = ShellFindEnvVarInList(Name, (CHAR16**)&Buffer, &Size, Attributes);\r
 \r
-    //\r
-    // get the size we need for this EnvVariable\r
-    //\r
-    Status = SHELL_GET_ENVIRONMENT_VARIABLE(Name, &Size, Buffer);\r
-    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    if (EFI_ERROR(Status)){\r
       //\r
-      // Allocate the space and recall the get function\r
+      // get the size we need for this EnvVariable\r
       //\r
-      Buffer = AllocateZeroPool(Size);\r
-      ASSERT(Buffer != NULL);\r
-      Status = SHELL_GET_ENVIRONMENT_VARIABLE(Name, &Size, Buffer);\r
-    }\r
-    //\r
-    // we didnt get it (might not exist)\r
-    // free the memory if we allocated any and return NULL\r
-    //\r
-    if (EFI_ERROR(Status)) {\r
-      if (Buffer != NULL) {\r
-        FreePool(Buffer);\r
+      Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer);\r
+      if (Status == EFI_BUFFER_TOO_SMALL) {\r
+        //\r
+        // Allocate the space and recall the get function\r
+        //\r
+        Buffer = AllocateZeroPool(Size);\r
+        Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer);\r
+      }\r
+      //\r
+      // we didnt get it (might not exist)\r
+      // free the memory if we allocated any and return NULL\r
+      //\r
+      if (EFI_ERROR(Status)) {\r
+        if (Buffer != NULL) {\r
+          FreePool(Buffer);\r
+        }\r
+        return (NULL);\r
+      } else {\r
+        //\r
+        // If we did not find the environment variable in the gShellEnvVarList\r
+        // but get it from UEFI variable storage successfully then we need update\r
+        // the gShellEnvVarList.\r
+        //\r
+        ShellFreeEnvVarList ();\r
+        Status = ShellInitEnvVarList ();\r
+        ASSERT (Status == EFI_SUCCESS);\r
       }\r
-      return (NULL);\r
     }\r
   }\r
 \r
@@ -2489,6 +2730,38 @@ EfiShellGetEnv(
   return (AddBufferToFreeList(Buffer));\r
 }\r
 \r
+/**\r
+  Gets either a single or list of environment variables.\r
+\r
+  If name is not NULL then this function returns the current value of the specified\r
+  environment variable.\r
+\r
+  If Name is NULL, then a list of all environment variable names is returned.  Each is a\r
+  NULL terminated string with a double NULL terminating the list.\r
+\r
+  @param Name                   A pointer to the environment variable name.  If\r
+                                Name is NULL, then the function will return all\r
+                                of the defined shell environment variables.  In\r
+                                the case where multiple environment variables are\r
+                                being returned, each variable will be terminated by\r
+                                a NULL, and the list will be terminated by a double\r
+                                NULL.\r
+\r
+  @retval !=NULL                A pointer to the returned string.\r
+                                The returned pointer does not need to be freed by the caller.\r
+\r
+  @retval NULL                  The environment variable doesn't exist or there are\r
+                                no environment variables.\r
+**/\r
+CONST CHAR16 *\r
+EFIAPI\r
+EfiShellGetEnv(\r
+  IN CONST CHAR16 *Name\r
+  )\r
+{\r
+  return (EfiShellGetEnvEx(Name, NULL));\r
+}\r
+\r
 /**\r
   Internal variable setting function.  Allows for setting of the read only variables.\r
 \r
@@ -2500,23 +2773,35 @@ EfiShellGetEnv(
   @retval EFI_SUCCESS           The environment variable was successfully updated.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 InternalEfiShellSetEnv(\r
   IN CONST CHAR16 *Name,\r
   IN CONST CHAR16 *Value,\r
   IN BOOLEAN Volatile\r
   )\r
 {\r
+  EFI_STATUS      Status;\r
+\r
   if (Value == NULL || StrLen(Value) == 0) {\r
-    return (SHELL_DELETE_ENVIRONMENT_VARIABLE(Name));\r
+    Status = SHELL_DELETE_ENVIRONMENT_VARIABLE(Name);\r
+    if (!EFI_ERROR(Status)) {\r
+      ShellRemvoeEnvVarFromList(Name);\r
+    }\r
   } else {\r
     SHELL_DELETE_ENVIRONMENT_VARIABLE(Name);\r
-    if (Volatile) {\r
-      return (SHELL_SET_ENVIRONMENT_VARIABLE_V(Name, StrSize(Value), Value));\r
-    } else {\r
-      return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(Name, StrSize(Value), Value));\r
+    Status = ShellAddEnvVarToList(\r
+               Name, Value, StrSize(Value),\r
+               EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE)\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = Volatile\r
+             ? SHELL_SET_ENVIRONMENT_VARIABLE_V (Name, StrSize (Value) - sizeof (CHAR16), Value)\r
+             : SHELL_SET_ENVIRONMENT_VARIABLE_NV (Name, StrSize (Value) - sizeof (CHAR16), Value);\r
+      if (EFI_ERROR (Status)) {\r
+        ShellRemvoeEnvVarFromList(Name);\r
+      }\r
     }\r
   }\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -2554,31 +2839,15 @@ EfiShellSetEnv(
   //\r
   // Make sure we dont 'set' a predefined read only variable\r
   //\r
-  if (gUnicodeCollation->StriColl(\r
-        gUnicodeCollation,\r
-        (CHAR16*)Name,\r
-        L"cwd") == 0\r
-    ||gUnicodeCollation->StriColl(\r
-        gUnicodeCollation,\r
-        (CHAR16*)Name,\r
-        L"Lasterror") == 0\r
-    ||gUnicodeCollation->StriColl(\r
-        gUnicodeCollation,\r
-        (CHAR16*)Name,\r
-        L"profiles") == 0\r
-    ||gUnicodeCollation->StriColl(\r
-        gUnicodeCollation,\r
-        (CHAR16*)Name,\r
-        L"uefishellsupport") == 0\r
-    ||gUnicodeCollation->StriColl(\r
-        gUnicodeCollation,\r
-        (CHAR16*)Name,\r
-        L"uefishellversion") == 0\r
-    ||gUnicodeCollation->StriColl(\r
-        gUnicodeCollation,\r
-        (CHAR16*)Name,\r
-        L"uefiversion") == 0\r
-       ){\r
+  if ((StrCmp (Name, L"cwd") == 0) ||\r
+      (StrCmp (Name, L"lasterror") == 0) ||\r
+      (StrCmp (Name, L"profiles") == 0) ||\r
+      (StrCmp (Name, L"uefishellsupport") == 0) ||\r
+      (StrCmp (Name, L"uefishellversion") == 0) ||\r
+      (StrCmp (Name, L"uefiversion") == 0) ||\r
+      (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest &&\r
+       StrCmp (Name, mNoNestingEnvVarName) == 0)\r
+     ) {\r
     return (EFI_INVALID_PARAMETER);\r
   }\r
   return (InternalEfiShellSetEnv(Name, Value, Volatile));\r
@@ -2592,6 +2861,8 @@ EfiShellSetEnv(
   FileSystemMapping. In both cases, the returned name includes the file system\r
   mapping (i.e. fs0:\current-dir).\r
 \r
+  Note that the current directory string should exclude the tailing backslash character.\r
+\r
   @param FileSystemMapping      A pointer to the file system mapping. If NULL,\r
                                 then the current working directory is returned.\r
 \r
@@ -2647,6 +2918,8 @@ EfiShellGetCurDir(
   If the current working directory or the current working file system is changed then the\r
   %cwd% environment variable will be updated\r
 \r
+  Note that the current directory string should exclude the tailing backslash character.\r
+\r
   @param FileSystem             A pointer to the file system's mapped name. If NULL, then the current working\r
                                 directory is changed.\r
   @param Dir                    Points to the NULL-terminated directory on the device specified by FileSystem.\r
@@ -2707,13 +2980,15 @@ EfiShellSetCurDir(
       // make that the current file system mapping\r
       //\r
       if (MapListItem != NULL) {\r
-        gShellCurDir = MapListItem;\r
+        gShellCurMapping = MapListItem;\r
       }\r
     } else {\r
-      MapListItem = gShellCurDir;\r
+      MapListItem = gShellCurMapping;\r
     }\r
 \r
     if (MapListItem == NULL) {\r
+      FreePool (DirectoryName);\r
+      SHELL_FREE_NON_NULL(MapName);\r
       return (EFI_NOT_FOUND);\r
     }\r
 \r
@@ -2730,19 +3005,23 @@ EfiShellSetCurDir(
         ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
         MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName+StrLen(MapName), 0);\r
       }\r
+      FreePool (MapName);\r
     } else {\r
       ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
       MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
     }\r
-    if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {\r
+    if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {\r
       ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
-      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
+      if (MapListItem->CurrentDirectoryPath != NULL) {\r
+        MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
+    }\r
     }\r
   } else {\r
     //\r
     // cant have a mapping in the directory...\r
     //\r
     if (StrStr(DirectoryName, L":") != NULL) {\r
+      FreePool (DirectoryName);\r
       return (EFI_INVALID_PARAMETER);\r
     }\r
     //\r
@@ -2750,9 +3029,10 @@ EfiShellSetCurDir(
     //\r
     MapListItem = ShellCommandFindMapItem(FileSystem);\r
     if (MapListItem == NULL) {\r
+      FreePool (DirectoryName);\r
       return (EFI_INVALID_PARAMETER);\r
     }\r
-//    gShellCurDir = MapListItem;\r
+//    gShellCurMapping = MapListItem;\r
     if (DirectoryName != NULL) {\r
       //\r
       // change current dir on that file system\r
@@ -2768,16 +3048,17 @@ EfiShellSetCurDir(
       MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
       ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
       MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
-      if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') {\r
+      if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') {\r
         ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
-        MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
+        MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
       }\r
     }\r
   }\r
+  FreePool (DirectoryName);\r
   //\r
   // if updated the current directory then update the environment variable\r
   //\r
-  if (MapListItem == gShellCurDir) {\r
+  if (MapListItem == gShellCurMapping) {\r
     Size = 0;\r
     ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
     StrnCatGrow(&TempString, &Size, MapListItem->MapName, 0);\r
@@ -2824,15 +3105,39 @@ EfiShellGetHelpText(
   )\r
 {\r
   CONST CHAR16  *ManFileName;\r
+  CHAR16        *FixCommand;\r
+  EFI_STATUS    Status;\r
 \r
   ASSERT(HelpText != NULL);\r
+  FixCommand = NULL;\r
 \r
   ManFileName = ShellCommandGetManFileNameHandler(Command);\r
 \r
   if (ManFileName != NULL) {\r
     return (ProcessManFile(ManFileName, Command, Sections, NULL, HelpText));\r
   } else {\r
-    return (ProcessManFile(Command, Command, Sections, NULL, HelpText));\r
+    if ((StrLen(Command)> 4)\r
+    && (Command[StrLen(Command)-1] == L'i' || Command[StrLen(Command)-1] == L'I')\r
+    && (Command[StrLen(Command)-2] == L'f' || Command[StrLen(Command)-2] == L'F')\r
+    && (Command[StrLen(Command)-3] == L'e' || Command[StrLen(Command)-3] == L'E')\r
+    && (Command[StrLen(Command)-4] == L'.')\r
+    ) {\r
+      FixCommand = AllocateZeroPool(StrSize(Command) - 4 * sizeof (CHAR16));\r
+      if (FixCommand == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+\r
+      StrnCpyS( FixCommand,\r
+                (StrSize(Command) - 4 * sizeof (CHAR16))/sizeof(CHAR16),\r
+                Command,\r
+                StrLen(Command)-4\r
+                );\r
+      Status = ProcessManFile(FixCommand, FixCommand, Sections, NULL, HelpText);\r
+      FreePool(FixCommand);\r
+      return Status;\r
+    } else {\r
+      return (ProcessManFile(Command, Command, Sections, NULL, HelpText));\r
+    }\r
   }\r
 }\r
 \r
@@ -2880,24 +3185,21 @@ EfiShellIsRootShell(
   @return !NULL   a list of all alias'\r
 **/\r
 CHAR16 *\r
-EFIAPI\r
 InternalEfiShellGetListAlias(\r
+  VOID\r
   )\r
 {\r
-  UINT64            MaxStorSize;\r
-  UINT64            RemStorSize;\r
-  UINT64            MaxVarSize;\r
+\r
   EFI_STATUS        Status;\r
   EFI_GUID          Guid;\r
   CHAR16            *VariableName;\r
   UINTN             NameSize;\r
+  UINTN             NameBufferSize;\r
   CHAR16            *RetVal;\r
   UINTN             RetSize;\r
 \r
-  Status = gRT->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, &MaxStorSize, &RemStorSize, &MaxVarSize);\r
-  ASSERT_EFI_ERROR(Status);\r
-\r
-  VariableName  = AllocateZeroPool((UINTN)MaxVarSize);\r
+  NameBufferSize = INIT_NAME_BUFFER_SIZE;\r
+  VariableName  = AllocateZeroPool(NameBufferSize);\r
   RetSize       = 0;\r
   RetVal        = NULL;\r
 \r
@@ -2908,26 +3210,65 @@ InternalEfiShellGetListAlias(
   VariableName[0] = CHAR_NULL;\r
 \r
   while (TRUE) {\r
-    NameSize = (UINTN)MaxVarSize;\r
+    NameSize = NameBufferSize;\r
     Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
     if (Status == EFI_NOT_FOUND){\r
       break;\r
+    } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;\r
+      SHELL_FREE_NON_NULL(VariableName);\r
+      VariableName = AllocateZeroPool(NameBufferSize);\r
+      if (VariableName == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        SHELL_FREE_NON_NULL(RetVal);\r
+        RetVal = NULL;\r
+        break;\r
+      }\r
+\r
+      NameSize = NameBufferSize;\r
+      Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
     }\r
-    ASSERT_EFI_ERROR(Status);\r
-    if (EFI_ERROR(Status)) {\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      SHELL_FREE_NON_NULL(RetVal);\r
+      RetVal = NULL;\r
       break;\r
     }\r
+\r
     if (CompareGuid(&Guid, &gShellAliasGuid)){\r
       ASSERT((RetVal == NULL && RetSize == 0) || (RetVal != NULL));\r
       RetVal = StrnCatGrow(&RetVal, &RetSize, VariableName, 0);\r
       RetVal = StrnCatGrow(&RetVal, &RetSize, L";", 0);\r
     } // compare guid\r
   } // while\r
-  FreePool(VariableName);\r
+  SHELL_FREE_NON_NULL(VariableName);\r
 \r
   return (RetVal);\r
 }\r
 \r
+/**\r
+  Convert a null-terminated unicode string, in-place, to all lowercase.\r
+  Then return it.\r
+\r
+  @param  Str    The null-terminated string to be converted to all lowercase.\r
+\r
+  @return        The null-terminated string converted into all lowercase.\r
+**/\r
+CHAR16 *\r
+ToLower (\r
+  CHAR16 *Str\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; Str[Index] != L'\0'; Index++) {\r
+    if (Str[Index] >= L'A' && Str[Index] <= L'Z') {\r
+      Str[Index] -= (CHAR16)(L'A' - L'a');\r
+    }\r
+  }\r
+  return Str;\r
+}\r
+\r
 /**\r
   This function returns the command associated with a alias or a list of all\r
   alias'.\r
@@ -2938,7 +3279,7 @@ InternalEfiShellGetListAlias(
   @param[out] Volatile          upon return of a single command if TRUE indicates\r
                                 this is stored in a volatile fashion.  FALSE otherwise.\r
 \r
-  @return                              If Alias is not NULL, it will return a pointer to\r
+  @return                        If Alias is not NULL, it will return a pointer to\r
                                 the NULL-terminated command for that alias.\r
                                 If Alias is NULL, ReturnedData points to a ';'\r
                                 delimited list of alias (e.g.\r
@@ -2957,22 +3298,34 @@ EfiShellGetAlias(
   UINTN       RetSize;\r
   UINT32      Attribs;\r
   EFI_STATUS  Status;\r
+  CHAR16      *AliasLower;\r
+  CHAR16      *AliasVal;\r
 \r
+  // Convert to lowercase to make aliases case-insensitive\r
   if (Alias != NULL) {\r
+    AliasLower = AllocateCopyPool (StrSize (Alias), Alias);\r
+    if (AliasLower == NULL) {\r
+      return NULL;\r
+    }\r
+    ToLower (AliasLower);\r
+\r
     if (Volatile == NULL) {\r
-      return (AddBufferToFreeList(GetVariable((CHAR16*)Alias, &gShellAliasGuid)));\r
+      GetVariable2 (AliasLower, &gShellAliasGuid, (VOID **)&AliasVal, NULL);\r
+      FreePool(AliasLower);\r
+      return (AddBufferToFreeList(AliasVal));\r
     }\r
     RetSize = 0;\r
     RetVal = NULL;\r
-    Status = gRT->GetVariable((CHAR16*)Alias, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
+    Status = gRT->GetVariable(AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
     if (Status == EFI_BUFFER_TOO_SMALL) {\r
       RetVal = AllocateZeroPool(RetSize);\r
-      Status = gRT->GetVariable((CHAR16*)Alias, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
+      Status = gRT->GetVariable(AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
     }\r
     if (EFI_ERROR(Status)) {\r
       if (RetVal != NULL) {\r
         FreePool(RetVal);\r
       }\r
+      FreePool(AliasLower);\r
       return (NULL);\r
     }\r
     if ((EFI_VARIABLE_NON_VOLATILE & Attribs) == EFI_VARIABLE_NON_VOLATILE) {\r
@@ -2981,6 +3334,7 @@ EfiShellGetAlias(
       *Volatile = TRUE;\r
     }\r
 \r
+    FreePool (AliasLower);\r
     return (AddBufferToFreeList(RetVal));\r
   }\r
   return (AddBufferToFreeList(InternalEfiShellGetListAlias()));\r
@@ -3003,31 +3357,49 @@ EfiShellGetAlias(
   @retval EFI_NOT_FOUND         the Alias intended to be deleted was not found\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 InternalSetAlias(\r
   IN CONST CHAR16 *Command,\r
   IN CONST CHAR16 *Alias,\r
   IN BOOLEAN Volatile\r
   )\r
 {\r
-  //\r
-  // We must be trying to remove one if Alias is NULL\r
-  //\r
+  EFI_STATUS  Status;\r
+  CHAR16      *AliasLower;\r
+  BOOLEAN     DeleteAlias;\r
+\r
+  DeleteAlias = FALSE;\r
   if (Alias == NULL) {\r
     //\r
+    // We must be trying to remove one if Alias is NULL\r
     // remove an alias (but passed in COMMAND parameter)\r
     //\r
-    return (gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL));\r
-  } else {\r
-    //\r
-    // Add and replace are the same\r
-    //\r
+    Alias       = Command;\r
+    DeleteAlias = TRUE;\r
+  }\r
+  ASSERT (Alias != NULL);\r
 \r
-    // We dont check the error return on purpose since the variable may not exist.\r
-    gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL);\r
+  //\r
+  // Convert to lowercase to make aliases case-insensitive\r
+  //\r
+  AliasLower = AllocateCopyPool (StrSize (Alias), Alias);\r
+  if (AliasLower == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  ToLower (AliasLower);\r
 \r
-    return (gRT->SetVariable((CHAR16*)Alias, &gShellAliasGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS|(Volatile?0:EFI_VARIABLE_NON_VOLATILE), StrSize(Command), (VOID*)Command));\r
+  if (DeleteAlias) {\r
+    Status = gRT->SetVariable (AliasLower, &gShellAliasGuid, 0, 0, NULL);\r
+  } else {\r
+    Status = gRT->SetVariable (\r
+                    AliasLower, &gShellAliasGuid,\r
+                    EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE),\r
+                    StrSize (Command), (VOID *) Command\r
+                    );\r
   }\r
+\r
+  FreePool (AliasLower);\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -3049,6 +3421,7 @@ InternalSetAlias(
   @retval EFI_NOT_FOUND         the Alias intended to be deleted was not found\r
   @retval EFI_ACCESS_DENIED     The alias is a built-in alias or already existed and Replace was set to\r
                                 FALSE.\r
+  @retval EFI_INVALID_PARAMETER Command is null or the empty string.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -3059,21 +3432,24 @@ EfiShellSetAlias(
   IN BOOLEAN Volatile\r
   )\r
 {\r
-  //\r
-  // cant set over a built in alias\r
-  //\r
   if (ShellCommandIsOnAliasList(Alias==NULL?Command:Alias)) {\r
+    //\r
+    // cant set over a built in alias\r
+    //\r
     return (EFI_ACCESS_DENIED);\r
-  }\r
-  if (Command == NULL || *Command == CHAR_NULL || StrLen(Command) == 0) {\r
+  } else if (Command == NULL || *Command == CHAR_NULL || StrLen(Command) == 0) {\r
+    //\r
+    // Command is null or empty\r
+    //\r
     return (EFI_INVALID_PARAMETER);\r
-  }\r
-\r
-  if (EfiShellGetAlias(Command, NULL) != NULL && !Replace) {\r
+  } else if (EfiShellGetAlias(Command, NULL) != NULL && !Replace) {\r
+    //\r
+    // Alias already exists, Replace not set\r
+    //\r
     return (EFI_ACCESS_DENIED);\r
+  } else {\r
+    return (InternalSetAlias(Command, Alias, Volatile));\r
   }\r
-\r
-  return (InternalSetAlias(Command, Alias, Volatile));\r
 }\r
 \r
 // Pure FILE_HANDLE operations are passed to FileHandleLib\r
@@ -3120,7 +3496,13 @@ EFI_SHELL_PROTOCOL         mShellProtocol = {
   EfiShellOpenRootByHandle,\r
   NULL,\r
   SHELL_MAJOR_VERSION,\r
-  SHELL_MINOR_VERSION\r
+  SHELL_MINOR_VERSION,\r
+\r
+  // New for UEFI Shell 2.1\r
+  EfiShellRegisterGuidName,\r
+  EfiShellGetGuidName,\r
+  EfiShellGetGuidFromName,\r
+  EfiShellGetEnvEx\r
 };\r
 \r
 /**\r
@@ -3138,7 +3520,6 @@ EFI_SHELL_PROTOCOL         mShellProtocol = {
   @return                 An error from LocateHandle, CreateEvent, or other core function.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 CreatePopulateInstallShellProtocol (\r
   IN OUT EFI_SHELL_PROTOCOL  **NewShell\r
   )\r
@@ -3148,6 +3529,7 @@ CreatePopulateInstallShellProtocol (
   EFI_HANDLE                  *Buffer;\r
   UINTN                       HandleCounter;\r
   SHELL_PROTOCOL_HANDLE_LIST  *OldProtocolNode;\r
+  EFI_SHELL_PROTOCOL          *OldShell;\r
 \r
   if (NewShell == NULL) {\r
     return (EFI_INVALID_PARAMETER);\r
@@ -3199,20 +3581,27 @@ CreatePopulateInstallShellProtocol (
     // now overwrite each of them, but save the info to restore when we end.\r
     //\r
     for (HandleCounter = 0 ; HandleCounter < (BufferSize/sizeof(EFI_HANDLE)) ; HandleCounter++) {\r
-      OldProtocolNode = AllocateZeroPool(sizeof(SHELL_PROTOCOL_HANDLE_LIST));\r
-      ASSERT(OldProtocolNode != NULL);\r
       Status = gBS->OpenProtocol(Buffer[HandleCounter],\r
                                 &gEfiShellProtocolGuid,\r
-                                (VOID **) &(OldProtocolNode->Interface),\r
+                                (VOID **) &OldShell,\r
                                 gImageHandle,\r
                                 NULL,\r
                                 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
                                );\r
       if (!EFI_ERROR(Status)) {\r
+        OldProtocolNode = AllocateZeroPool(sizeof(SHELL_PROTOCOL_HANDLE_LIST));\r
+        if (OldProtocolNode == NULL) {\r
+          if (!IsListEmpty (&ShellInfoObject.OldShellList.Link)) {\r
+            CleanUpShellProtocol (&mShellProtocol);\r
+          }\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          break;\r
+        }\r
         //\r
         // reinstall over the old one...\r
         //\r
-        OldProtocolNode->Handle = Buffer[HandleCounter];\r
+        OldProtocolNode->Handle    = Buffer[HandleCounter];\r
+        OldProtocolNode->Interface = OldShell;\r
         Status = gBS->ReinstallProtocolInterface(\r
                             OldProtocolNode->Handle,\r
                             &gEfiShellProtocolGuid,\r
@@ -3265,38 +3654,50 @@ CreatePopulateInstallShellProtocol (
   @retval EFI_SUCCESS       The operation was successful.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 CleanUpShellProtocol (\r
   IN OUT EFI_SHELL_PROTOCOL  *NewShell\r
   )\r
 {\r
-  EFI_STATUS                        Status;\r
   SHELL_PROTOCOL_HANDLE_LIST        *Node2;\r
-  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
 \r
   //\r
   // if we need to restore old protocols...\r
   //\r
   if (!IsListEmpty(&ShellInfoObject.OldShellList.Link)) {\r
-    for (Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link)\r
+    for (Node2 = (SHELL_PROTOCOL_HANDLE_LIST *) GetFirstNode (&ShellInfoObject.OldShellList.Link)\r
          ; !IsListEmpty (&ShellInfoObject.OldShellList.Link)\r
-         ; Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link)\r
-        ){\r
-      RemoveEntryList(&Node2->Link);\r
-      Status = gBS->ReinstallProtocolInterface(Node2->Handle,\r
-                                               &gEfiShellProtocolGuid,\r
-                                               NewShell,\r
-                                               Node2->Interface);\r
-      FreePool(Node2);\r
+         ; Node2 = (SHELL_PROTOCOL_HANDLE_LIST *) GetFirstNode (&ShellInfoObject.OldShellList.Link)\r
+         ) {\r
+      RemoveEntryList (&Node2->Link);\r
+      gBS->ReinstallProtocolInterface (Node2->Handle, &gEfiShellProtocolGuid, NewShell, Node2->Interface);\r
+      FreePool (Node2);\r
     }\r
   } else {\r
     //\r
     // no need to restore\r
     //\r
-    Status = gBS->UninstallProtocolInterface(gImageHandle,\r
-                                             &gEfiShellProtocolGuid,\r
-                                             NewShell);\r
+    gBS->UninstallProtocolInterface (gImageHandle, &gEfiShellProtocolGuid, NewShell);\r
   }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Cleanup the shell environment.\r
+\r
+  @param[in, out] NewShell   The pointer to the new shell protocol structure.\r
+\r
+  @retval EFI_SUCCESS       The operation was successful.\r
+**/\r
+EFI_STATUS\r
+CleanUpShellEnvironment (\r
+  IN OUT EFI_SHELL_PROTOCOL  *NewShell\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
+\r
+  CleanUpShellProtocol (NewShell);\r
+\r
   Status = gBS->CloseEvent(NewShell->ExecutionBreak);\r
   NewShell->ExecutionBreak = NULL;\r
 \r
@@ -3334,37 +3735,30 @@ NotificationFunction(
   IN EFI_KEY_DATA *KeyData\r
   )\r
 {\r
-  EFI_INPUT_KEY Key;\r
-  if ((KeyData->Key.UnicodeChar == L'c' || KeyData->Key.UnicodeChar == 3) &&\r
-      (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))\r
-      ){ \r
+  if ( ((KeyData->Key.UnicodeChar == L'c') &&\r
+        (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))) ||\r
+      (KeyData->Key.UnicodeChar == 3)\r
+      ){\r
     if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
       return (EFI_UNSUPPORTED);\r
     }\r
     return (gBS->SignalEvent(ShellInfoObject.NewEfiShellProtocol->ExecutionBreak));\r
   } else if  ((KeyData->Key.UnicodeChar == L's') &&\r
               (KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))\r
-              ){ \r
+              ){\r
     ShellInfoObject.HaltOutput = TRUE;\r
-\r
-    //\r
-    // Make sure that there are no pending keystrokes to pervent the pause.\r
-    //\r
-    gST->ConIn->Reset(gST->ConIn, FALSE);\r
-    while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key)==EFI_SUCCESS);\r
   }\r
   return (EFI_SUCCESS);\r
 }\r
 \r
 /**\r
-  Function to start monitoring for CTRL-C using SimpleTextInputEx.  This \r
+  Function to start monitoring for CTRL-C using SimpleTextInputEx.  This\r
   feature's enabled state was not known when the shell initially launched.\r
 \r
   @retval EFI_SUCCESS           The feature is enabled.\r
   @retval EFI_OUT_OF_RESOURCES  There is not enough mnemory available.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 InernalEfiShellStartMonitor(\r
   VOID\r
   )\r
@@ -3382,8 +3776,8 @@ InernalEfiShellStartMonitor(
     EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
   if (EFI_ERROR(Status)) {\r
     ShellPrintHiiEx(\r
-      -1, \r
-      -1, \r
+      -1,\r
+      -1,\r
       NULL,\r
       STRING_TOKEN (STR_SHELL_NO_IN_EX),\r
       ShellInfoObject.HiiHandle);\r
@@ -3404,7 +3798,7 @@ InernalEfiShellStartMonitor(
     &KeyData,\r
     NotificationFunction,\r
     &ShellInfoObject.CtrlCNotifyHandle1);\r
-  \r
+\r
   KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
   if (!EFI_ERROR(Status)) {\r
     Status = SimpleEx->RegisterKeyNotify(\r
@@ -3432,3 +3826,4 @@ InernalEfiShellStartMonitor(
   }\r
   return (Status);\r
 }\r
+\r