]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/ShellProtocol.c
ShellPkg/alias: Fix bug to support upper-case alias
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
index 392298989ee6dd7a943deb50453d8a1d09580eef..b3b8acc0d01833c6e09fd4c661bf160ebe895ab2 100644 (file)
@@ -2,7 +2,9 @@
   Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
   manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
 \r
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\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 - 2017, 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
@@ -14,7 +16,8 @@
 **/\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
@@ -37,6 +40,35 @@ EfiShellClose (
   return (FileHandleClose(ConvertShellHandleToEfiFileProtocol(FileHandle)));\r
 }\r
 \r
+/**\r
+  Internal worker to determine whether there is a BlockIo somewhere\r
+  upon the device path specified.\r
+\r
+  @param[in] DevicePath    The device path to test.\r
+\r
+  @retval TRUE      gEfiBlockIoProtocolGuid was installed on a handle with this device path\r
+  @retval FALSE     gEfiBlockIoProtocolGuid was not found.\r
+**/\r
+BOOLEAN\r
+InternalShellProtocolIsBlockIoPresent(\r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathCopy;\r
+  EFI_STATUS                Status;\r
+  EFI_HANDLE                Handle;\r
+\r
+  Handle = NULL;\r
+\r
+  DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath;\r
+  Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid, &DevicePathCopy, &Handle);\r
+\r
+  if ((Handle != NULL) && (!EFI_ERROR(Status))) {\r
+    return (TRUE);\r
+  }\r
+  return (FALSE);\r
+}\r
+\r
 /**\r
   Internal worker to determine whether there is a file system somewhere\r
   upon the device path specified.\r
@@ -47,7 +79,6 @@ EfiShellClose (
   @retval FALSE     gEfiSimpleFileSystemProtocolGuid was not found.\r
 **/\r
 BOOLEAN\r
-EFIAPI\r
 InternalShellProtocolIsSimpleFileSystemPresent(\r
   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
   )\r
@@ -80,33 +111,24 @@ InternalShellProtocolIsSimpleFileSystemPresent(
   @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
+  Temp = ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
+  DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp));\r
+  FreePool(Temp);\r
+\r
   DEBUG_CODE_END();\r
   return (Status);\r
 }\r
@@ -161,6 +183,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
@@ -176,7 +201,8 @@ EfiShellSetMap(
   // make sure this is a valid to add device path\r
   //\r
   ///@todo add BlockIo to this test...\r
-  if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath)) {\r
+  if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath)\r
+    && !InternalShellProtocolIsBlockIoPresent(DevicePath)) {\r
     return (EFI_INVALID_PARAMETER);\r
   }\r
 \r
@@ -386,6 +412,7 @@ EfiShellGetFilePathFromDevicePath(
   EFI_HANDLE                      MapHandle;\r
   EFI_STATUS                      Status;\r
   FILEPATH_DEVICE_PATH            *FilePath;\r
+  FILEPATH_DEVICE_PATH            *AlignedNode;\r
 \r
   PathForReturn = NULL;\r
   PathSize = 0;\r
@@ -423,21 +450,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
-          PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, FilePath->PathName, 0);\r
+          return NULL;\r
         }\r
+\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 - 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
@@ -453,10 +499,12 @@ EfiShellGetFilePathFromDevicePath(
   This function converts a file system style name to a device path, by replacing any\r
   mapping references to the associated device path.\r
 \r
-  @param Path                   the pointer to the path\r
+  @param[in] Path               The pointer to the path.\r
 \r
-  @return all                   The pointer of the file path. The file path is callee\r
+  @return                       The pointer of the file path. The file path is callee\r
                                 allocated and should be freed by the caller.\r
+  @retval NULL                  The path could not be found.\r
+  @retval NULL                  There was not enough available memory.\r
 **/\r
 EFI_DEVICE_PATH_PROTOCOL *\r
 EFIAPI\r
@@ -487,17 +535,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
-    ASSERT(NewPath != NULL);\r
-    StrCpy(NewPath, Cwd);\r
-    if ((Path[0] == (CHAR16)L'\\') &&\r
-        (NewPath[StrLen(NewPath)-1] == (CHAR16)L'\\')\r
-       ) {\r
-      ((CHAR16*)NewPath)[StrLen(NewPath)-1] = CHAR_NULL;\r
-    }\r
-    StrCat(NewPath, Path);\r
+    if (NewPath == NULL) {\r
+      return (NULL);\r
+    }\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
+    StrCatS(NewPath, Size/sizeof(CHAR16), Path);\r
     DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath);\r
     FreePool(NewPath);\r
     return (DevicePathForReturn);\r
@@ -509,8 +558,7 @@ EfiShellGetDevicePathFromFilePath(
   //\r
   ASSERT((MapName == NULL && Size == 0) || (MapName != NULL));\r
   MapName = StrnCatGrow(&MapName, &Size, Path, (StrStr(Path, L":")-Path+1));\r
-  if (MapName[StrLen(MapName)-1] != L':') {\r
-    ASSERT(FALSE);\r
+  if (MapName == NULL || MapName[StrLen(MapName)-1] != L':') {\r
     return (NULL);\r
   }\r
 \r
@@ -530,7 +578,6 @@ EfiShellGetDevicePathFromFilePath(
   //\r
   DevicePathCopyForFree = DevicePathCopy = DuplicateDevicePath(DevicePath);\r
   if (DevicePathCopy == NULL) {\r
-    ASSERT(FALSE);\r
     FreePool(MapName);\r
     return (NULL);\r
   }\r
@@ -551,7 +598,11 @@ EfiShellGetDevicePathFromFilePath(
   //\r
   // build the full device path\r
   //\r
-  DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName)+1);\r
+  if (*(Path+StrLen(MapName)+1) == CHAR_NULL) {\r
+    DevicePathForReturn = FileDevicePath(Handle, L"\\");\r
+  } else {\r
+    DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName));\r
+  }\r
 \r
   FreePool(MapName);\r
   if (DevicePathCopyForFree != NULL) {\r
@@ -608,14 +659,16 @@ 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
+  UINTN                             ParentControllerCount;\r
+  EFI_HANDLE                        *ParentControllerBuffer;\r
+  UINTN                             ParentDriverCount;\r
+  EFI_HANDLE                        *ParentDriverBuffer;\r
 \r
   if (BestDeviceName == NULL ||\r
       DeviceHandle   == NULL\r
@@ -668,23 +721,7 @@ EfiShellGetDeviceName(
       if (EFI_ERROR(Status)) {\r
         continue;\r
       }\r
-      if (Language == NULL) {\r
-        Lang = AllocatePool(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 = AllocatePool(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
@@ -695,38 +732,79 @@ EfiShellGetDeviceName(
     if (HandleList != NULL) {\r
       FreePool(HandleList);\r
     }\r
+\r
+    //\r
+    // Now check the parent controller using this as the child.\r
+    //\r
+    if (DeviceNameToReturn == NULL){\r
+      PARSE_HANDLE_DATABASE_PARENTS(DeviceHandle, &ParentControllerCount, &ParentControllerBuffer);\r
+      for (LoopVar = 0 ; LoopVar < ParentControllerCount ; LoopVar++) {\r
+        PARSE_HANDLE_DATABASE_UEFI_DRIVERS(ParentControllerBuffer[LoopVar], &ParentDriverCount, &ParentDriverBuffer);\r
+        for (HandleCount = 0 ; HandleCount < ParentDriverCount ; HandleCount++) {\r
+          //\r
+          // try using that driver's component name with controller and our driver as the child.\r
+          //\r
+          Status = gBS->OpenProtocol(\r
+            ParentDriverBuffer[HandleCount],\r
+            &gEfiComponentName2ProtocolGuid,\r
+            (VOID**)&CompName2,\r
+            gImageHandle,\r
+            NULL,\r
+            EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+          if (EFI_ERROR(Status)) {\r
+            Status = gBS->OpenProtocol(\r
+              ParentDriverBuffer[HandleCount],\r
+              &gEfiComponentNameProtocolGuid,\r
+              (VOID**)&CompName2,\r
+              gImageHandle,\r
+              NULL,\r
+              EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+          }\r
+\r
+          if (EFI_ERROR(Status)) {\r
+            continue;\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
+          if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {\r
+            break;\r
+          }\r
+\r
+\r
+\r
+        }\r
+        SHELL_FREE_NON_NULL(ParentDriverBuffer);\r
+        if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {\r
+          break;\r
+        }\r
+      }\r
+      SHELL_FREE_NON_NULL(ParentControllerBuffer);\r
+    }\r
+    //\r
+    // dont return on fail since we will try device path if that bit is on\r
+    //\r
     if (DeviceNameToReturn != NULL){\r
       ASSERT(BestDeviceName != NULL);\r
       StrnCatGrow(BestDeviceName, NULL, DeviceNameToReturn, 0);\r
       return (EFI_SUCCESS);\r
     }\r
-    //\r
-    // dont return on fail since we will try device path if that bit is on\r
-    //\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
@@ -870,7 +948,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
@@ -884,7 +961,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
@@ -894,7 +970,6 @@ InternalOpenFileDevicePath(
   Handle1       = NULL;\r
   Handle2       = NULL;\r
   Handle        = NULL;\r
-  DpCopy        = DevicePath;\r
   ShellHandle   = NULL;\r
   FilePathNode  = NULL;\r
   AlignedNode   = NULL;\r
@@ -903,75 +978,46 @@ InternalOpenFileDevicePath(
 \r
   if (!EFI_ERROR(Status)) {\r
     Handle1 = ConvertShellHandleToEfiFileProtocol(ShellHandle);\r
-    //\r
-    // chop off the begining part before the file system part...\r
-    //\r
-    ///@todo BlockIo?\r
-    Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,\r
-                                   &DevicePath,\r
-                                   &Handle);\r
-      if (!EFI_ERROR(Status)) {\r
+    if (Handle1 != NULL) {\r
       //\r
-      // To access as a file system, the file path should only\r
-      // contain file path components.  Follow the file path nodes\r
-      // and find the target file\r
+      // chop off the begining part before the file system part...\r
       //\r
-      for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath\r
-          ; !IsDevicePathEnd (&FilePathNode->Header)\r
-          ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header)\r
-         ){\r
-        SHELL_FREE_NON_NULL(AlignedNode);\r
-        AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePathNode), FilePathNode);\r
-        //\r
-        // For file system access each node should be a file path component\r
-        //\r
-        if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||\r
-            DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP\r
-           ) {\r
-          Status = EFI_UNSUPPORTED;\r
-          break;\r
-        }\r
-\r
-        //\r
-        // Open this file path node\r
-        //\r
-        Handle2 = Handle1;\r
-        Handle1 = NULL;\r
-\r
+      ///@todo BlockIo?\r
+      Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,\r
+                                     &DevicePath,\r
+                                     &Handle);\r
+        if (!EFI_ERROR(Status)) {\r
         //\r
-        // if this is the last node in the DevicePath always create (if that was requested).\r
+        // To access as a file system, the file path should only\r
+        // contain file path components.  Follow the file path nodes\r
+        // and find the target file\r
         //\r
-        if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) {\r
-          Status = Handle2->Open (\r
-                                Handle2,\r
-                                &Handle1,\r
-                                AlignedNode->PathName,\r
-                                OpenMode,\r
-                                Attributes\r
-                               );\r
-        } else {\r
-\r
+        for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath\r
+            ; !IsDevicePathEnd (&FilePathNode->Header)\r
+            ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header)\r
+           ){\r
+          SHELL_FREE_NON_NULL(AlignedNode);\r
+          AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePathNode), FilePathNode);\r
           //\r
-          //  This is not the last node and we dont want to 'create' existing\r
-          //  directory entries...\r
+          // For file system access each node should be a file path component\r
           //\r
+          if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||\r
+              DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP\r
+             ) {\r
+            Status = EFI_UNSUPPORTED;\r
+            break;\r
+          }\r
 \r
           //\r
-          // open without letting it create\r
-          // prevents error on existing files/directories\r
+          // Open this file path node\r
           //\r
-          Status = Handle2->Open (\r
-                                Handle2,\r
-                                &Handle1,\r
-                                AlignedNode->PathName,\r
-                                OpenMode &~EFI_FILE_MODE_CREATE,\r
-                                Attributes\r
-                               );\r
+          Handle2 = Handle1;\r
+          Handle1 = NULL;\r
+\r
           //\r
-          // if above failed now open and create the 'item'\r
-          // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)\r
+          // if this is the last node in the DevicePath always create (if that was requested).\r
           //\r
-          if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {\r
+          if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) {\r
             Status = Handle2->Open (\r
                                   Handle2,\r
                                   &Handle1,\r
@@ -979,20 +1025,51 @@ InternalOpenFileDevicePath(
                                   OpenMode,\r
                                   Attributes\r
                                  );\r
+          } else {\r
+\r
+            //\r
+            //  This is not the last node and we dont want to 'create' existing\r
+            //  directory entries...\r
+            //\r
+\r
+            //\r
+            // open without letting it create\r
+            // prevents error on existing files/directories\r
+            //\r
+            Status = Handle2->Open (\r
+                                  Handle2,\r
+                                  &Handle1,\r
+                                  AlignedNode->PathName,\r
+                                  OpenMode &~EFI_FILE_MODE_CREATE,\r
+                                  Attributes\r
+                                 );\r
+            //\r
+            // if above failed now open and create the 'item'\r
+            // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)\r
+            //\r
+            if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {\r
+              Status = Handle2->Open (\r
+                                    Handle2,\r
+                                    &Handle1,\r
+                                    AlignedNode->PathName,\r
+                                    OpenMode,\r
+                                    Attributes\r
+                                   );\r
+            }\r
           }\r
-        }\r
-        //\r
-        // Close the last node\r
-        //\r
-        ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle2);\r
+          //\r
+          // Close the last node\r
+          //\r
+          ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle2);\r
 \r
-        //\r
-        // If there's been an error, stop\r
-        //\r
-        if (EFI_ERROR (Status)) {\r
-          break;\r
-        }\r
-      } // for loop\r
+          //\r
+          // If there's been an error, stop\r
+          //\r
+          if (EFI_ERROR (Status)) {\r
+            break;\r
+          }\r
+        } // for loop\r
+      }\r
     }\r
   }\r
   SHELL_FREE_NON_NULL(AlignedNode);\r
@@ -1052,13 +1129,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
@@ -1073,12 +1155,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
@@ -1141,6 +1250,7 @@ EfiShellOpenFileByName(
 {\r
   EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
   EFI_STATUS                      Status;\r
+  BOOLEAN                         Volatile;\r
 \r
   *FileHandle = NULL;\r
 \r
@@ -1174,9 +1284,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
@@ -1200,7 +1311,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
@@ -1246,6 +1361,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
@@ -1258,6 +1375,7 @@ EfiShellDeleteFileByName(
   //\r
   // now delete the file\r
   //\r
+  ShellFileHandleRemove(FileHandle);\r
   return (ShellInfoObject.NewEfiShellProtocol->DeleteFile(FileHandle));\r
 }\r
 \r
@@ -1288,17 +1406,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
@@ -1307,28 +1426,45 @@ 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
@@ -1346,6 +1482,7 @@ InternalShellExecuteDevicePath(
     if (NewHandle != NULL) {\r
       gBS->UnloadImage(NewHandle);\r
     }\r
+    FreePool (NewCmdLine);\r
     return (Status);\r
   }\r
   Status = gBS->OpenProtocol(\r
@@ -1357,10 +1494,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
@@ -1379,8 +1530,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
@@ -1390,34 +1568,152 @@ 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
+)\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
@@ -1441,7 +1737,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
@@ -1470,35 +1766,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
@@ -1511,7 +1815,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
@@ -1561,6 +1864,8 @@ EfiShellFreeFileList(
     RemoveEntryList(&ShellFileListItem->Link);\r
     InternalFreeShellFileInfoNode(ShellFileListItem);\r
   }\r
+  InternalFreeShellFileInfoNode(*FileList);\r
+  *FileList = NULL;\r
   return(EFI_SUCCESS);\r
 }\r
 \r
@@ -1582,6 +1887,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
@@ -1599,13 +1905,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
@@ -1616,26 +1942,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 = AllocatePool(sizeof(EFI_SHELL_FILE_INFO));\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     = AllocatePool((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
@@ -1643,11 +1976,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
@@ -1656,7 +1986,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
@@ -1665,11 +1994,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
@@ -1686,7 +2013,7 @@ CreateAndPopulateShellFileInfo(
   if (ShellFileListItem == NULL) {\r
     return (NULL);\r
   }\r
-  if (Info != NULL) {\r
+  if (Info != NULL && Info->Size != 0) {\r
     ShellFileListItem->Info = AllocateZeroPool((UINTN)Info->Size);\r
     if (ShellFileListItem->Info == NULL) {\r
       FreePool(ShellFileListItem);\r
@@ -1714,7 +2041,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
@@ -1730,6 +2057,8 @@ CreateAndPopulateShellFileInfo(
     }\r
   }\r
 \r
+  TempString = PathCleanUpDirectories(TempString);\r
+\r
   ShellFileListItem->FullName = TempString;\r
   ShellFileListItem->Status   = Status;\r
   ShellFileListItem->Handle   = Handle;\r
@@ -1768,6 +2097,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
@@ -1777,6 +2107,10 @@ EfiShellFindFilesInDir(
     TempString        = NULL;\r
     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
 \r
     if (TempSpot != NULL) {\r
@@ -1784,6 +2118,11 @@ EfiShellFindFilesInDir(
     }\r
 \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
@@ -1798,26 +2137,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
@@ -1831,17 +2173,97 @@ EfiShellFindFilesInDir(
   return(Status);\r
 }\r
 \r
+/**\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
+  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]  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
+EfiShellGetGuidFromName(\r
+  IN  CONST CHAR16   *GuidName,\r
+  OUT       EFI_GUID *Guid\r
+  )\r
+{\r
+  EFI_GUID    *NewGuid;\r
+  EFI_STATUS  Status;\r
+\r
+  if (Guid == NULL || GuidName == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
\r
+  Status = GetGuidFromStringName(GuidName, NULL, &NewGuid);\r
+\r
+  if (!EFI_ERROR(Status)) {\r
+    CopyGuid(Guid, NewGuid);\r
+  }\r
+\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
   Updates a file name to be preceeded by the mapped drive name\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
+  @param[in] BasePath      the Mapped drive name to prepend\r
+  @param[in, out] Path     pointer to pointer to the file name to update.\r
 \r
   @retval EFI_SUCCESS\r
   @retval EFI_OUT_OF_RESOURCES\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 UpdateFileName(\r
   IN CONST CHAR16 *BasePath,\r
   IN OUT CHAR16   **Path\r
@@ -1890,19 +2312,18 @@ UpdateFileName(
   Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call\r
   FreeFileList with FileList.\r
 \r
-  @param[in] FilePattern        The FilePattern to check against.\r
-  @param[in] UnicodeCollation   The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure\r
-  @param[in] FileHandle         The FileHandle to start with\r
-  @param[in,out] FileList       pointer to pointer to list of found files.\r
-  @param[in] ParentNode         The node for the parent. Same file as identified by HANDLE.\r
-  @param[in] MapName            The file system name this file is on.\r
+  @param[in] FilePattern         The FilePattern to check against.\r
+  @param[in] UnicodeCollation    The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure\r
+  @param[in] FileHandle          The FileHandle to start with\r
+  @param[in, out] FileList       pointer to pointer to list of found files.\r
+  @param[in] ParentNode          The node for the parent. Same file as identified by HANDLE.\r
+  @param[in] MapName             The file system name this file is on.\r
 \r
   @retval EFI_SUCCESS           all files were found and the FileList contains a list.\r
   @retval EFI_NOT_FOUND         no files were found\r
   @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
@@ -1918,6 +2339,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
@@ -1940,35 +2362,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 = AllocatePool(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
@@ -1985,19 +2424,18 @@ 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
-          if (Directory && !EFI_ERROR(Status)){\r
+          if (Directory && !EFI_ERROR(Status) && ShellInfoNode->FullName != NULL && ShellInfoNode->FileName != NULL){\r
             //\r
             // should be a directory\r
             //\r
@@ -2011,7 +2449,6 @@ ShellSearchHandle(
               //\r
               //\r
               //\r
-              ASSERT_EFI_ERROR(Status);\r
               if (EFI_ERROR(Status)) {\r
                 break;\r
               }\r
@@ -2024,6 +2461,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
@@ -2034,12 +2473,11 @@ 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
             if (*FileList == NULL) {\r
-              *FileList = AllocatePool(sizeof(EFI_SHELL_FILE_INFO));\r
+              *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
               InitializeListHead(&((*FileList)->Link));\r
             }\r
 \r
@@ -2061,6 +2499,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
@@ -2116,21 +2558,21 @@ EfiShellFindFiles(
   RootDevicePath = NULL;\r
   RootFileHandle = NULL;\r
   MapName        = NULL;\r
-  PatternCopy = AllocatePool(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 = CleanPath(PatternCopy);\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
-\r
-  if (!EFI_ERROR(Status)) {\r
+  if (MapName == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+  } else {\r
     RootDevicePath = EfiShellGetDevicePathFromFilePath(PatternCopy);\r
     if (RootDevicePath == NULL) {\r
       Status = EFI_INVALID_PARAMETER;\r
@@ -2142,6 +2584,7 @@ EfiShellFindFiles(
             ; PatternCurrentLocation++);\r
         PatternCurrentLocation++;\r
         Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL, MapName);\r
+        EfiShellClose(RootFileHandle);\r
       }\r
       FreePool(RootDevicePath);\r
     }\r
@@ -2181,17 +2624,19 @@ EfiShellOpenFileList(
   CHAR16              *Path2;\r
   UINTN               Path2Size;\r
   CONST CHAR16        *CurDir;\r
+  BOOLEAN             Found;\r
 \r
-  ShellCommandCleanPath(Path);\r
+  PathCleanUpDirectories(Path);\r
 \r
   Path2Size     = 0;\r
   Path2         = NULL;\r
 \r
-  ASSERT(FileList  != NULL);\r
-  ASSERT(*FileList != NULL);\r
+  if (FileList == NULL || *FileList == NULL) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
 \r
   if (*Path == L'.' && *(Path+1) == L'\\') {\r
-    Path++;\r
+    Path+=2;\r
   }\r
 \r
   //\r
@@ -2201,8 +2646,10 @@ 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
     }\r
     ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
     StrnCatGrow(&Path2, &Path2Size, Path, 0);\r
@@ -2211,7 +2658,7 @@ EfiShellOpenFileList(
     StrnCatGrow(&Path2, NULL, Path, 0);\r
   }\r
 \r
-  CleanPath (Path2);\r
+  PathCleanUpDirectories (Path2);\r
 \r
   //\r
   // do the search\r
@@ -2224,6 +2671,7 @@ EfiShellOpenFileList(
     return (Status);\r
   }\r
 \r
+  Found = FALSE;\r
   //\r
   // We had no errors so open all the files (that are not already opened...)\r
   //\r
@@ -2233,47 +2681,48 @@ EfiShellOpenFileList(
      ){\r
     if (ShellFileListItem->Status == 0 && ShellFileListItem->Handle == NULL) {\r
       ShellFileListItem->Status = EfiShellOpenFileByName (ShellFileListItem->FullName, &ShellFileListItem->Handle, OpenMode);\r
+      Found = TRUE;\r
     }\r
   }\r
 \r
+  if (!Found) {\r
+    return (EFI_NOT_FOUND);\r
+  }\r
   return(EFI_SUCCESS);\r
 }\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
@@ -2281,21 +2730,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
@@ -2305,54 +2746,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
@@ -2362,6 +2808,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
@@ -2373,23 +2851,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
@@ -2451,6 +2941,11 @@ EfiShellSetEnv(
         gUnicodeCollation,\r
         (CHAR16*)Name,\r
         L"uefiversion") == 0\r
+    ||(!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest &&\r
+      gUnicodeCollation->StriColl(\r
+        gUnicodeCollation,\r
+        (CHAR16*)Name,\r
+        (CHAR16*)mNoNestingEnvVarName) == 0)\r
        ){\r
     return (EFI_INVALID_PARAMETER);\r
   }\r
@@ -2465,6 +2960,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
@@ -2520,6 +3017,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
@@ -2559,7 +3058,7 @@ EfiShellSetCurDir(
   DirectoryName = StrnCatGrow(&DirectoryName, NULL, Dir, 0);\r
   ASSERT(DirectoryName != NULL);\r
 \r
-  CleanPath(DirectoryName);\r
+  PathCleanUpDirectories(DirectoryName);\r
 \r
   if (FileSystem == NULL) {\r
     //\r
@@ -2587,6 +3086,8 @@ EfiShellSetCurDir(
     }\r
 \r
     if (MapListItem == NULL) {\r
+      FreePool (DirectoryName);\r
+      SHELL_FREE_NON_NULL(MapName);\r
       return (EFI_NOT_FOUND);\r
     }\r
 \r
@@ -2603,19 +3104,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
@@ -2623,6 +3128,7 @@ EfiShellSetCurDir(
     //\r
     MapListItem = ShellCommandFindMapItem(FileSystem);\r
     if (MapListItem == NULL) {\r
+      FreePool (DirectoryName);\r
       return (EFI_INVALID_PARAMETER);\r
     }\r
 //    gShellCurDir = MapListItem;\r
@@ -2641,12 +3147,13 @@ 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[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
@@ -2697,15 +3204,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
@@ -2753,25 +3284,20 @@ EfiShellIsRootShell(
   @return !NULL   a list of all alias'\r
 **/\r
 CHAR16 *\r
-EFIAPI\r
 InternalEfiShellGetListAlias(\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
-  CHAR16            *Alias;\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
@@ -2782,27 +3308,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
-    }\r
-    ASSERT_EFI_ERROR(Status);\r
-    if (EFI_ERROR(Status)) {\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
+    \r
+    if (EFI_ERROR (Status)) {\r
+      SHELL_FREE_NON_NULL(RetVal);\r
+      RetVal = NULL;\r
       break;\r
     }\r
+    \r
     if (CompareGuid(&Guid, &gShellAliasGuid)){\r
-      Alias = GetVariable(VariableName, &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
@@ -2832,22 +3396,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
@@ -2856,6 +3432,7 @@ EfiShellGetAlias(
       *Volatile = TRUE;\r
     }\r
 \r
+    FreePool (AliasLower);\r
     return (AddBufferToFreeList(RetVal));\r
   }\r
   return (AddBufferToFreeList(InternalEfiShellGetListAlias()));\r
@@ -2878,31 +3455,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
@@ -2924,6 +3519,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
@@ -2934,21 +3530,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
@@ -2995,7 +3594,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
@@ -3006,14 +3611,13 @@ EFI_SHELL_PROTOCOL         mShellProtocol = {
 \r
   This must be removed via calling CleanUpShellProtocol().\r
 \r
-  @param[in,out] NewShell   The pointer to the pointer to the structure\r
+  @param[in, out] NewShell   The pointer to the pointer to the structure\r
   to install.\r
 \r
   @retval EFI_SUCCESS     The operation was successful.\r
   @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
@@ -3023,6 +3627,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
@@ -3074,20 +3679,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
@@ -3135,43 +3747,55 @@ CreatePopulateInstallShellProtocol (
   Free all memory and restore the system to the state it was in before calling\r
   CreatePopulateInstallShellProtocol.\r
 \r
-  @param[in,out] NewShell   The pointer to the new shell protocol structure.\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
-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
@@ -3183,9 +3807,16 @@ CleanUpShellProtocol (
     NULL,\r
     EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
 \r
-  Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle1);\r
-  Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle2);\r
-\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle1);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle2);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle3);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle4);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle1);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle2);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle3);\r
+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle4);\r
+  }\r
   return (Status);\r
 }\r
 \r
@@ -3202,10 +3833,20 @@ NotificationFunction(
   IN EFI_KEY_DATA *KeyData\r
   )\r
 {\r
-  if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
-    return (EFI_UNSUPPORTED);\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
+    ShellInfoObject.HaltOutput = TRUE;\r
   }\r
-  return (gBS->SignalEvent(ShellInfoObject.NewEfiShellProtocol->ExecutionBreak));\r
+  return (EFI_SUCCESS);\r
 }\r
 \r
 /**\r
@@ -3216,7 +3857,6 @@ NotificationFunction(
   @retval EFI_OUT_OF_RESOURCES  There is not enough mnemory available.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 InernalEfiShellStartMonitor(\r
   VOID\r
   )\r
@@ -3284,3 +3924,4 @@ InernalEfiShellStartMonitor(
   }\r
   return (Status);\r
 }\r
+\r