hikey: Add UEFI sources for reference

UEFI needs to be built outside Android build system.
Please follow the instructions in README.

The sources correspond to:
https://github.com/96boards/edk2/commit/14eae0c12e71fd33c4c0fc51e4475e8db02566cf
https://github.com/96boards/arm-trusted-firmware/commit/e9b4909dcd75fc4ae7041cfb83d28ab9adb7afdf
https://github.com/96boards/l-loader/commit/6b784ad5c4ab00e2b1c6f53cd5f74054e5d00a78
https://git.linaro.org/uefi/uefi-tools.git/commit/abe618f8ab72034fff1ce46c9c006a2c6bd40a7e

Change-Id: Ieeefdb63e673e0c8e64e0a1f02c7bddc63b2c7fb
Signed-off-by: Vishal Bhoj <vishal.bhoj@linaro.org>
diff --git a/uefi/linaro-edk2/ShellPkg/Application/Shell/ShellProtocol.c b/uefi/linaro-edk2/ShellPkg/Application/Shell/ShellProtocol.c
new file mode 100644
index 0000000..6fc5668
--- /dev/null
+++ b/uefi/linaro-edk2/ShellPkg/Application/Shell/ShellProtocol.c
@@ -0,0 +1,3704 @@
+/** @file

+  Member functions of EFI_SHELL_PROTOCOL and functions for creation,

+  manipulation, and initialization of EFI_SHELL_PROTOCOL.

+

+  (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>

+  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>

+  This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include "Shell.h"

+

+/**

+  Close an open file handle.

+

+  This function closes a specified file handle. All "dirty" cached file data is

+  flushed to the device, and the file is closed. In all cases the handle is

+  closed.

+

+  @param[in] FileHandle           The file handle to close.

+

+  @retval EFI_SUCCESS             The file handle was closed successfully.

+**/

+EFI_STATUS

+EFIAPI

+EfiShellClose (

+  IN SHELL_FILE_HANDLE            FileHandle

+  )

+{

+  ShellFileHandleRemove(FileHandle);

+  return (FileHandleClose(ConvertShellHandleToEfiFileProtocol(FileHandle)));

+}

+

+/**

+  Internal worker to determine whether there is a BlockIo somewhere

+  upon the device path specified.

+

+  @param[in] DevicePath    The device path to test.

+

+  @retval TRUE      gEfiBlockIoProtocolGuid was installed on a handle with this device path

+  @retval FALSE     gEfiBlockIoProtocolGuid was not found.

+**/

+BOOLEAN

+EFIAPI

+InternalShellProtocolIsBlockIoPresent(

+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath

+  )

+{

+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathCopy;

+  EFI_STATUS                Status;

+  EFI_HANDLE                Handle;

+

+  Handle = NULL;

+

+  DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath;

+  Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid, &DevicePathCopy, &Handle);

+

+  if ((Handle != NULL) && (!EFI_ERROR(Status))) {

+    return (TRUE);

+  }

+  return (FALSE);

+}

+

+/**

+  Internal worker to determine whether there is a file system somewhere

+  upon the device path specified.

+

+  @param[in] DevicePath    The device path to test.

+

+  @retval TRUE      gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path

+  @retval FALSE     gEfiSimpleFileSystemProtocolGuid was not found.

+**/

+BOOLEAN

+EFIAPI

+InternalShellProtocolIsSimpleFileSystemPresent(

+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath

+  )

+{

+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathCopy;

+  EFI_STATUS                Status;

+  EFI_HANDLE                Handle;

+

+  Handle = NULL;

+

+  DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath;

+  Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);

+

+  if ((Handle != NULL) && (!EFI_ERROR(Status))) {

+    return (TRUE);

+  }

+  return (FALSE);

+}

+

+/**

+  Internal worker debug helper function to print out maps as they are added.

+

+  @param[in] Mapping        string mapping that has been added

+  @param[in] DevicePath     pointer to device path that has been mapped.

+

+  @retval EFI_SUCCESS   the operation was successful.

+  @return other         an error ocurred

+

+  @sa LocateHandle

+  @sa OpenProtocol

+**/

+EFI_STATUS

+EFIAPI

+InternalShellProtocolDebugPrintMessage (

+  IN CONST CHAR16                   *Mapping,

+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath

+  )

+{

+  EFI_STATUS                        Status;

+  CHAR16                            *Temp;

+

+  Status = EFI_SUCCESS;

+  DEBUG_CODE_BEGIN();

+

+  if (Mapping != NULL) {

+    DEBUG((EFI_D_INFO, "Added new map item:\"%S\"\r\n", Mapping));

+  }

+  Temp = ConvertDevicePathToText(DevicePath, TRUE, TRUE);

+  DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp));

+  FreePool(Temp);

+

+  DEBUG_CODE_END();

+  return (Status);

+}

+

+/**

+  This function creates a mapping for a device path.

+

+  If both DeviecPath and Mapping are NULL, this will reset the mapping to default values.

+

+  @param DevicePath             Points to the device path. If this is NULL and Mapping points to a valid mapping,

+                                then the mapping will be deleted.

+  @param Mapping                Points to the NULL-terminated mapping for the device path.  Must end with a ':'

+

+  @retval EFI_SUCCESS           Mapping created or deleted successfully.

+  @retval EFI_NO_MAPPING        There is no handle that corresponds exactly to DevicePath. See the

+                                boot service function LocateDevicePath().

+  @retval EFI_ACCESS_DENIED     The mapping is a built-in alias.

+  @retval EFI_INVALID_PARAMETER Mapping was NULL

+  @retval EFI_INVALID_PARAMETER Mapping did not end with a ':'

+  @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed.

+  @retval EFI_NOT_FOUND         There was no mapping found to delete

+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed

+**/

+EFI_STATUS

+EFIAPI

+EfiShellSetMap(

+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,

+  IN CONST CHAR16 *Mapping

+  )

+{

+  EFI_STATUS      Status;

+  SHELL_MAP_LIST  *MapListNode;

+

+  if (Mapping == NULL){

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  if (Mapping[StrLen(Mapping)-1] != ':') {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  //

+  // Delete the mapping

+  //

+  if (DevicePath == NULL) {

+    if (IsListEmpty(&gShellMapList.Link)) {

+      return (EFI_NOT_FOUND);

+    }

+    for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)

+        ; !IsNull(&gShellMapList.Link, &MapListNode->Link)

+        ; MapListNode = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListNode->Link)

+       ){

+          if (StringNoCaseCompare(&MapListNode->MapName, &Mapping) == 0) {

+            RemoveEntryList(&MapListNode->Link);

+            FreePool(MapListNode);

+            return (EFI_SUCCESS);

+          }

+    } // for loop

+

+    //

+    // We didnt find one to delete

+    //

+    return (EFI_NOT_FOUND);

+  }

+

+  //

+  // make sure this is a valid to add device path

+  //

+  ///@todo add BlockIo to this test...

+  if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath)

+    && !InternalShellProtocolIsBlockIoPresent(DevicePath)) {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  //

+  // First make sure there is no old mapping

+  //

+  Status = EfiShellSetMap(NULL, Mapping);

+  if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_FOUND)) {

+    return (Status);

+  }

+

+  //

+  // now add the new one.

+  //

+  Status = ShellCommandAddMapItemAndUpdatePath(Mapping, DevicePath, 0, FALSE);

+

+  return(Status);

+}

+

+/**

+  Gets the device path from the mapping.

+

+  This function gets the device path associated with a mapping.

+

+  @param Mapping                A pointer to the mapping

+

+  @retval !=NULL                Pointer to the device path that corresponds to the

+                                device mapping. The returned pointer does not need

+                                to be freed.

+  @retval NULL                  There is no device path associated with the

+                                specified mapping.

+**/

+CONST EFI_DEVICE_PATH_PROTOCOL *

+EFIAPI

+EfiShellGetDevicePathFromMap(

+  IN CONST CHAR16 *Mapping

+  )

+{

+  SHELL_MAP_LIST  *MapListItem;

+  CHAR16          *NewName;

+  UINTN           Size;

+

+  NewName = NULL;

+  Size    = 0;

+

+  StrnCatGrow(&NewName, &Size, Mapping, 0);

+  if (Mapping[StrLen(Mapping)-1] != L':') {

+    StrnCatGrow(&NewName, &Size, L":", 0);

+  }

+

+  MapListItem = ShellCommandFindMapItem(NewName);

+

+  FreePool(NewName);

+

+  if (MapListItem != NULL) {

+    return (MapListItem->DevicePath);

+  }

+  return(NULL);

+}

+

+/**

+  Gets the mapping(s) that most closely matches the device path.

+

+  This function gets the mapping which corresponds to the device path *DevicePath. If

+  there is no exact match, then the mapping which most closely matches *DevicePath

+  is returned, and *DevicePath is updated to point to the remaining portion of the

+  device path. If there is an exact match, the mapping is returned and *DevicePath

+  points to the end-of-device-path node.

+

+  If there are multiple map names they will be semi-colon seperated in the

+  NULL-terminated string.

+

+  @param DevicePath             On entry, points to a device path pointer. On

+                                exit, updates the pointer to point to the

+                                portion of the device path after the mapping.

+

+  @retval NULL                  No mapping was found.

+  @return !=NULL                Pointer to NULL-terminated mapping. The buffer

+                                is callee allocated and should be freed by the caller.

+**/

+CONST CHAR16 *

+EFIAPI

+EfiShellGetMapFromDevicePath(

+  IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath

+  )

+{

+  SHELL_MAP_LIST              *Node;

+  CHAR16                      *PathForReturn;

+  UINTN                       PathSize;

+//  EFI_HANDLE                  PathHandle;

+//  EFI_HANDLE                  MapHandle;

+//  EFI_STATUS                  Status;

+//  EFI_DEVICE_PATH_PROTOCOL    *DevicePathCopy;

+//  EFI_DEVICE_PATH_PROTOCOL    *MapPathCopy;

+

+  if (DevicePath == NULL || *DevicePath == NULL) {

+    return (NULL);

+  }

+

+  PathForReturn = NULL;

+  PathSize      = 0;

+

+  for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)

+      ; !IsNull(&gShellMapList.Link, &Node->Link)

+      ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)

+     ){

+    //

+    // check for exact match

+    //

+    if (DevicePathCompare(DevicePath, &Node->DevicePath) == 0) {

+      ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));

+      if (PathSize != 0) {

+        PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);

+      }

+      PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);

+    }

+  }

+  if (PathForReturn != NULL) {

+    while (!IsDevicePathEndType (*DevicePath)) {

+      *DevicePath = NextDevicePathNode (*DevicePath);

+    }

+    SetDevicePathEndNode (*DevicePath);

+  }

+/*

+  ///@todo finish code for inexact matches.

+  if (PathForReturn == NULL) {

+    PathSize = 0;

+

+    DevicePathCopy = DuplicateDevicePath(*DevicePath);

+    ASSERT(DevicePathCopy != NULL);

+    Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);

+    ASSERT_EFI_ERROR(Status);

+    //

+    //  check each of the device paths we have to get the root of the path for consist mappings

+    //

+    for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)

+        ; !IsNull(&gShellMapList.Link, &Node->Link)

+        ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)

+       ){

+      if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) {

+        continue;

+      }

+      MapPathCopy = DuplicateDevicePath(Node->DevicePath);

+      ASSERT(MapPathCopy != NULL);

+      Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);

+      if (MapHandle == PathHandle) {

+

+        *DevicePath = DevicePathCopy;

+

+        MapPathCopy = NULL;

+        DevicePathCopy = NULL;

+        PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);

+        PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);

+        break;

+      }

+    }

+    //

+    // now add on the non-consistent mappings

+    //

+    for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)

+        ; !IsNull(&gShellMapList.Link, &Node->Link)

+        ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)

+       ){

+      if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) {

+        continue;

+      }

+      MapPathCopy = Node->DevicePath;

+      ASSERT(MapPathCopy != NULL);

+      Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);

+      if (MapHandle == PathHandle) {

+        PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);

+        PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);

+        break;

+      }

+    }

+  }

+*/

+

+  return (AddBufferToFreeList(PathForReturn));

+}

+

+/**

+  Converts a device path to a file system-style path.

+

+  This function converts a device path to a file system path by replacing part, or all, of

+  the device path with the file-system mapping. If there are more than one application

+  file system mappings, the one that most closely matches Path will be used.

+

+  @param Path                   The pointer to the device path

+

+  @retval NULL                  the device path could not be found.

+  @return all                   The pointer of the NULL-terminated file path. The path

+                                is callee-allocated and should be freed by the caller.

+**/

+CHAR16 *

+EFIAPI

+EfiShellGetFilePathFromDevicePath(

+  IN CONST EFI_DEVICE_PATH_PROTOCOL *Path

+  )

+{

+  EFI_DEVICE_PATH_PROTOCOL  *DevicePathCopy;

+  EFI_DEVICE_PATH_PROTOCOL        *MapPathCopy;

+  SHELL_MAP_LIST                  *MapListItem;

+  CHAR16                          *PathForReturn;

+  UINTN                           PathSize;

+  EFI_HANDLE                      PathHandle;

+  EFI_HANDLE                      MapHandle;

+  EFI_STATUS                      Status;

+  FILEPATH_DEVICE_PATH            *FilePath;

+  FILEPATH_DEVICE_PATH            *AlignedNode;

+

+  PathForReturn = NULL;

+  PathSize = 0;

+

+  DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)Path;

+  ASSERT(DevicePathCopy != NULL);

+  if (DevicePathCopy == NULL) {

+    return (NULL);

+  }

+  ///@todo BlockIo?

+  Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);

+

+  if (EFI_ERROR(Status)) {

+    return (NULL);

+  }

+  //

+  //  check each of the device paths we have to get the root of the path

+  //

+  for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)

+      ; !IsNull(&gShellMapList.Link, &MapListItem->Link)

+      ; MapListItem = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListItem->Link)

+     ){

+    MapPathCopy = (EFI_DEVICE_PATH_PROTOCOL*)MapListItem->DevicePath;

+    ASSERT(MapPathCopy != NULL);

+    ///@todo BlockIo?

+    Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);

+    if (MapHandle == PathHandle) {

+      ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));

+      PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, MapListItem->MapName, 0);

+      //

+      // go through all the remaining nodes in the device path

+      //

+      for ( FilePath = (FILEPATH_DEVICE_PATH*)DevicePathCopy

+          ; !IsDevicePathEnd (&FilePath->Header)

+          ; FilePath = (FILEPATH_DEVICE_PATH*)NextDevicePathNode (&FilePath->Header)

+         ){

+        //

+        // all the rest should be file path nodes

+        //

+        if ((DevicePathType(&FilePath->Header) != MEDIA_DEVICE_PATH) ||

+            (DevicePathSubType(&FilePath->Header) != MEDIA_FILEPATH_DP)) {

+          FreePool(PathForReturn);

+          PathForReturn = NULL;

+          ASSERT(FALSE);

+        } else {

+          //

+          // append the path part onto the filepath.

+          //

+          ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));

+

+          AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath);

+          ASSERT (AlignedNode != NULL);

+

+          // File Path Device Path Nodes 'can optionally add a "\" separator to

+          //  the beginning and/or the end of the Path Name string.'

+          // (UEFI Spec 2.4 section 9.3.6.4).

+          // If necessary, add a "\", but otherwise don't

+          // (This is specified in the above section, and also implied by the

+          //  UEFI Shell spec section 3.7)

+          if ((PathSize != 0)                        &&

+              (PathForReturn != NULL)                &&

+              (PathForReturn[PathSize - 1] != L'\\') &&

+              (AlignedNode->PathName[0]    != L'\\')) {

+            PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1);

+          }

+

+          PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0);

+          FreePool(AlignedNode);

+        }

+      } // for loop of remaining nodes

+    }

+    if (PathForReturn != NULL) {

+      break;

+    }

+  } // for loop of paths to check

+  return(PathForReturn);

+}

+

+/**

+  Converts a file system style name to a device path.

+

+  This function converts a file system style name to a device path, by replacing any

+  mapping references to the associated device path.

+

+  @param[in] Path               The pointer to the path.

+

+  @return                       The pointer of the file path. The file path is callee

+                                allocated and should be freed by the caller.

+  @retval NULL                  The path could not be found.

+  @retval NULL                  There was not enough available memory.

+**/

+EFI_DEVICE_PATH_PROTOCOL *

+EFIAPI

+EfiShellGetDevicePathFromFilePath(

+  IN CONST CHAR16 *Path

+  )

+{

+  CHAR16                          *MapName;

+  CHAR16                          *NewPath;

+  CONST CHAR16                    *Cwd;

+  UINTN                           Size;

+  CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath;

+  EFI_DEVICE_PATH_PROTOCOL        *DevicePathCopy;

+  EFI_DEVICE_PATH_PROTOCOL        *DevicePathCopyForFree;

+  EFI_DEVICE_PATH_PROTOCOL        *DevicePathForReturn;

+  EFI_HANDLE                      Handle;

+  EFI_STATUS                      Status;

+

+  if (Path == NULL) {

+    return (NULL);

+  }

+

+  MapName = NULL;

+  NewPath = NULL;

+

+  if (StrStr(Path, L":") == NULL) {

+    Cwd = EfiShellGetCurDir(NULL);

+    if (Cwd == NULL) {

+      return (NULL);

+    }

+    Size = StrSize(Cwd) + StrSize(Path) - sizeof(CHAR16);

+    NewPath = AllocateZeroPool(Size);

+    if (NewPath == NULL) {

+      return (NULL);

+    }

+    StrnCpy(NewPath, Cwd, Size/sizeof(CHAR16)-1);

+    if (*Path == L'\\') {

+      Path++;

+      while (PathRemoveLastItem(NewPath)) ;

+    }

+    StrnCat(NewPath, Path, Size/sizeof(CHAR16) - 1 - StrLen(NewPath));

+    DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath);

+    FreePool(NewPath);

+    return (DevicePathForReturn);

+  }

+

+  Size = 0;

+  //

+  // find the part before (but including) the : for the map name

+  //

+  ASSERT((MapName == NULL && Size == 0) || (MapName != NULL));

+  MapName = StrnCatGrow(&MapName, &Size, Path, (StrStr(Path, L":")-Path+1));

+  if (MapName == NULL || MapName[StrLen(MapName)-1] != L':') {

+    return (NULL);

+  }

+

+  //

+  // look up the device path in the map

+  //

+  DevicePath = EfiShellGetDevicePathFromMap(MapName);

+  if (DevicePath == NULL) {

+    //

+    // Must have been a bad Mapname

+    //

+    return (NULL);

+  }

+

+  //

+  // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with)

+  //

+  DevicePathCopyForFree = DevicePathCopy = DuplicateDevicePath(DevicePath);

+  if (DevicePathCopy == NULL) {

+    FreePool(MapName);

+    return (NULL);

+  }

+

+  //

+  // get the handle

+  //

+  ///@todo BlockIo?

+  Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);

+  if (EFI_ERROR(Status)) {

+    if (DevicePathCopyForFree != NULL) {

+      FreePool(DevicePathCopyForFree);

+    }

+    FreePool(MapName);

+    return (NULL);

+  }

+

+  //

+  // build the full device path

+  //

+  if (*(Path+StrLen(MapName)+1) == CHAR_NULL) {

+    DevicePathForReturn = FileDevicePath(Handle, L"\\");

+  } else {

+    DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName));

+  }

+

+  FreePool(MapName);

+  if (DevicePathCopyForFree != NULL) {

+    FreePool(DevicePathCopyForFree);

+  }

+

+  return (DevicePathForReturn);

+}

+

+/**

+  Gets the name of the device specified by the device handle.

+

+  This function gets the user-readable name of the device specified by the device

+  handle. If no user-readable name could be generated, then *BestDeviceName will be

+  NULL and EFI_NOT_FOUND will be returned.

+

+  If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the

+  device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on

+  DeviceHandle.

+

+  If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the

+  device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle.

+  If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and

+  EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then

+  EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority.

+

+  @param DeviceHandle           The handle of the device.

+  @param Flags                  Determines the possible sources of component names.

+                                Valid bits are:

+                                  EFI_DEVICE_NAME_USE_COMPONENT_NAME

+                                  EFI_DEVICE_NAME_USE_DEVICE_PATH

+  @param Language               A pointer to the language specified for the device

+                                name, in the same format as described in the UEFI

+                                specification, Appendix M

+  @param BestDeviceName         On return, points to the callee-allocated NULL-

+                                terminated name of the device. If no device name

+                                could be found, points to NULL. The name must be

+                                freed by the caller...

+

+  @retval EFI_SUCCESS           Get the name successfully.

+  @retval EFI_NOT_FOUND         Fail to get the device name.

+  @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set.

+  @retval EFI_INVALID_PARAMETER BestDeviceName was NULL

+  @retval EFI_INVALID_PARAMETER DeviceHandle was NULL

+**/

+EFI_STATUS

+EFIAPI

+EfiShellGetDeviceName(

+  IN EFI_HANDLE DeviceHandle,

+  IN EFI_SHELL_DEVICE_NAME_FLAGS Flags,

+  IN CHAR8 *Language,

+  OUT CHAR16 **BestDeviceName

+  )

+{

+  EFI_STATUS                        Status;

+  EFI_COMPONENT_NAME2_PROTOCOL      *CompName2;

+  EFI_DEVICE_PATH_PROTOCOL          *DevicePath;

+  EFI_HANDLE                        *HandleList;

+  UINTN                             HandleCount;

+  UINTN                             LoopVar;

+  CHAR16                            *DeviceNameToReturn;

+  CHAR8                             *Lang;

+  UINTN                             ParentControllerCount;

+  EFI_HANDLE                        *ParentControllerBuffer;

+  UINTN                             ParentDriverCount;

+  EFI_HANDLE                        *ParentDriverBuffer;

+

+  if (BestDeviceName == NULL ||

+      DeviceHandle   == NULL

+     ){

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  //

+  // make sure one of the 2 supported bits is on

+  //

+  if (((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) == 0) &&

+      ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) == 0)) {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  DeviceNameToReturn  = NULL;

+  *BestDeviceName     = NULL;

+  HandleList          = NULL;

+  HandleCount         = 0;

+  Lang                = NULL;

+

+  if ((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) != 0) {

+    Status = ParseHandleDatabaseByRelationship(

+      NULL,

+      DeviceHandle,

+      HR_DRIVER_BINDING_HANDLE|HR_DEVICE_DRIVER,

+      &HandleCount,

+      &HandleList);

+    for (LoopVar = 0; LoopVar < HandleCount ; LoopVar++){

+      //

+      // Go through those handles until we get one that passes for GetComponentName

+      //

+      Status = gBS->OpenProtocol(

+        HandleList[LoopVar],

+        &gEfiComponentName2ProtocolGuid,

+        (VOID**)&CompName2,

+        gImageHandle,

+        NULL,

+        EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+      if (EFI_ERROR(Status)) {

+        Status = gBS->OpenProtocol(

+          HandleList[LoopVar],

+          &gEfiComponentNameProtocolGuid,

+          (VOID**)&CompName2,

+          gImageHandle,

+          NULL,

+          EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+      }

+

+      if (EFI_ERROR(Status)) {

+        continue;

+      }

+      Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);

+      Status = CompName2->GetControllerName(CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn);

+      FreePool(Lang);

+      Lang = NULL;

+      if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {

+        break;

+      }

+    }

+    if (HandleList != NULL) {

+      FreePool(HandleList);

+    }

+

+    //

+    // Now check the parent controller using this as the child.

+    //

+    if (DeviceNameToReturn == NULL){

+      PARSE_HANDLE_DATABASE_PARENTS(DeviceHandle, &ParentControllerCount, &ParentControllerBuffer);

+      for (LoopVar = 0 ; LoopVar < ParentControllerCount ; LoopVar++) {

+        PARSE_HANDLE_DATABASE_UEFI_DRIVERS(ParentControllerBuffer[LoopVar], &ParentDriverCount, &ParentDriverBuffer);

+        for (HandleCount = 0 ; HandleCount < ParentDriverCount ; HandleCount++) {

+          //

+          // try using that driver's component name with controller and our driver as the child.

+          //

+          Status = gBS->OpenProtocol(

+            ParentDriverBuffer[HandleCount],

+            &gEfiComponentName2ProtocolGuid,

+            (VOID**)&CompName2,

+            gImageHandle,

+            NULL,

+            EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+          if (EFI_ERROR(Status)) {

+            Status = gBS->OpenProtocol(

+              ParentDriverBuffer[HandleCount],

+              &gEfiComponentNameProtocolGuid,

+              (VOID**)&CompName2,

+              gImageHandle,

+              NULL,

+              EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+          }

+

+          if (EFI_ERROR(Status)) {

+            continue;

+          }

+          Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);

+          Status = CompName2->GetControllerName(CompName2, ParentControllerBuffer[LoopVar], DeviceHandle, Lang, &DeviceNameToReturn);

+          FreePool(Lang);

+          Lang = NULL;

+          if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {

+            break;

+          }

+

+

+

+        }

+        SHELL_FREE_NON_NULL(ParentDriverBuffer);

+        if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {

+          break;

+        }

+      }

+      SHELL_FREE_NON_NULL(ParentControllerBuffer);

+    }

+    //

+    // dont return on fail since we will try device path if that bit is on

+    //

+    if (DeviceNameToReturn != NULL){

+      ASSERT(BestDeviceName != NULL);

+      StrnCatGrow(BestDeviceName, NULL, DeviceNameToReturn, 0);

+      return (EFI_SUCCESS);

+    }

+  }

+  if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) {

+    Status = gBS->OpenProtocol(

+      DeviceHandle,

+      &gEfiDevicePathProtocolGuid,

+      (VOID**)&DevicePath,

+      gImageHandle,

+      NULL,

+      EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+    if (!EFI_ERROR(Status)) {

+      //

+      // use device path to text on the device path

+      //

+      *BestDeviceName = ConvertDevicePathToText(DevicePath, TRUE, TRUE);

+      return (EFI_SUCCESS);

+    }

+  }

+  //

+  // none of the selected bits worked.

+  //

+  return (EFI_NOT_FOUND);

+}

+

+/**

+  Opens the root directory of a device on a handle

+

+  This function opens the root directory of a device and returns a file handle to it.

+

+  @param DeviceHandle           The handle of the device that contains the volume.

+  @param FileHandle             On exit, points to the file handle corresponding to the root directory on the

+                                device.

+

+  @retval EFI_SUCCESS           Root opened successfully.

+  @retval EFI_NOT_FOUND         EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory

+                                could not be opened.

+  @retval EFI_VOLUME_CORRUPTED  The data structures in the volume were corrupted.

+  @retval EFI_DEVICE_ERROR      The device had an error

+**/

+EFI_STATUS

+EFIAPI

+EfiShellOpenRootByHandle(

+  IN EFI_HANDLE DeviceHandle,

+  OUT SHELL_FILE_HANDLE *FileHandle

+  )

+{

+  EFI_STATUS                      Status;

+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;

+  EFI_FILE_PROTOCOL               *RealFileHandle;

+  EFI_DEVICE_PATH_PROTOCOL        *DevPath;

+

+  //

+  // get the simple file system interface

+  //

+  Status = gBS->OpenProtocol(DeviceHandle,

+                             &gEfiSimpleFileSystemProtocolGuid,

+                             (VOID**)&SimpleFileSystem,

+                             gImageHandle,

+                             NULL,

+                             EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+  if (EFI_ERROR(Status)) {

+    return (EFI_NOT_FOUND);

+  }

+

+  Status = gBS->OpenProtocol(DeviceHandle,

+                             &gEfiDevicePathProtocolGuid,

+                             (VOID**)&DevPath,

+                             gImageHandle,

+                             NULL,

+                             EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+  if (EFI_ERROR(Status)) {

+    return (EFI_NOT_FOUND);

+  }

+  //

+  // Open the root volume now...

+  //

+  Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &RealFileHandle);

+  *FileHandle = ConvertEfiFileProtocolToShellHandle(RealFileHandle, EfiShellGetMapFromDevicePath(&DevPath));

+  return (Status);

+}

+

+/**

+  Opens the root directory of a device.

+

+  This function opens the root directory of a device and returns a file handle to it.

+

+  @param DevicePath             Points to the device path corresponding to the device where the

+                                EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed.

+  @param FileHandle             On exit, points to the file handle corresponding to the root directory on the

+                                device.

+

+  @retval EFI_SUCCESS           Root opened successfully.

+  @retval EFI_NOT_FOUND         EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory

+                                could not be opened.

+  @retval EFI_VOLUME_CORRUPTED  The data structures in the volume were corrupted.

+  @retval EFI_DEVICE_ERROR      The device had an error

+  @retval EFI_INVALID_PARAMETER FileHandle is NULL.

+**/

+EFI_STATUS

+EFIAPI

+EfiShellOpenRoot(

+  IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,

+  OUT SHELL_FILE_HANDLE *FileHandle

+  )

+{

+  EFI_STATUS Status;

+  EFI_HANDLE Handle;

+

+  if (FileHandle == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  //

+  // find the handle of the device with that device handle and the file system

+  //

+  ///@todo BlockIo?

+  Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,

+                                 &DevicePath,

+                                 &Handle);

+  if (EFI_ERROR(Status)) {

+    return (EFI_NOT_FOUND);

+  }

+

+  return (EfiShellOpenRootByHandle(Handle, FileHandle));

+}

+

+/**

+  Returns whether any script files are currently being processed.

+

+  @retval TRUE                 There is at least one script file active.

+  @retval FALSE                No script files are active now.

+

+**/

+BOOLEAN

+EFIAPI

+EfiShellBatchIsActive (

+  VOID

+  )

+{

+  if (ShellCommandGetCurrentScriptFile() == NULL) {

+    return (FALSE);

+  }

+  return (TRUE);

+}

+

+/**

+  Worker function to open a file based on a device path.  this will open the root

+  of the volume and then traverse down to the file itself.

+

+  @param DevicePath               Device Path of the file.

+  @param FileHandle               Pointer to the file upon a successful return.

+  @param OpenMode                 mode to open file in.

+  @param Attributes               the File Attributes to use when creating a new file.

+

+  @retval EFI_SUCCESS             the file is open and FileHandle is valid

+  @retval EFI_UNSUPPORTED         the device path cotained non-path elements

+  @retval other                   an error ocurred.

+**/

+EFI_STATUS

+EFIAPI

+InternalOpenFileDevicePath(

+  IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath,

+  OUT SHELL_FILE_HANDLE           *FileHandle,

+  IN UINT64                       OpenMode,

+  IN UINT64                       Attributes OPTIONAL

+  )

+{

+  EFI_STATUS                      Status;

+  FILEPATH_DEVICE_PATH            *FilePathNode;

+  EFI_HANDLE                      Handle;

+  SHELL_FILE_HANDLE               ShellHandle;

+  EFI_FILE_PROTOCOL               *Handle1;

+  EFI_FILE_PROTOCOL               *Handle2;

+  FILEPATH_DEVICE_PATH            *AlignedNode;

+

+  if (FileHandle == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+  *FileHandle   = NULL;

+  Handle1       = NULL;

+  Handle2       = NULL;

+  Handle        = NULL;

+  ShellHandle   = NULL;

+  FilePathNode  = NULL;

+  AlignedNode   = NULL;

+

+  Status = EfiShellOpenRoot(DevicePath, &ShellHandle);

+

+  if (!EFI_ERROR(Status)) {

+    Handle1 = ConvertShellHandleToEfiFileProtocol(ShellHandle);

+    if (Handle1 != NULL) {

+      //

+      // chop off the begining part before the file system part...

+      //

+      ///@todo BlockIo?

+      Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,

+                                     &DevicePath,

+                                     &Handle);

+        if (!EFI_ERROR(Status)) {

+        //

+        // To access as a file system, the file path should only

+        // contain file path components.  Follow the file path nodes

+        // and find the target file

+        //

+        for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath

+            ; !IsDevicePathEnd (&FilePathNode->Header)

+            ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header)

+           ){

+          SHELL_FREE_NON_NULL(AlignedNode);

+          AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePathNode), FilePathNode);

+          //

+          // For file system access each node should be a file path component

+          //

+          if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||

+              DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP

+             ) {

+            Status = EFI_UNSUPPORTED;

+            break;

+          }

+

+          //

+          // Open this file path node

+          //

+          Handle2 = Handle1;

+          Handle1 = NULL;

+

+          //

+          // if this is the last node in the DevicePath always create (if that was requested).

+          //

+          if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) {

+            Status = Handle2->Open (

+                                  Handle2,

+                                  &Handle1,

+                                  AlignedNode->PathName,

+                                  OpenMode,

+                                  Attributes

+                                 );

+          } else {

+

+            //

+            //  This is not the last node and we dont want to 'create' existing

+            //  directory entries...

+            //

+

+            //

+            // open without letting it create

+            // prevents error on existing files/directories

+            //

+            Status = Handle2->Open (

+                                  Handle2,

+                                  &Handle1,

+                                  AlignedNode->PathName,

+                                  OpenMode &~EFI_FILE_MODE_CREATE,

+                                  Attributes

+                                 );

+            //

+            // if above failed now open and create the 'item'

+            // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)

+            //

+            if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {

+              Status = Handle2->Open (

+                                    Handle2,

+                                    &Handle1,

+                                    AlignedNode->PathName,

+                                    OpenMode,

+                                    Attributes

+                                   );

+            }

+          }

+          //

+          // Close the last node

+          //

+          ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle2);

+

+          //

+          // If there's been an error, stop

+          //

+          if (EFI_ERROR (Status)) {

+            break;

+          }

+        } // for loop

+      }

+    }

+  }

+  SHELL_FREE_NON_NULL(AlignedNode);

+  if (EFI_ERROR(Status)) {

+    if (Handle1 != NULL) {

+      ShellInfoObject.NewEfiShellProtocol->CloseFile(Handle1);

+    }

+  } else {

+    *FileHandle = ConvertEfiFileProtocolToShellHandle(Handle1, ShellFileHandleGetPath(ShellHandle));

+  }

+  return (Status);

+}

+

+/**

+  Creates a file or directory by name.

+

+  This function creates an empty new file or directory with the specified attributes and

+  returns the new file's handle. If the file already exists and is read-only, then

+  EFI_INVALID_PARAMETER will be returned.

+

+  If the file already existed, it is truncated and its attributes updated. If the file is

+  created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL.

+

+  If the file name begins with >v, then the file handle which is returned refers to the

+  shell environment variable with the specified name. If the shell environment variable

+  already exists and is non-volatile then EFI_INVALID_PARAMETER is returned.

+

+  @param FileName           Pointer to NULL-terminated file path

+  @param FileAttribs        The new file's attrbiutes.  the different attributes are

+                            described in EFI_FILE_PROTOCOL.Open().

+  @param FileHandle         On return, points to the created file handle or directory's handle

+

+  @retval EFI_SUCCESS       The file was opened.  FileHandle points to the new file's handle.

+  @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.

+  @retval EFI_UNSUPPORTED   could not open the file path

+  @retval EFI_NOT_FOUND     the specified file could not be found on the devide, or could not

+                            file the file system on the device.

+  @retval EFI_NO_MEDIA      the device has no medium.

+  @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no

+                            longer supported.

+  @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according

+                            the DirName.

+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.

+  @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write

+                            when the media is write-protected.

+  @retval EFI_ACCESS_DENIED The service denied access to the file.

+  @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.

+  @retval EFI_VOLUME_FULL   The volume is full.

+**/

+EFI_STATUS

+EFIAPI

+EfiShellCreateFile(

+  IN CONST CHAR16       *FileName,

+  IN UINT64             FileAttribs,

+  OUT SHELL_FILE_HANDLE *FileHandle

+  )

+{

+  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;

+  EFI_STATUS                Status;

+

+  //

+  // Is this for an environment variable

+  // do we start with >v

+  //

+  if (StrStr(FileName, L">v") == FileName) {

+    if (!IsVolatileEnv(FileName+2)) {

+      return (EFI_INVALID_PARAMETER);

+    }

+    *FileHandle = CreateFileInterfaceEnv(FileName+2);

+    return (EFI_SUCCESS);

+  }

+

+  //

+  // We are opening a regular file.

+  //

+  DevicePath = EfiShellGetDevicePathFromFilePath(FileName);

+  if (DevicePath == NULL) {

+    return (EFI_NOT_FOUND);

+  }

+

+  Status = InternalOpenFileDevicePath(DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs);

+  FreePool(DevicePath);

+

+  return(Status);

+}

+

+/**

+  Register a GUID and a localized human readable name for it.

+

+  If Guid is not assigned a name, then assign GuidName to Guid.  This list of GUID

+  names must be used whenever a shell command outputs GUID information.

+

+  This function is only available when the major and minor versions in the

+  EfiShellProtocol are greater than or equal to 2 and 1, respectively.

+

+  @param[in] Guid       A pointer to the GUID being registered.

+  @param[in] GuidName   A pointer to the localized name for the GUID being registered.

+

+  @retval EFI_SUCCESS             The operation was successful.

+  @retval EFI_INVALID_PARAMETER   Guid was NULL.

+  @retval EFI_INVALID_PARAMETER   GuidName was NULL.

+  @retval EFI_ACCESS_DENIED       Guid already is assigned a name.

+**/

+EFI_STATUS

+EFIAPI 

+EfiShellRegisterGuidName(

+  IN CONST EFI_GUID *Guid,

+  IN CONST CHAR16   *GuidName

+  )

+{

+  return (AddNewGuidNameMapping(Guid, GuidName, NULL));

+}

+

+/**

+  Opens a file or a directory by file name.

+

+  This function opens the specified file in the specified OpenMode and returns a file

+  handle.

+  If the file name begins with >v, then the file handle which is returned refers to the

+  shell environment variable with the specified name. If the shell environment variable

+  exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then

+  EFI_INVALID_PARAMETER is returned.

+

+  If the file name is >i, then the file handle which is returned refers to the standard

+  input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER

+  is returned.

+

+  If the file name is >o, then the file handle which is returned refers to the standard

+  output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER

+  is returned.

+

+  If the file name is >e, then the file handle which is returned refers to the standard

+  error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER

+  is returned.

+

+  If the file name is NUL, then the file handle that is returned refers to the standard NUL

+  file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is

+  returned.

+

+  If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the

+  FileHandle is NULL.

+

+  @param FileName               Points to the NULL-terminated UCS-2 encoded file name.

+  @param FileHandle             On return, points to the file handle.

+  @param OpenMode               File open mode. Either EFI_FILE_MODE_READ or

+                                EFI_FILE_MODE_WRITE from section 12.4 of the UEFI

+                                Specification.

+  @retval EFI_SUCCESS           The file was opened. FileHandle has the opened file's handle.

+  @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL.

+  @retval EFI_UNSUPPORTED       Could not open the file path. FileHandle is NULL.

+  @retval EFI_NOT_FOUND         The specified file could not be found on the device or the file

+                                system could not be found on the device. FileHandle is NULL.

+  @retval EFI_NO_MEDIA          The device has no medium. FileHandle is NULL.

+  @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the medium is no

+                                longer supported. FileHandle is NULL.

+  @retval EFI_DEVICE_ERROR      The device reported an error or can't get the file path according

+                                the FileName. FileHandle is NULL.

+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted. FileHandle is NULL.

+  @retval EFI_WRITE_PROTECTED   An attempt was made to create a file, or open a file for write

+                                when the media is write-protected. FileHandle is NULL.

+  @retval EFI_ACCESS_DENIED     The service denied access to the file. FileHandle is NULL.

+  @retval EFI_OUT_OF_RESOURCES  Not enough resources were available to open the file. FileHandle

+                                is NULL.

+  @retval EFI_VOLUME_FULL       The volume is full. FileHandle is NULL.

+**/

+EFI_STATUS

+EFIAPI

+EfiShellOpenFileByName(

+  IN CONST CHAR16       *FileName,

+  OUT SHELL_FILE_HANDLE *FileHandle,

+  IN UINT64             OpenMode

+  )

+{

+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;

+  EFI_STATUS                      Status;

+

+  *FileHandle = NULL;

+

+  //

+  // Is this for StdIn

+  //

+  if (StrCmp(FileName, L">i") == 0) {

+    //

+    // make sure not writing to StdIn

+    //

+    if ((OpenMode & EFI_FILE_MODE_WRITE) != 0) {

+      return (EFI_INVALID_PARAMETER);

+    }

+    *FileHandle = ShellInfoObject.NewShellParametersProtocol->StdIn;

+    ASSERT(*FileHandle != NULL);

+    return (EFI_SUCCESS);

+  }

+

+  //

+  // Is this for StdOut

+  //

+  if (StrCmp(FileName, L">o") == 0) {

+    //

+    // make sure not writing to StdIn

+    //

+    if ((OpenMode & EFI_FILE_MODE_READ) != 0) {

+      return (EFI_INVALID_PARAMETER);

+    }

+    *FileHandle = &FileInterfaceStdOut;

+    return (EFI_SUCCESS);

+  }

+

+  //

+  // Is this for NUL file

+  //

+  if (StrCmp(FileName, L"NUL") == 0) {

+    *FileHandle = &FileInterfaceNulFile;

+    return (EFI_SUCCESS);

+  }

+

+  //

+  // Is this for StdErr

+  //

+  if (StrCmp(FileName, L">e") == 0) {

+    //

+    // make sure not writing to StdIn

+    //

+    if ((OpenMode & EFI_FILE_MODE_READ) != 0) {

+      return (EFI_INVALID_PARAMETER);

+    }

+    *FileHandle = &FileInterfaceStdErr;

+    return (EFI_SUCCESS);

+  }

+

+  //

+  // Is this for an environment variable

+  // do we start with >v

+  //

+  if (StrStr(FileName, L">v") == FileName) {

+    if (!IsVolatileEnv(FileName+2) &&

+        ((OpenMode & EFI_FILE_MODE_WRITE) != 0)) {

+      return (EFI_INVALID_PARAMETER);

+    }

+    *FileHandle = CreateFileInterfaceEnv(FileName+2);

+    return (EFI_SUCCESS);

+  }

+

+  //

+  // We are opening a regular file.

+  //

+  DevicePath = EfiShellGetDevicePathFromFilePath(FileName);

+//  DEBUG_CODE(InternalShellProtocolDebugPrintMessage (NULL, DevicePath););

+  if (DevicePath == NULL) {

+    return (EFI_NOT_FOUND);

+  }

+

+  //

+  // Copy the device path, open the file, then free the memory

+  //

+  Status = InternalOpenFileDevicePath(DevicePath, FileHandle, OpenMode, 0); // 0 = no specific file attributes

+  FreePool(DevicePath);

+

+  return(Status);

+}

+

+/**

+  Deletes the file specified by the file name.

+

+  This function deletes a file.

+

+  @param FileName                 Points to the NULL-terminated file name.

+

+  @retval EFI_SUCCESS             The file was closed and deleted, and the handle was closed.

+  @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.

+  @sa EfiShellCreateFile

+**/

+EFI_STATUS

+EFIAPI

+EfiShellDeleteFileByName(

+  IN CONST CHAR16 *FileName

+  )

+{

+  SHELL_FILE_HANDLE FileHandle;

+  EFI_STATUS        Status;

+

+  FileHandle = NULL;

+

+  //

+  // get a handle to the file

+  //

+  Status = EfiShellCreateFile(FileName,

+                              0,

+                              &FileHandle);

+  if (EFI_ERROR(Status)) {

+    return (Status);

+  }

+  //

+  // now delete the file

+  //

+  return (ShellInfoObject.NewEfiShellProtocol->DeleteFile(FileHandle));

+}

+

+/**

+  Disables the page break output mode.

+**/

+VOID

+EFIAPI

+EfiShellDisablePageBreak (

+  VOID

+  )

+{

+  ShellInfoObject.PageBreakEnabled = FALSE;

+}

+

+/**

+  Enables the page break output mode.

+**/

+VOID

+EFIAPI

+EfiShellEnablePageBreak (

+  VOID

+  )

+{

+  ShellInfoObject.PageBreakEnabled = TRUE;

+}

+

+/**

+  internal worker function to load and run an image via device path.

+

+  @param ParentImageHandle      A handle of the image that is executing the specified

+                                command line.

+  @param DevicePath             device path of the file to execute

+  @param CommandLine            Points to the NULL-terminated UCS-2 encoded string

+                                containing the command line. If NULL then the command-

+                                line will be empty.

+  @param Environment            Points to a NULL-terminated array of environment

+                                variables with the format 'x=y', where x is the

+                                environment variable name and y is the value. If this

+                                is NULL, then the current shell environment is used.

+                            

+  @param[out] StartImageStatus  Returned status from gBS->StartImage.

+

+  @retval EFI_SUCCESS       The command executed successfully. The  status code

+                            returned by the command is pointed to by StatusCode.

+  @retval EFI_INVALID_PARAMETER The parameters are invalid.

+  @retval EFI_OUT_OF_RESOURCES Out of resources.

+  @retval EFI_UNSUPPORTED   Nested shell invocations are not allowed.

+**/

+EFI_STATUS

+EFIAPI

+InternalShellExecuteDevicePath(

+  IN CONST EFI_HANDLE               *ParentImageHandle,

+  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,

+  IN CONST CHAR16                   *CommandLine OPTIONAL,

+  IN CONST CHAR16                   **Environment OPTIONAL,

+  OUT EFI_STATUS                    *StartImageStatus OPTIONAL

+  )

+{

+  EFI_STATUS                    Status;

+  EFI_STATUS                    StartStatus;

+  EFI_STATUS                    CleanupStatus;

+  EFI_HANDLE                    NewHandle;

+  EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;

+  LIST_ENTRY                    OrigEnvs;

+  EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;

+  CHAR16                        *ImagePath;

+  UINTN                         Index;

+  CHAR16                        *Walker;

+  CHAR16                        *NewCmdLine;

+

+  if (ParentImageHandle == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  InitializeListHead(&OrigEnvs);

+

+  NewHandle = NULL;

+  

+  NewCmdLine = AllocateCopyPool (StrSize (CommandLine), CommandLine);

+  if (NewCmdLine == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {

+    if (*Walker == L'^' && *(Walker+1) == L'#') {

+      CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));

+    }

+  }

+

+  //

+  // Load the image with:

+  // FALSE - not from boot manager and NULL, 0 being not already in memory

+  //

+  Status = gBS->LoadImage(

+    FALSE,

+    *ParentImageHandle,

+    (EFI_DEVICE_PATH_PROTOCOL*)DevicePath,

+    NULL,

+    0,

+    &NewHandle);

+

+  if (EFI_ERROR(Status)) {

+    if (NewHandle != NULL) {

+      gBS->UnloadImage(NewHandle);

+    }

+    return (Status);

+  }

+  Status = gBS->OpenProtocol(

+    NewHandle,

+    &gEfiLoadedImageProtocolGuid,

+    (VOID**)&LoadedImage,

+    gImageHandle,

+    NULL,

+    EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+

+  if (!EFI_ERROR(Status)) {

+    ASSERT(LoadedImage->LoadOptionsSize == 0);

+    if (NewCmdLine != NULL) {

+      LoadedImage->LoadOptionsSize  = (UINT32)StrSize(NewCmdLine);

+      LoadedImage->LoadOptions      = (VOID*)NewCmdLine;

+    }

+

+    //

+    // Save our current environment settings for later restoration if necessary

+    //

+    if (Environment != NULL) {

+      Status = GetEnvironmentVariableList(&OrigEnvs);

+      if (!EFI_ERROR(Status)) {

+        Status = SetEnvironmentVariables(Environment);

+      }

+    }

+

+    //

+    // Initialize and install a shell parameters protocol on the image.

+    //

+    ShellParamsProtocol.StdIn   = ShellInfoObject.NewShellParametersProtocol->StdIn;

+    ShellParamsProtocol.StdOut  = ShellInfoObject.NewShellParametersProtocol->StdOut;

+    ShellParamsProtocol.StdErr  = ShellInfoObject.NewShellParametersProtocol->StdErr;

+    Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, NULL, NULL);

+    ASSERT_EFI_ERROR(Status);

+    //

+    // Replace Argv[0] with the full path of the binary we're executing:

+    // If the command line was "foo", the binary might be called "foo.efi".

+    // "The first entry in [Argv] is always the full file path of the

+    //  executable" - UEFI Shell Spec section 2.3

+    //

+    ImagePath = EfiShellGetFilePathFromDevicePath (DevicePath);

+    // The image we're executing isn't necessarily in a filesystem - it might

+    // be memory mapped. In this case EfiShellGetFilePathFromDevicePath will

+    // return NULL, and we'll leave Argv[0] as UpdateArgcArgv set it.

+    if (ImagePath != NULL) {

+      if (ShellParamsProtocol.Argv == NULL) {

+        // Command line was empty or null.

+        // (UpdateArgcArgv sets Argv to NULL when CommandLine is "" or NULL)

+        ShellParamsProtocol.Argv = AllocatePool (sizeof (CHAR16 *));

+        if (ShellParamsProtocol.Argv == NULL) {

+          Status = EFI_OUT_OF_RESOURCES;

+          goto UnloadImage;

+        }

+        ShellParamsProtocol.Argc = 1;

+      } else {

+        // Free the string UpdateArgcArgv put in Argv[0];

+        FreePool (ShellParamsProtocol.Argv[0]);

+      }

+      ShellParamsProtocol.Argv[0] = ImagePath;

+    }

+

+    Status = gBS->InstallProtocolInterface(&NewHandle, &gEfiShellParametersProtocolGuid, EFI_NATIVE_INTERFACE, &ShellParamsProtocol);

+    ASSERT_EFI_ERROR(Status);

+

+    ///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)

+

+    //

+    // now start the image and if the caller wanted the return code pass it to them...

+    //

+    if (!EFI_ERROR(Status)) {

+      StartStatus      = gBS->StartImage(

+                          NewHandle,

+                          0,

+                          NULL

+                          );

+      if (StartImageStatus != NULL) {

+        *StartImageStatus = StartStatus;

+      }

+

+      CleanupStatus = gBS->UninstallProtocolInterface(

+                            NewHandle,

+                            &gEfiShellParametersProtocolGuid,

+                            &ShellParamsProtocol

+                            );

+      ASSERT_EFI_ERROR(CleanupStatus);

+

+      goto FreeAlloc;

+    }

+

+UnloadImage:

+    // Unload image - We should only get here if we didn't call StartImage

+    gBS->UnloadImage (NewHandle);

+

+FreeAlloc:

+    // Free Argv (Allocated in UpdateArgcArgv)

+    if (ShellParamsProtocol.Argv != NULL) {

+      for (Index = 0; Index < ShellParamsProtocol.Argc; Index++) {

+        if (ShellParamsProtocol.Argv[Index] != NULL) {

+          FreePool (ShellParamsProtocol.Argv[Index]);

+        }

+      }

+      FreePool (ShellParamsProtocol.Argv);

+    }

+  }

+

+  // Restore environment variables

+  if (!IsListEmpty(&OrigEnvs)) {

+    CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);

+    ASSERT_EFI_ERROR (CleanupStatus);

+  }

+

+  FreePool (NewCmdLine);

+

+  return(Status);

+}

+/**

+  Execute the command line.

+

+  This function creates a nested instance of the shell and executes the specified

+  command (CommandLine) with the specified environment (Environment). Upon return,

+  the status code returned by the specified command is placed in StatusCode.

+

+  If Environment is NULL, then the current environment is used and all changes made

+  by the commands executed will be reflected in the current environment. If the

+  Environment is non-NULL, then the changes made will be discarded.

+

+  The CommandLine is executed from the current working directory on the current

+  device.

+

+  @param ParentImageHandle  A handle of the image that is executing the specified

+                            command line.

+  @param CommandLine        Points to the NULL-terminated UCS-2 encoded string

+                            containing the command line. If NULL then the command-

+                            line will be empty.

+  @param Environment        Points to a NULL-terminated array of environment

+                            variables with the format 'x=y', where x is the

+                            environment variable name and y is the value. If this

+                            is NULL, then the current shell environment is used.

+  @param StatusCode         Points to the status code returned by the command.

+

+  @retval EFI_SUCCESS       The command executed successfully. The  status code

+                            returned by the command is pointed to by StatusCode.

+  @retval EFI_INVALID_PARAMETER The parameters are invalid.

+  @retval EFI_OUT_OF_RESOURCES Out of resources.

+  @retval EFI_UNSUPPORTED   Nested shell invocations are not allowed.

+  @retval EFI_UNSUPPORTED   The support level required for this function is not present.

+

+  @sa InternalShellExecuteDevicePath

+**/

+EFI_STATUS

+EFIAPI

+EfiShellExecute(

+  IN EFI_HANDLE *ParentImageHandle,

+  IN CHAR16 *CommandLine OPTIONAL,

+  IN CHAR16 **Environment OPTIONAL,

+  OUT EFI_STATUS *StatusCode OPTIONAL

+  )

+{

+  EFI_STATUS                Status;

+  CHAR16                    *Temp;

+  EFI_DEVICE_PATH_PROTOCOL  *DevPath;

+  UINTN                     Size;

+

+  if ((PcdGet8(PcdShellSupportLevel) < 1)) {

+    return (EFI_UNSUPPORTED);

+  }

+

+  DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);

+

+  DEBUG_CODE_BEGIN();

+  Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);

+  FreePool(Temp);

+  Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);

+  FreePool(Temp);

+  Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE);

+  FreePool(Temp);

+  DEBUG_CODE_END();

+

+  Temp = NULL;

+  Size = 0;

+  ASSERT((Temp == NULL && Size == 0) || (Temp != NULL));

+  StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0);

+  StrnCatGrow(&Temp, &Size, CommandLine, 0);

+

+  Status = InternalShellExecuteDevicePath(

+    ParentImageHandle,

+    DevPath,

+    Temp,

+    (CONST CHAR16**)Environment,

+    StatusCode);

+

+  //

+  // de-allocate and return

+  //

+  FreePool(DevPath);

+  FreePool(Temp);

+  return(Status);

+}

+

+/**

+  Utility cleanup function for EFI_SHELL_FILE_INFO objects.

+

+  1) frees all pointers (non-NULL)

+  2) Closes the SHELL_FILE_HANDLE

+

+  @param FileListNode     pointer to the list node to free

+**/

+VOID

+EFIAPI

+InternalFreeShellFileInfoNode(

+  IN EFI_SHELL_FILE_INFO *FileListNode

+  )

+{

+  if (FileListNode->Info != NULL) {

+    FreePool((VOID*)FileListNode->Info);

+  }

+  if (FileListNode->FileName != NULL) {

+    FreePool((VOID*)FileListNode->FileName);

+  }

+  if (FileListNode->FullName != NULL) {

+    FreePool((VOID*)FileListNode->FullName);

+  }

+  if (FileListNode->Handle != NULL) {

+    ShellInfoObject.NewEfiShellProtocol->CloseFile(FileListNode->Handle);

+  }

+  FreePool(FileListNode);

+}

+/**

+  Frees the file list.

+

+  This function cleans up the file list and any related data structures. It has no

+  impact on the files themselves.

+

+  @param FileList               The file list to free. Type EFI_SHELL_FILE_INFO is

+                                defined in OpenFileList()

+

+  @retval EFI_SUCCESS           Free the file list successfully.

+  @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;

+**/

+EFI_STATUS

+EFIAPI

+EfiShellFreeFileList(

+  IN EFI_SHELL_FILE_INFO **FileList

+  )

+{

+  EFI_SHELL_FILE_INFO *ShellFileListItem;

+

+  if (FileList == NULL || *FileList == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)

+      ; !IsListEmpty(&(*FileList)->Link)

+      ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)

+     ){

+    RemoveEntryList(&ShellFileListItem->Link);

+    InternalFreeShellFileInfoNode(ShellFileListItem);

+  }

+  InternalFreeShellFileInfoNode(*FileList);

+  *FileList = NULL;

+  return(EFI_SUCCESS);

+}

+

+/**

+  Deletes the duplicate file names files in the given file list.

+

+  This function deletes the reduplicate files in the given file list.

+

+  @param FileList               A pointer to the first entry in the file list.

+

+  @retval EFI_SUCCESS           Always success.

+  @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;

+**/

+EFI_STATUS

+EFIAPI

+EfiShellRemoveDupInFileList(

+  IN EFI_SHELL_FILE_INFO **FileList

+  )

+{

+  EFI_SHELL_FILE_INFO *ShellFileListItem;

+  EFI_SHELL_FILE_INFO *ShellFileListItem2;

+  EFI_SHELL_FILE_INFO *TempNode;

+

+  if (FileList == NULL || *FileList == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+  for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)

+      ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link)

+      ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)

+     ){

+    for ( ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)

+        ; !IsNull(&(*FileList)->Link, &ShellFileListItem2->Link)

+        ; ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem2->Link)

+       ){

+      if (gUnicodeCollation->StriColl(

+            gUnicodeCollation,

+            (CHAR16*)ShellFileListItem->FullName,

+            (CHAR16*)ShellFileListItem2->FullName) == 0

+         ){

+        TempNode = (EFI_SHELL_FILE_INFO *)GetPreviousNode(

+                                            &(*FileList)->Link,

+                                            &ShellFileListItem2->Link

+                                            );

+        RemoveEntryList(&ShellFileListItem2->Link);

+        InternalFreeShellFileInfoNode(ShellFileListItem2);

+        // Set ShellFileListItem2 to PreviousNode so we don't access Freed

+        // memory in GetNextNode in the loop expression above.

+        ShellFileListItem2 = TempNode;

+      }

+    }

+  }

+  return (EFI_SUCCESS);

+}

+

+//

+// This is the same structure as the external version, but it has no CONST qualifiers.

+//

+typedef struct {

+  LIST_ENTRY        Link;       ///< Linked list members.

+  EFI_STATUS        Status;     ///< Status of opening the file.  Valid only if Handle != NULL.

+        CHAR16      *FullName;  ///< Fully qualified filename.

+        CHAR16      *FileName;  ///< name of this file.

+  SHELL_FILE_HANDLE Handle;     ///< Handle for interacting with the opened file or NULL if closed.

+  EFI_FILE_INFO     *Info;      ///< Pointer to the FileInfo struct for this file or NULL.

+} EFI_SHELL_FILE_INFO_NO_CONST;

+

+/**

+  Allocates and duplicates a EFI_SHELL_FILE_INFO node.

+

+  @param[in] Node     The node to copy from.

+  @param[in] Save     TRUE to set Node->Handle to NULL, FALSE otherwise.

+

+  @retval NULL        a memory allocation error ocurred

+  @return != NULL     a pointer to the new node

+**/

+EFI_SHELL_FILE_INFO*

+EFIAPI

+InternalDuplicateShellFileInfo(

+  IN       EFI_SHELL_FILE_INFO *Node,

+  IN BOOLEAN                   Save

+  )

+{

+  EFI_SHELL_FILE_INFO_NO_CONST *NewNode;

+

+  //

+  // try to confirm that the objects are in sync

+  //

+  ASSERT(sizeof(EFI_SHELL_FILE_INFO_NO_CONST) == sizeof(EFI_SHELL_FILE_INFO));

+

+  NewNode = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));

+  if (NewNode == NULL) {

+    return (NULL);

+  }

+  NewNode->FullName = AllocateCopyPool(StrSize(Node->FullName), Node->FullName);

+  NewNode->FileName = AllocateCopyPool(StrSize(Node->FileName), Node->FileName);

+  NewNode->Info     = AllocateCopyPool((UINTN)Node->Info->Size, Node->Info);

+  if ( NewNode->FullName == NULL

+    || NewNode->FileName == NULL

+    || NewNode->Info == NULL

+  ){

+    SHELL_FREE_NON_NULL(NewNode->FullName);

+    SHELL_FREE_NON_NULL(NewNode->FileName);

+    SHELL_FREE_NON_NULL(NewNode->Info);

+    SHELL_FREE_NON_NULL(NewNode);

+    return(NULL);

+  }

+  NewNode->Status = Node->Status;

+  NewNode->Handle = Node->Handle;

+  if (!Save) {

+    Node->Handle = NULL;

+  }

+

+  return((EFI_SHELL_FILE_INFO*)NewNode);

+}

+

+/**

+  Allocates and populates a EFI_SHELL_FILE_INFO structure.  if any memory operation

+  failed it will return NULL.

+

+  @param[in] BasePath         the Path to prepend onto filename for FullPath

+  @param[in] Status           Status member initial value.

+  @param[in] FileName         FileName member initial value.

+  @param[in] Handle           Handle member initial value.

+  @param[in] Info             Info struct to copy.

+

+  @retval NULL                An error ocurred.

+  @return                     a pointer to the newly allocated structure.

+**/

+EFI_SHELL_FILE_INFO *

+EFIAPI

+CreateAndPopulateShellFileInfo(

+  IN CONST CHAR16 *BasePath,

+  IN CONST EFI_STATUS Status,

+  IN CONST CHAR16 *FileName,

+  IN CONST SHELL_FILE_HANDLE Handle,

+  IN CONST EFI_FILE_INFO *Info

+  )

+{

+  EFI_SHELL_FILE_INFO *ShellFileListItem;

+  CHAR16              *TempString;

+  UINTN               Size;

+

+  TempString = NULL;

+  Size = 0;

+

+  ShellFileListItem = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));

+  if (ShellFileListItem == NULL) {

+    return (NULL);

+  }

+  if (Info != NULL && Info->Size != 0) {

+    ShellFileListItem->Info = AllocateZeroPool((UINTN)Info->Size);

+    if (ShellFileListItem->Info == NULL) {

+      FreePool(ShellFileListItem);

+      return (NULL);

+    }

+    CopyMem(ShellFileListItem->Info, Info, (UINTN)Info->Size);

+  } else {

+    ShellFileListItem->Info = NULL;

+  }

+  if (FileName != NULL) {

+    ASSERT(TempString == NULL);

+    ShellFileListItem->FileName = StrnCatGrow(&TempString, 0, FileName, 0);

+    if (ShellFileListItem->FileName == NULL) {

+      FreePool(ShellFileListItem->Info);

+      FreePool(ShellFileListItem);

+      return (NULL);

+    }

+  } else {

+    ShellFileListItem->FileName = NULL;

+  }

+  Size = 0;

+  TempString = NULL;

+  if (BasePath != NULL) {

+    ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));

+    TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);

+    if (TempString == NULL) {

+      FreePool((VOID*)ShellFileListItem->FileName);

+      SHELL_FREE_NON_NULL(ShellFileListItem->Info);

+      FreePool(ShellFileListItem);

+      return (NULL);

+    }

+  }

+  if (ShellFileListItem->FileName != NULL) {

+    ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));

+    TempString = StrnCatGrow(&TempString, &Size, ShellFileListItem->FileName, 0);

+    if (TempString == NULL) {

+      FreePool((VOID*)ShellFileListItem->FileName);

+      FreePool(ShellFileListItem->Info);

+      FreePool(ShellFileListItem);

+      return (NULL);

+    }

+  }

+

+  TempString = PathCleanUpDirectories(TempString);

+

+  ShellFileListItem->FullName = TempString;

+  ShellFileListItem->Status   = Status;

+  ShellFileListItem->Handle   = Handle;

+

+  return (ShellFileListItem);

+}

+

+/**

+  Find all files in a specified directory.

+

+  @param FileDirHandle          Handle of the directory to search.

+  @param FileList               On return, points to the list of files in the directory

+                                or NULL if there are no files in the directory.

+

+  @retval EFI_SUCCESS           File information was returned successfully.

+  @retval EFI_VOLUME_CORRUPTED  The file system structures have been corrupted.

+  @retval EFI_DEVICE_ERROR      The device reported an error.

+  @retval EFI_NO_MEDIA          The device media is not present.

+  @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory.

+  @return                       An error from FileHandleGetFileName().

+**/

+EFI_STATUS

+EFIAPI

+EfiShellFindFilesInDir(

+  IN SHELL_FILE_HANDLE FileDirHandle,

+  OUT EFI_SHELL_FILE_INFO **FileList

+  )

+{

+  EFI_SHELL_FILE_INFO       *ShellFileList;

+  EFI_SHELL_FILE_INFO       *ShellFileListItem;

+  EFI_FILE_INFO             *FileInfo;

+  EFI_STATUS                Status;

+  BOOLEAN                   NoFile;

+  CHAR16                    *TempString;

+  CHAR16                    *BasePath;

+  UINTN                     Size;

+  CHAR16                    *TempSpot;

+

+  BasePath = NULL;

+  Status = FileHandleGetFileName(FileDirHandle, &BasePath);

+  if (EFI_ERROR(Status)) {

+    return (Status);

+  }

+

+  if (ShellFileHandleGetPath(FileDirHandle) != NULL) {

+    TempString        = NULL;

+    Size              = 0;

+    TempString        = StrnCatGrow(&TempString, &Size, ShellFileHandleGetPath(FileDirHandle), 0);

+    if (TempString == NULL) {

+      SHELL_FREE_NON_NULL(BasePath);

+      return (EFI_OUT_OF_RESOURCES);

+    }

+    TempSpot          = StrStr(TempString, L";");

+

+    if (TempSpot != NULL) {

+      *TempSpot = CHAR_NULL;

+    }

+

+    TempString        = StrnCatGrow(&TempString, &Size, BasePath, 0);

+    if (TempString == NULL) {

+      SHELL_FREE_NON_NULL(BasePath);

+      return (EFI_OUT_OF_RESOURCES);

+    }

+    SHELL_FREE_NON_NULL(BasePath);

+    BasePath          = TempString;

+  }

+

+  NoFile            = FALSE;

+  ShellFileList     = NULL;

+  ShellFileListItem = NULL;

+  FileInfo          = NULL;

+  Status            = EFI_SUCCESS;

+

+

+  for ( Status = FileHandleFindFirstFile(FileDirHandle, &FileInfo)

+      ; !EFI_ERROR(Status) && !NoFile

+      ; Status = FileHandleFindNextFile(FileDirHandle, FileInfo, &NoFile)

+     ){

+    //

+    // allocate a new EFI_SHELL_FILE_INFO and populate it...

+    //

+    ShellFileListItem = CreateAndPopulateShellFileInfo(

+      BasePath,

+      EFI_SUCCESS,  // success since we didnt fail to open it...

+      FileInfo->FileName,

+      NULL,         // no handle since not open

+      FileInfo);

+

+    if (ShellFileList == NULL) {

+      ShellFileList = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));

+      ASSERT(ShellFileList != NULL);

+      InitializeListHead(&ShellFileList->Link);

+    }

+    InsertTailList(&ShellFileList->Link, &ShellFileListItem->Link);

+  }

+  if (EFI_ERROR(Status)) {

+    EfiShellFreeFileList(&ShellFileList);

+    *FileList = NULL;

+  } else {

+    *FileList = ShellFileList;

+  }

+  SHELL_FREE_NON_NULL(BasePath);

+  return(Status);

+}

+

+/**

+  Get the GUID value from a human readable name.

+

+  If GuidName is a known GUID name, then update Guid to have the correct value for

+  that GUID.

+

+  This function is only available when the major and minor versions in the

+  EfiShellProtocol are greater than or equal to 2 and 1, respectively.

+

+  @param[in]  GuidName   A pointer to the localized name for the GUID being queried.

+  @param[out] Guid       A pointer to the GUID structure to be filled in.

+

+  @retval EFI_SUCCESS             The operation was successful.

+  @retval EFI_INVALID_PARAMETER   Guid was NULL.

+  @retval EFI_INVALID_PARAMETER   GuidName was NULL.

+  @retval EFI_NOT_FOUND           GuidName is not a known GUID Name.

+**/

+EFI_STATUS

+EFIAPI 

+EfiShellGetGuidFromName(

+  IN  CONST CHAR16   *GuidName,

+  OUT       EFI_GUID *Guid

+  )

+{

+  EFI_GUID    *NewGuid;

+  EFI_STATUS  Status;

+

+  if (Guid == NULL || GuidName == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+ 

+  Status = GetGuidFromStringName(GuidName, NULL, &NewGuid);

+

+  if (!EFI_ERROR(Status)) {

+    CopyGuid(NewGuid, Guid);

+  }

+

+  return (Status);

+}

+

+/**

+  Get the human readable name for a GUID from the value.

+

+  If Guid is assigned a name, then update *GuidName to point to the name. The callee

+  should not modify the value.

+

+  This function is only available when the major and minor versions in the

+  EfiShellProtocol are greater than or equal to 2 and 1, respectively.

+

+  @param[in]  Guid       A pointer to the GUID being queried.

+  @param[out] GuidName   A pointer to a pointer the localized to name for the GUID being requested

+

+  @retval EFI_SUCCESS             The operation was successful.

+  @retval EFI_INVALID_PARAMETER   Guid was NULL.

+  @retval EFI_INVALID_PARAMETER   GuidName was NULL.

+  @retval EFI_NOT_FOUND           Guid is not assigned a name.

+**/

+EFI_STATUS

+EFIAPI 

+EfiShellGetGuidName(

+  IN  CONST EFI_GUID *Guid,

+  OUT CONST CHAR16   **GuidName

+  )

+{

+  CHAR16   *Name;

+

+  if (Guid == NULL || GuidName == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  Name = GetStringNameFromGuid(Guid, NULL);

+  if (Name == NULL || StrLen(Name) == 0) {

+    SHELL_FREE_NON_NULL(Name);

+    return (EFI_NOT_FOUND);

+  }

+

+  *GuidName = AddBufferToFreeList(Name);

+

+  return (EFI_SUCCESS);

+}

+

+/**

+  Updates a file name to be preceeded by the mapped drive name

+

+  @param[in] BasePath      the Mapped drive name to prepend

+  @param[in, out] Path     pointer to pointer to the file name to update.

+

+  @retval EFI_SUCCESS

+  @retval EFI_OUT_OF_RESOURCES

+**/

+EFI_STATUS

+EFIAPI

+UpdateFileName(

+  IN CONST CHAR16 *BasePath,

+  IN OUT CHAR16   **Path

+  )

+{

+  CHAR16              *Path2;

+  UINTN               Path2Size;

+

+  Path2Size = 0;

+  Path2 = NULL;

+

+  ASSERT(Path      != NULL);

+  ASSERT(*Path     != NULL);

+  ASSERT(BasePath  != NULL);

+

+  //

+  // convert a local path to an absolute path

+  //

+  if (StrStr(*Path, L":") == NULL) {

+    ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));

+    StrnCatGrow(&Path2, &Path2Size, BasePath, 0);

+    if (Path2 == NULL) {

+      return (EFI_OUT_OF_RESOURCES);

+    }

+    ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));

+    StrnCatGrow(&Path2, &Path2Size, (*Path)[0] == L'\\'?(*Path) + 1 :*Path, 0);

+    if (Path2 == NULL) {

+      return (EFI_OUT_OF_RESOURCES);

+    }

+  }

+

+  FreePool(*Path);

+  (*Path) = Path2;

+

+  return (EFI_SUCCESS);

+}

+

+/**

+  If FileHandle is a directory then the function reads from FileHandle and reads in

+  each of the FileInfo structures.  If one of them matches the Pattern's first

+  "level" then it opens that handle and calls itself on that handle.

+

+  If FileHandle is a file and matches all of the remaining Pattern (which would be

+  on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList.

+

+  Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call

+  FreeFileList with FileList.

+

+  @param[in] FilePattern         The FilePattern to check against.

+  @param[in] UnicodeCollation    The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure

+  @param[in] FileHandle          The FileHandle to start with

+  @param[in, out] FileList       pointer to pointer to list of found files.

+  @param[in] ParentNode          The node for the parent. Same file as identified by HANDLE.

+  @param[in] MapName             The file system name this file is on.

+

+  @retval EFI_SUCCESS           all files were found and the FileList contains a list.

+  @retval EFI_NOT_FOUND         no files were found

+  @retval EFI_OUT_OF_RESOURCES  a memory allocation failed

+**/

+EFI_STATUS

+EFIAPI

+ShellSearchHandle(

+  IN     CONST CHAR16                         *FilePattern,

+  IN           EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation,

+  IN           SHELL_FILE_HANDLE              FileHandle,

+  IN OUT       EFI_SHELL_FILE_INFO            **FileList,

+  IN     CONST EFI_SHELL_FILE_INFO            *ParentNode OPTIONAL,

+  IN     CONST CHAR16                         *MapName

+  )

+{

+  EFI_STATUS          Status;

+  CONST CHAR16        *NextFilePatternStart;

+  CHAR16              *CurrentFilePattern;

+  EFI_SHELL_FILE_INFO *ShellInfo;

+  EFI_SHELL_FILE_INFO *ShellInfoNode;

+  EFI_SHELL_FILE_INFO *NewShellNode;

+  EFI_FILE_INFO       *FileInfo;

+  BOOLEAN             Directory;

+  CHAR16              *NewFullName;

+  UINTN               Size;

+

+  if ( FilePattern      == NULL

+    || UnicodeCollation == NULL

+    || FileList         == NULL

+   ){

+    return (EFI_INVALID_PARAMETER);

+  }

+  ShellInfo = NULL;

+  CurrentFilePattern = NULL;

+

+  if (*FilePattern == L'\\') {

+    FilePattern++;

+  }

+

+  for( NextFilePatternStart = FilePattern

+     ; *NextFilePatternStart != CHAR_NULL && *NextFilePatternStart != L'\\'

+     ; NextFilePatternStart++);

+

+  CurrentFilePattern = AllocateZeroPool((NextFilePatternStart-FilePattern+1)*sizeof(CHAR16));

+  ASSERT(CurrentFilePattern != NULL);

+  StrnCpy(CurrentFilePattern, FilePattern, NextFilePatternStart-FilePattern);

+

+  if (CurrentFilePattern[0]   == CHAR_NULL

+    &&NextFilePatternStart[0] == CHAR_NULL

+    ){

+    //

+    // we want the parent or root node (if no parent)

+    //

+    if (ParentNode == NULL) {

+      //

+      // We want the root node.  create the node.

+      //

+      FileInfo = FileHandleGetInfo(FileHandle);

+      NewShellNode = CreateAndPopulateShellFileInfo(

+        MapName,

+        EFI_SUCCESS,

+        L"\\",

+        FileHandle,

+        FileInfo

+        );

+      SHELL_FREE_NON_NULL(FileInfo);

+    } else {

+      //

+      // Add the current parameter FileHandle to the list, then end...

+      //

+      NewShellNode = InternalDuplicateShellFileInfo((EFI_SHELL_FILE_INFO*)ParentNode, TRUE);

+    }

+    if (NewShellNode == NULL) {

+      Status = EFI_OUT_OF_RESOURCES;

+    } else {

+      NewShellNode->Handle = NULL;

+      if (*FileList == NULL) {

+        *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));

+        InitializeListHead(&((*FileList)->Link));

+      }

+

+      //

+      // Add to the returning to use list

+      //

+      InsertTailList(&(*FileList)->Link, &NewShellNode->Link);

+

+      Status = EFI_SUCCESS;

+    }

+  } else {

+    Status = EfiShellFindFilesInDir(FileHandle, &ShellInfo);

+

+    if (!EFI_ERROR(Status)){

+      if (StrStr(NextFilePatternStart, L"\\") != NULL){

+        Directory = TRUE;

+      } else {

+        Directory = FALSE;

+      }

+      for ( ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetFirstNode(&ShellInfo->Link)

+          ; !IsNull (&ShellInfo->Link, &ShellInfoNode->Link)

+          ; ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ShellInfo->Link, &ShellInfoNode->Link)

+         ){

+        if (UnicodeCollation->MetaiMatch(UnicodeCollation, (CHAR16*)ShellInfoNode->FileName, CurrentFilePattern)){

+          if (ShellInfoNode->FullName != NULL && StrStr(ShellInfoNode->FullName, L":") == NULL) {

+            Size = StrSize(ShellInfoNode->FullName);

+            Size += StrSize(MapName) + sizeof(CHAR16);

+            NewFullName = AllocateZeroPool(Size);

+            if (NewFullName == NULL) {

+              Status = EFI_OUT_OF_RESOURCES;

+            } else {

+              StrnCpy(NewFullName, MapName, Size/sizeof(CHAR16)-1);

+              StrnCat(NewFullName, ShellInfoNode->FullName+1, (Size/sizeof(CHAR16))-StrLen(NewFullName)-1);

+              FreePool((VOID*)ShellInfoNode->FullName);

+              ShellInfoNode->FullName = NewFullName;

+            }

+          }

+          if (Directory && !EFI_ERROR(Status) && ShellInfoNode->FullName != NULL && ShellInfoNode->FileName != NULL){

+            //

+            // should be a directory

+            //

+

+            //

+            // don't open the . and .. directories

+            //

+            if ( (StrCmp(ShellInfoNode->FileName, L".") != 0)

+              && (StrCmp(ShellInfoNode->FileName, L"..") != 0)

+             ){

+              //

+              //

+              //

+              if (EFI_ERROR(Status)) {

+                break;

+              }

+              //

+              // Open the directory since we need that handle in the next recursion.

+              //

+              ShellInfoNode->Status = EfiShellOpenFileByName (ShellInfoNode->FullName, &ShellInfoNode->Handle, EFI_FILE_MODE_READ);

+

+              //

+              // recurse with the next part of the pattern

+              //

+              Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode, MapName);

+            }

+          } else if (!EFI_ERROR(Status)) {

+            //

+            // should be a file

+            //

+

+            //

+            // copy the information we need into a new Node

+            //

+            NewShellNode = InternalDuplicateShellFileInfo(ShellInfoNode, FALSE);

+            ASSERT(NewShellNode != NULL);

+            if (NewShellNode == NULL) {

+              Status = EFI_OUT_OF_RESOURCES;

+            }

+            if (*FileList == NULL) {

+              *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));

+              InitializeListHead(&((*FileList)->Link));

+            }

+

+            //

+            // Add to the returning to use list

+            //

+            InsertTailList(&(*FileList)->Link, &NewShellNode->Link);

+          }

+        }

+        if (EFI_ERROR(Status)) {

+          break;

+        }

+      }

+      if (EFI_ERROR(Status)) {

+        EfiShellFreeFileList(&ShellInfo);

+      } else {

+        Status = EfiShellFreeFileList(&ShellInfo);

+      }

+    }

+  }

+

+  FreePool(CurrentFilePattern);

+  return (Status);

+}

+

+/**

+  Find files that match a specified pattern.

+

+  This function searches for all files and directories that match the specified

+  FilePattern. The FilePattern can contain wild-card characters. The resulting file

+  information is placed in the file list FileList.

+

+  Wildcards are processed

+  according to the rules specified in UEFI Shell 2.0 spec section 3.7.1.

+

+  The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo

+  field is set to NULL.

+

+  if *FileList is not NULL then it must be a pre-existing and properly initialized list.

+

+  @param FilePattern      Points to a NULL-terminated shell file path, including wildcards.

+  @param FileList         On return, points to the start of a file list containing the names

+                          of all matching files or else points to NULL if no matching files

+                          were found.  only on a EFI_SUCCESS return will; this be non-NULL.

+

+  @retval EFI_SUCCESS           Files found.  FileList is a valid list.

+  @retval EFI_NOT_FOUND         No files found.

+  @retval EFI_NO_MEDIA          The device has no media

+  @retval EFI_DEVICE_ERROR      The device reported an error

+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted

+**/

+EFI_STATUS

+EFIAPI

+EfiShellFindFiles(

+  IN CONST CHAR16 *FilePattern,

+  OUT EFI_SHELL_FILE_INFO **FileList

+  )

+{

+  EFI_STATUS                      Status;

+  CHAR16                          *PatternCopy;

+  CHAR16                          *PatternCurrentLocation;

+  EFI_DEVICE_PATH_PROTOCOL        *RootDevicePath;

+  SHELL_FILE_HANDLE               RootFileHandle;

+  CHAR16                          *MapName;

+  UINTN                           Count;

+

+  if ( FilePattern      == NULL

+    || FileList         == NULL

+    || StrStr(FilePattern, L":") == NULL

+   ){

+    return (EFI_INVALID_PARAMETER);

+  }

+  Status = EFI_SUCCESS;

+  RootDevicePath = NULL;

+  RootFileHandle = NULL;

+  MapName        = NULL;

+  PatternCopy = AllocateCopyPool(StrSize(FilePattern), FilePattern);

+  if (PatternCopy == NULL) {

+    return (EFI_OUT_OF_RESOURCES);

+  }

+

+  PatternCopy = PathCleanUpDirectories(PatternCopy);

+

+  Count = StrStr(PatternCopy, L":") - PatternCopy;

+  Count += 2;

+

+  ASSERT(MapName == NULL);

+  MapName = StrnCatGrow(&MapName, NULL, PatternCopy, Count);

+  if (MapName == NULL) {

+    Status = EFI_OUT_OF_RESOURCES;

+  } else {

+    RootDevicePath = EfiShellGetDevicePathFromFilePath(PatternCopy);

+    if (RootDevicePath == NULL) {

+      Status = EFI_INVALID_PARAMETER;

+    } else {

+      Status = EfiShellOpenRoot(RootDevicePath, &RootFileHandle);

+      if (!EFI_ERROR(Status)) {

+        for ( PatternCurrentLocation = PatternCopy

+            ; *PatternCurrentLocation != ':'

+            ; PatternCurrentLocation++);

+        PatternCurrentLocation++;

+        Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL, MapName);

+      }

+      FreePool(RootDevicePath);

+    }

+  }

+

+  SHELL_FREE_NON_NULL(PatternCopy);

+  SHELL_FREE_NON_NULL(MapName);

+

+  return(Status);

+}

+

+/**

+  Opens the files that match the path specified.

+

+  This function opens all of the files specified by Path. Wildcards are processed

+  according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each

+  matching file has an EFI_SHELL_FILE_INFO structure created in a linked list.

+

+  @param Path                   A pointer to the path string.

+  @param OpenMode               Specifies the mode used to open each file, EFI_FILE_MODE_READ or

+                                EFI_FILE_MODE_WRITE.

+  @param FileList               Points to the start of a list of files opened.

+

+  @retval EFI_SUCCESS           Create the file list successfully.

+  @return Others                Can't create the file list.

+**/

+EFI_STATUS

+EFIAPI

+EfiShellOpenFileList(

+  IN CHAR16 *Path,

+  IN UINT64 OpenMode,

+  IN OUT EFI_SHELL_FILE_INFO **FileList

+  )

+{

+  EFI_STATUS Status;

+  EFI_SHELL_FILE_INFO *ShellFileListItem;

+  CHAR16              *Path2;

+  UINTN               Path2Size;

+  CONST CHAR16        *CurDir;

+  BOOLEAN             Found;

+

+  PathCleanUpDirectories(Path);

+

+  Path2Size     = 0;

+  Path2         = NULL;

+

+  if (FileList == NULL || *FileList == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  if (*Path == L'.' && *(Path+1) == L'\\') {

+    Path+=2;

+  }

+

+  //

+  // convert a local path to an absolute path

+  //

+  if (StrStr(Path, L":") == NULL) {

+    CurDir = EfiShellGetCurDir(NULL);

+    ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));

+    StrnCatGrow(&Path2, &Path2Size, CurDir, 0);

+    if (*Path == L'\\') {

+      Path++;

+      while (PathRemoveLastItem(Path2)) ;

+    }

+    ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));

+    StrnCatGrow(&Path2, &Path2Size, Path, 0);

+  } else {

+    ASSERT(Path2 == NULL);

+    StrnCatGrow(&Path2, NULL, Path, 0);

+  }

+

+  PathCleanUpDirectories (Path2);

+

+  //

+  // do the search

+  //

+  Status = EfiShellFindFiles(Path2, FileList);

+

+  FreePool(Path2);

+

+  if (EFI_ERROR(Status)) {

+    return (Status);

+  }

+

+  Found = FALSE;

+  //

+  // We had no errors so open all the files (that are not already opened...)

+  //

+  for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)

+      ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link)

+      ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)

+     ){

+    if (ShellFileListItem->Status == 0 && ShellFileListItem->Handle == NULL) {

+      ShellFileListItem->Status = EfiShellOpenFileByName (ShellFileListItem->FullName, &ShellFileListItem->Handle, OpenMode);

+      Found = TRUE;

+    }

+  }

+

+  if (!Found) {

+    return (EFI_NOT_FOUND);

+  }

+  return(EFI_SUCCESS);

+}

+

+/**

+  Gets the environment variable and Attributes, or list of environment variables.  Can be

+  used instead of GetEnv().

+

+  This function returns the current value of the specified environment variable and

+  the Attributes. If no variable name was specified, then all of the known

+  variables will be returned.

+

+  @param[in] Name               A pointer to the environment variable name. If Name is NULL,

+                                then the function will return all of the defined shell

+                                environment variables. In the case where multiple environment

+                                variables are being returned, each variable will be terminated

+                                by a NULL, and the list will be terminated by a double NULL.

+  @param[out] Attributes        If not NULL, a pointer to the returned attributes bitmask for

+                                the environment variable. In the case where Name is NULL, and

+                                multiple environment variables are being returned, Attributes

+                                is undefined.

+

+  @retval NULL                  The environment variable doesn't exist.

+  @return                       A non-NULL value points to the variable's value. The returned

+                                pointer does not need to be freed by the caller.

+**/

+CONST CHAR16 *

+EFIAPI 

+EfiShellGetEnvEx(

+  IN  CONST CHAR16 *Name,

+  OUT       UINT32 *Attributes OPTIONAL

+  )

+{

+  EFI_STATUS  Status;

+  VOID        *Buffer;

+  UINTN       Size;

+  LIST_ENTRY  List;

+  ENV_VAR_LIST *Node;

+  CHAR16      *CurrentWriteLocation;

+

+  Size = 0;

+  Buffer = NULL;

+

+  if (Name == NULL) {

+    //

+    // Get all our environment variables

+    //

+    InitializeListHead(&List);

+    Status = GetEnvironmentVariableList(&List);

+    if (EFI_ERROR(Status)){

+      return (NULL);

+    }

+

+    //

+    // Build the semi-colon delimited list. (2 passes)

+    //

+    for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List)

+      ; !IsNull(&List, &Node->Link)

+      ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)

+     ){

+      ASSERT(Node->Key != NULL);

+      Size += StrSize(Node->Key);

+    }

+

+    Size += 2*sizeof(CHAR16);

+

+    Buffer = AllocateZeroPool(Size);

+    if (Buffer == NULL) {

+      if (!IsListEmpty (&List)) {

+        FreeEnvironmentVariableList(&List);

+      }

+      return (NULL);

+    }

+    CurrentWriteLocation = (CHAR16*)Buffer;

+

+    for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List)

+      ; !IsNull(&List, &Node->Link)

+      ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)

+     ){

+      ASSERT(Node->Key != NULL);

+      StrnCpy(CurrentWriteLocation, Node->Key,  (Size)/sizeof(CHAR16) - (CurrentWriteLocation - ((CHAR16*)Buffer)) - 1);

+      CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1;

+    }

+

+    //

+    // Free the list...

+    //

+    if (!IsListEmpty (&List)) {

+      FreeEnvironmentVariableList(&List);

+    }

+  } else {

+    //

+    // We are doing a specific environment variable

+    //

+

+    //

+    // get the size we need for this EnvVariable

+    //

+    Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer);

+    if (Status == EFI_BUFFER_TOO_SMALL) {

+      //

+      // Allocate the space and recall the get function

+      //

+      Buffer = AllocateZeroPool(Size);

+      Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer);

+    }

+    //

+    // we didnt get it (might not exist)

+    // free the memory if we allocated any and return NULL

+    //

+    if (EFI_ERROR(Status)) {

+      if (Buffer != NULL) {

+        FreePool(Buffer);

+      }

+      return (NULL);

+    }

+  }

+

+  //

+  // return the buffer

+  //

+  return (AddBufferToFreeList(Buffer));

+}

+

+/**

+  Gets either a single or list of environment variables.

+

+  If name is not NULL then this function returns the current value of the specified

+  environment variable.

+

+  If Name is NULL, then a list of all environment variable names is returned.  Each is a

+  NULL terminated string with a double NULL terminating the list.

+

+  @param Name                   A pointer to the environment variable name.  If

+                                Name is NULL, then the function will return all

+                                of the defined shell environment variables.  In

+                                the case where multiple environment variables are

+                                being returned, each variable will be terminated by

+                                a NULL, and the list will be terminated by a double

+                                NULL.

+

+  @retval !=NULL                A pointer to the returned string.

+                                The returned pointer does not need to be freed by the caller.

+

+  @retval NULL                  The environment variable doesn't exist or there are

+                                no environment variables.

+**/

+CONST CHAR16 *

+EFIAPI

+EfiShellGetEnv(

+  IN CONST CHAR16 *Name

+  )

+{

+  return (EfiShellGetEnvEx(Name, NULL));

+}

+

+/**

+  Internal variable setting function.  Allows for setting of the read only variables.

+

+  @param Name                   Points to the NULL-terminated environment variable name.

+  @param Value                  Points to the NULL-terminated environment variable value. If the value is an

+                                empty string then the environment variable is deleted.

+  @param Volatile               Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).

+

+  @retval EFI_SUCCESS           The environment variable was successfully updated.

+**/

+EFI_STATUS

+EFIAPI

+InternalEfiShellSetEnv(

+  IN CONST CHAR16 *Name,

+  IN CONST CHAR16 *Value,

+  IN BOOLEAN Volatile

+  )

+{

+  if (Value == NULL || StrLen(Value) == 0) {

+    return (SHELL_DELETE_ENVIRONMENT_VARIABLE(Name));

+  } else {

+    SHELL_DELETE_ENVIRONMENT_VARIABLE(Name);

+    if (Volatile) {

+      return (SHELL_SET_ENVIRONMENT_VARIABLE_V(Name, StrSize(Value), Value));

+    } else {

+      return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(Name, StrSize(Value), Value));

+    }

+  }

+}

+

+/**

+  Sets the environment variable.

+

+  This function changes the current value of the specified environment variable. If the

+  environment variable exists and the Value is an empty string, then the environment

+  variable is deleted. If the environment variable exists and the Value is not an empty

+  string, then the value of the environment variable is changed. If the environment

+  variable does not exist and the Value is an empty string, there is no action. If the

+  environment variable does not exist and the Value is a non-empty string, then the

+  environment variable is created and assigned the specified value.

+

+  For a description of volatile and non-volatile environment variables, see UEFI Shell

+  2.0 specification section 3.6.1.

+

+  @param Name                   Points to the NULL-terminated environment variable name.

+  @param Value                  Points to the NULL-terminated environment variable value. If the value is an

+                                empty string then the environment variable is deleted.

+  @param Volatile               Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).

+

+  @retval EFI_SUCCESS           The environment variable was successfully updated.

+**/

+EFI_STATUS

+EFIAPI

+EfiShellSetEnv(

+  IN CONST CHAR16 *Name,

+  IN CONST CHAR16 *Value,

+  IN BOOLEAN Volatile

+  )

+{

+  if (Name == NULL || *Name == CHAR_NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+  //

+  // Make sure we dont 'set' a predefined read only variable

+  //

+  if (gUnicodeCollation->StriColl(

+        gUnicodeCollation,

+        (CHAR16*)Name,

+        L"cwd") == 0

+    ||gUnicodeCollation->StriColl(

+        gUnicodeCollation,

+        (CHAR16*)Name,

+        L"Lasterror") == 0

+    ||gUnicodeCollation->StriColl(

+        gUnicodeCollation,

+        (CHAR16*)Name,

+        L"profiles") == 0

+    ||gUnicodeCollation->StriColl(

+        gUnicodeCollation,

+        (CHAR16*)Name,

+        L"uefishellsupport") == 0

+    ||gUnicodeCollation->StriColl(

+        gUnicodeCollation,

+        (CHAR16*)Name,

+        L"uefishellversion") == 0

+    ||gUnicodeCollation->StriColl(

+        gUnicodeCollation,

+        (CHAR16*)Name,

+        L"uefiversion") == 0

+       ){

+    return (EFI_INVALID_PARAMETER);

+  }

+  return (InternalEfiShellSetEnv(Name, Value, Volatile));

+}

+

+/**

+  Returns the current directory on the specified device.

+

+  If FileSystemMapping is NULL, it returns the current working directory. If the

+  FileSystemMapping is not NULL, it returns the current directory associated with the

+  FileSystemMapping. In both cases, the returned name includes the file system

+  mapping (i.e. fs0:\current-dir).

+

+  @param FileSystemMapping      A pointer to the file system mapping. If NULL,

+                                then the current working directory is returned.

+

+  @retval !=NULL                The current directory.

+  @retval NULL                  Current directory does not exist.

+**/

+CONST CHAR16 *

+EFIAPI

+EfiShellGetCurDir(

+  IN CONST CHAR16 *FileSystemMapping OPTIONAL

+  )

+{

+  CHAR16  *PathToReturn;

+  UINTN   Size;

+  SHELL_MAP_LIST *MapListItem;

+  if (!IsListEmpty(&gShellMapList.Link)) {

+    //

+    // if parameter is NULL, use current

+    //

+    if (FileSystemMapping == NULL) {

+      return (EfiShellGetEnv(L"cwd"));

+    } else {

+      Size = 0;

+      PathToReturn = NULL;

+      MapListItem = ShellCommandFindMapItem(FileSystemMapping);

+      if (MapListItem != NULL) {

+        ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL));

+        PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->MapName, 0);

+        PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->CurrentDirectoryPath, 0);

+      }

+    }

+    return (AddBufferToFreeList(PathToReturn));

+  } else {

+    return (NULL);

+  }

+}

+

+/**

+  Changes the current directory on the specified device.

+

+  If the FileSystem is NULL, and the directory Dir does not contain a file system's

+  mapped name, this function changes the current working directory.

+

+  If the FileSystem is NULL and the directory Dir contains a mapped name, then the

+  current file system and the current directory on that file system are changed.

+

+  If FileSystem is NULL, and Dir is not NULL, then this changes the current working file

+  system.

+

+  If FileSystem is not NULL and Dir is not NULL, then this function changes the current

+  directory on the specified file system.

+

+  If the current working directory or the current working file system is changed then the

+  %cwd% environment variable will be updated

+

+  @param FileSystem             A pointer to the file system's mapped name. If NULL, then the current working

+                                directory is changed.

+  @param Dir                    Points to the NULL-terminated directory on the device specified by FileSystem.

+

+  @retval EFI_SUCCESS           The operation was sucessful

+  @retval EFI_NOT_FOUND         The file system could not be found

+**/

+EFI_STATUS

+EFIAPI

+EfiShellSetCurDir(

+  IN CONST CHAR16 *FileSystem OPTIONAL,

+  IN CONST CHAR16 *Dir

+  )

+{

+  CHAR16          *MapName;

+  SHELL_MAP_LIST  *MapListItem;

+  UINTN           Size;

+  EFI_STATUS      Status;

+  CHAR16          *TempString;

+  CHAR16          *DirectoryName;

+  UINTN           TempLen;

+

+  Size          = 0;

+  MapName       = NULL;

+  MapListItem   = NULL;

+  TempString    = NULL;

+  DirectoryName = NULL;

+

+  if ((FileSystem == NULL && Dir == NULL) || Dir == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  if (IsListEmpty(&gShellMapList.Link)){

+    return (EFI_NOT_FOUND);

+  }

+

+  DirectoryName = StrnCatGrow(&DirectoryName, NULL, Dir, 0);

+  ASSERT(DirectoryName != NULL);

+

+  PathCleanUpDirectories(DirectoryName);

+

+  if (FileSystem == NULL) {

+    //

+    // determine the file system mapping to use

+    //

+    if (StrStr(DirectoryName, L":") != NULL) {

+      ASSERT(MapName == NULL);

+      MapName = StrnCatGrow(&MapName, NULL, DirectoryName, (StrStr(DirectoryName, L":")-DirectoryName+1));

+    }

+    //

+    // find the file system mapping's entry in the list

+    // or use current

+    //

+    if (MapName != NULL) {

+      MapListItem = ShellCommandFindMapItem(MapName);

+

+      //

+      // make that the current file system mapping

+      //

+      if (MapListItem != NULL) {

+        gShellCurDir = MapListItem;

+      }

+    } else {

+      MapListItem = gShellCurDir;

+    }

+

+    if (MapListItem == NULL) {

+      return (EFI_NOT_FOUND);

+    }

+

+    //

+    // now update the MapListItem's current directory

+    //

+    if (MapListItem->CurrentDirectoryPath != NULL && DirectoryName[StrLen(DirectoryName) - 1] != L':') {

+      FreePool(MapListItem->CurrentDirectoryPath);

+      MapListItem->CurrentDirectoryPath = NULL;

+    }

+    if (MapName != NULL) {

+      TempLen = StrLen(MapName);

+      if (TempLen != StrLen(DirectoryName)) {

+        ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));

+        MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName+StrLen(MapName), 0);

+      }

+    } else {

+      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));

+      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);

+    }

+    if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {

+      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));

+      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);

+    }

+  } else {

+    //

+    // cant have a mapping in the directory...

+    //

+    if (StrStr(DirectoryName, L":") != NULL) {

+      return (EFI_INVALID_PARAMETER);

+    }

+    //

+    // FileSystem != NULL

+    //

+    MapListItem = ShellCommandFindMapItem(FileSystem);

+    if (MapListItem == NULL) {

+      return (EFI_INVALID_PARAMETER);

+    }

+//    gShellCurDir = MapListItem;

+    if (DirectoryName != NULL) {

+      //

+      // change current dir on that file system

+      //

+

+      if (MapListItem->CurrentDirectoryPath != NULL) {

+        FreePool(MapListItem->CurrentDirectoryPath);

+        DEBUG_CODE(MapListItem->CurrentDirectoryPath = NULL;);

+      }

+//      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));

+//      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0);

+      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));

+      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);

+      ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));

+      MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);

+      if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') {

+        ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));

+        MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);

+      }

+    }

+  }

+  //

+  // if updated the current directory then update the environment variable

+  //

+  if (MapListItem == gShellCurDir) {

+    Size = 0;

+    ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));

+    StrnCatGrow(&TempString, &Size, MapListItem->MapName, 0);

+    ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));

+    StrnCatGrow(&TempString, &Size, MapListItem->CurrentDirectoryPath, 0);

+    Status =  InternalEfiShellSetEnv(L"cwd", TempString, TRUE);

+    FreePool(TempString);

+    return (Status);

+  }

+  return(EFI_SUCCESS);

+}

+

+/**

+  Return help information about a specific command.

+

+  This function returns the help information for the specified command. The help text

+  can be internal to the shell or can be from a UEFI Shell manual page.

+

+  If Sections is specified, then each section name listed will be compared in a casesensitive

+  manner, to the section names described in Appendix B. If the section exists,

+  it will be appended to the returned help text. If the section does not exist, no

+  information will be returned. If Sections is NULL, then all help text information

+  available will be returned.

+

+  @param Command                Points to the NULL-terminated UEFI Shell command name.

+  @param Sections               Points to the NULL-terminated comma-delimited

+                                section names to return. If NULL, then all

+                                sections will be returned.

+  @param HelpText               On return, points to a callee-allocated buffer

+                                containing all specified help text.

+

+  @retval EFI_SUCCESS           The help text was returned.

+  @retval EFI_OUT_OF_RESOURCES  The necessary buffer could not be allocated to hold the

+                                returned help text.

+  @retval EFI_INVALID_PARAMETER HelpText is NULL

+  @retval EFI_NOT_FOUND         There is no help text available for Command.

+**/

+EFI_STATUS

+EFIAPI

+EfiShellGetHelpText(

+  IN CONST CHAR16 *Command,

+  IN CONST CHAR16 *Sections OPTIONAL,

+  OUT CHAR16 **HelpText

+  )

+{

+  CONST CHAR16  *ManFileName;

+  CHAR16        *FixCommand;

+  EFI_STATUS    Status;

+

+  ASSERT(HelpText != NULL);

+  FixCommand = NULL;

+

+  ManFileName = ShellCommandGetManFileNameHandler(Command);

+

+  if (ManFileName != NULL) {

+    return (ProcessManFile(ManFileName, Command, Sections, NULL, HelpText));

+  } else {

+    if ((StrLen(Command)> 4)

+    && (Command[StrLen(Command)-1] == L'i' || Command[StrLen(Command)-1] == L'I')

+    && (Command[StrLen(Command)-2] == L'f' || Command[StrLen(Command)-2] == L'F')

+    && (Command[StrLen(Command)-3] == L'e' || Command[StrLen(Command)-3] == L'E')

+    && (Command[StrLen(Command)-4] == L'.')

+    ) {

+      FixCommand = AllocateZeroPool(StrSize(Command) - 4 * sizeof (CHAR16));

+      ASSERT(FixCommand != NULL);

+

+      StrnCpy(FixCommand, Command, StrLen(Command)-4);

+      Status = ProcessManFile(FixCommand, FixCommand, Sections, NULL, HelpText);

+      FreePool(FixCommand);

+      return Status;

+    } else {

+      return (ProcessManFile(Command, Command, Sections, NULL, HelpText));

+    }

+  }

+}

+

+/**

+  Gets the enable status of the page break output mode.

+

+  User can use this function to determine current page break mode.

+

+  @retval TRUE                  The page break output mode is enabled.

+  @retval FALSE                 The page break output mode is disabled.

+**/

+BOOLEAN

+EFIAPI

+EfiShellGetPageBreak(

+  VOID

+  )

+{

+  return(ShellInfoObject.PageBreakEnabled);

+}

+

+/**

+  Judges whether the active shell is the root shell.

+

+  This function makes the user to know that whether the active Shell is the root shell.

+

+  @retval TRUE                  The active Shell is the root Shell.

+  @retval FALSE                 The active Shell is NOT the root Shell.

+**/

+BOOLEAN

+EFIAPI

+EfiShellIsRootShell(

+  VOID

+  )

+{

+  return(ShellInfoObject.RootShellInstance);

+}

+

+/**

+  function to return a semi-colon delimeted list of all alias' in the current shell

+

+  up to caller to free the memory.

+

+  @retval NULL    No alias' were found

+  @retval NULL    An error ocurred getting alias'

+  @return !NULL   a list of all alias'

+**/

+CHAR16 *

+EFIAPI

+InternalEfiShellGetListAlias(

+  )

+{

+  UINT64            MaxStorSize;

+  UINT64            RemStorSize;

+  UINT64            MaxVarSize;

+  EFI_STATUS        Status;

+  EFI_GUID          Guid;

+  CHAR16            *VariableName;

+  UINTN             NameSize;

+  CHAR16            *RetVal;

+  UINTN             RetSize;

+

+  Status = gRT->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, &MaxStorSize, &RemStorSize, &MaxVarSize);

+  ASSERT_EFI_ERROR(Status);

+

+  VariableName  = AllocateZeroPool((UINTN)MaxVarSize);

+  RetSize       = 0;

+  RetVal        = NULL;

+

+  if (VariableName == NULL) {

+    return (NULL);

+  }

+

+  VariableName[0] = CHAR_NULL;

+

+  while (TRUE) {

+    NameSize = (UINTN)MaxVarSize;

+    Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);

+    if (Status == EFI_NOT_FOUND){

+      break;

+    }

+    ASSERT_EFI_ERROR(Status);

+    if (EFI_ERROR(Status)) {

+      break;

+    }

+    if (CompareGuid(&Guid, &gShellAliasGuid)){

+      ASSERT((RetVal == NULL && RetSize == 0) || (RetVal != NULL));

+      RetVal = StrnCatGrow(&RetVal, &RetSize, VariableName, 0);

+      RetVal = StrnCatGrow(&RetVal, &RetSize, L";", 0);

+    } // compare guid

+  } // while

+  FreePool(VariableName);

+

+  return (RetVal);

+}

+

+/**

+  Convert a null-terminated unicode string, in-place, to all lowercase.

+  Then return it.

+  

+  @param  Str    The null-terminated string to be converted to all lowercase.

+  

+  @return        The null-terminated string converted into all lowercase.  

+**/

+CHAR16 *

+ToLower (

+  CHAR16 *Str

+  )

+{

+  UINTN Index;

+

+  for (Index = 0; Str[Index] != L'\0'; Index++) {

+    if (Str[Index] >= L'A' && Str[Index] <= L'Z') {

+      Str[Index] -= (CHAR16)(L'A' - L'a');

+    }

+  }

+  return Str;

+}

+

+/**

+  This function returns the command associated with a alias or a list of all

+  alias'.

+

+  @param[in] Alias              Points to the NULL-terminated shell alias.

+                                If this parameter is NULL, then all

+                                aliases will be returned in ReturnedData.

+  @param[out] Volatile          upon return of a single command if TRUE indicates

+                                this is stored in a volatile fashion.  FALSE otherwise.

+

+  @return                      	If Alias is not NULL, it will return a pointer to

+                                the NULL-terminated command for that alias.

+                                If Alias is NULL, ReturnedData points to a ';'

+                                delimited list of alias (e.g.

+                                ReturnedData = "dir;del;copy;mfp") that is NULL-terminated.

+  @retval NULL                  an error ocurred

+  @retval NULL                  Alias was not a valid Alias

+**/

+CONST CHAR16 *

+EFIAPI

+EfiShellGetAlias(

+  IN  CONST CHAR16 *Alias,

+  OUT BOOLEAN      *Volatile OPTIONAL

+  )

+{

+  CHAR16      *RetVal;

+  UINTN       RetSize;

+  UINT32      Attribs;

+  EFI_STATUS  Status;

+  CHAR16      *AliasLower;

+

+  // Convert to lowercase to make aliases case-insensitive

+  if (Alias != NULL) {

+    AliasLower = AllocateCopyPool (StrSize (Alias), Alias);

+    ASSERT (AliasLower != NULL);

+    ToLower (AliasLower);

+

+    if (Volatile == NULL) {

+      return (AddBufferToFreeList(GetVariable(AliasLower, &gShellAliasGuid)));

+    }

+    RetSize = 0;

+    RetVal = NULL;

+    Status = gRT->GetVariable(AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);

+    if (Status == EFI_BUFFER_TOO_SMALL) {

+      RetVal = AllocateZeroPool(RetSize);

+      Status = gRT->GetVariable(AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);

+    }

+    if (EFI_ERROR(Status)) {

+      if (RetVal != NULL) {

+        FreePool(RetVal);

+      }

+      return (NULL);

+    }

+    if ((EFI_VARIABLE_NON_VOLATILE & Attribs) == EFI_VARIABLE_NON_VOLATILE) {

+      *Volatile = FALSE;

+    } else {

+      *Volatile = TRUE;

+    }

+

+    FreePool (AliasLower);

+    return (AddBufferToFreeList(RetVal));

+  }

+  return (AddBufferToFreeList(InternalEfiShellGetListAlias()));

+}

+

+/**

+  Changes a shell command alias.

+

+  This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.

+

+  this function does not check for built in alias'.

+

+  @param[in] Command            Points to the NULL-terminated shell command or existing alias.

+  @param[in] Alias              Points to the NULL-terminated alias for the shell command. If this is NULL, and

+                                Command refers to an alias, that alias will be deleted.

+  @param[in] Volatile           if TRUE the Alias being set will be stored in a volatile fashion.  if FALSE the

+                                Alias being set will be stored in a non-volatile fashion.

+

+  @retval EFI_SUCCESS           Alias created or deleted successfully.

+  @retval EFI_NOT_FOUND         the Alias intended to be deleted was not found

+**/

+EFI_STATUS

+EFIAPI

+InternalSetAlias(

+  IN CONST CHAR16 *Command,

+  IN CONST CHAR16 *Alias,

+  IN BOOLEAN Volatile

+  )

+{

+  EFI_STATUS  Status;

+  CHAR16      *AliasLower;

+

+  // Convert to lowercase to make aliases case-insensitive

+  if (Alias != NULL) {

+    AliasLower = AllocateCopyPool (StrSize (Alias), Alias);

+    ASSERT (AliasLower != NULL);

+    ToLower (AliasLower);

+  } else {

+    AliasLower = NULL;

+  }

+

+  //

+  // We must be trying to remove one if Alias is NULL

+  //

+  if (Alias == NULL) {

+    //

+    // remove an alias (but passed in COMMAND parameter)

+    //

+    Status = (gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL));

+  } else {

+    //

+    // Add and replace are the same

+    //

+

+    // We dont check the error return on purpose since the variable may not exist.

+    gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL);

+

+    Status = (gRT->SetVariable((CHAR16*)Alias, &gShellAliasGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS|(Volatile?0:EFI_VARIABLE_NON_VOLATILE), StrSize(Command), (VOID*)Command));

+  }

+

+  if (Alias != NULL) {

+    FreePool (AliasLower);

+  }

+  return Status;

+}

+

+/**

+  Changes a shell command alias.

+

+  This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.

+

+

+  @param[in] Command            Points to the NULL-terminated shell command or existing alias.

+  @param[in] Alias              Points to the NULL-terminated alias for the shell command. If this is NULL, and

+                                Command refers to an alias, that alias will be deleted.

+  @param[in] Replace            If TRUE and the alias already exists, then the existing alias will be replaced. If

+                                FALSE and the alias already exists, then the existing alias is unchanged and

+                                EFI_ACCESS_DENIED is returned.

+  @param[in] Volatile           if TRUE the Alias being set will be stored in a volatile fashion.  if FALSE the

+                                Alias being set will be stored in a non-volatile fashion.

+

+  @retval EFI_SUCCESS           Alias created or deleted successfully.

+  @retval EFI_NOT_FOUND         the Alias intended to be deleted was not found

+  @retval EFI_ACCESS_DENIED     The alias is a built-in alias or already existed and Replace was set to

+                                FALSE.

+  @retval EFI_INVALID_PARAMETER Command is null or the empty string.

+**/

+EFI_STATUS

+EFIAPI

+EfiShellSetAlias(

+  IN CONST CHAR16 *Command,

+  IN CONST CHAR16 *Alias,

+  IN BOOLEAN Replace,

+  IN BOOLEAN Volatile

+  )

+{

+  if (ShellCommandIsOnAliasList(Alias==NULL?Command:Alias)) {

+    //

+    // cant set over a built in alias

+    //

+    return (EFI_ACCESS_DENIED);

+  } else if (Command == NULL || *Command == CHAR_NULL || StrLen(Command) == 0) {

+    //

+    // Command is null or empty

+    //

+    return (EFI_INVALID_PARAMETER);

+  } else if (EfiShellGetAlias(Command, NULL) != NULL && !Replace) {

+    //

+    // Alias already exists, Replace not set

+    //

+    return (EFI_ACCESS_DENIED);

+  } else {

+    return (InternalSetAlias(Command, Alias, Volatile));

+  }

+}

+

+// Pure FILE_HANDLE operations are passed to FileHandleLib

+// these functions are indicated by the *

+EFI_SHELL_PROTOCOL         mShellProtocol = {

+  EfiShellExecute,

+  EfiShellGetEnv,

+  EfiShellSetEnv,

+  EfiShellGetAlias,

+  EfiShellSetAlias,

+  EfiShellGetHelpText,

+  EfiShellGetDevicePathFromMap,

+  EfiShellGetMapFromDevicePath,

+  EfiShellGetDevicePathFromFilePath,

+  EfiShellGetFilePathFromDevicePath,

+  EfiShellSetMap,

+  EfiShellGetCurDir,

+  EfiShellSetCurDir,

+  EfiShellOpenFileList,

+  EfiShellFreeFileList,

+  EfiShellRemoveDupInFileList,

+  EfiShellBatchIsActive,

+  EfiShellIsRootShell,

+  EfiShellEnablePageBreak,

+  EfiShellDisablePageBreak,

+  EfiShellGetPageBreak,

+  EfiShellGetDeviceName,

+  (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo,         //*

+  (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo,         //*

+  EfiShellOpenFileByName,

+  EfiShellClose,

+  EfiShellCreateFile,

+  (EFI_SHELL_READ_FILE)FileHandleRead,                //*

+  (EFI_SHELL_WRITE_FILE)FileHandleWrite,              //*

+  (EFI_SHELL_DELETE_FILE)FileHandleDelete,            //*

+  EfiShellDeleteFileByName,

+  (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition, //*

+  (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition, //*

+  (EFI_SHELL_FLUSH_FILE)FileHandleFlush,              //*

+  EfiShellFindFiles,

+  EfiShellFindFilesInDir,

+  (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize,         //*

+  EfiShellOpenRoot,

+  EfiShellOpenRootByHandle,

+  NULL,

+  SHELL_MAJOR_VERSION,

+  SHELL_MINOR_VERSION,

+

+  // New for UEFI Shell 2.1

+  EfiShellRegisterGuidName,

+  EfiShellGetGuidName,

+  EfiShellGetGuidFromName,

+  EfiShellGetEnvEx

+};

+

+/**

+  Function to create and install on the current handle.

+

+  Will overwrite any existing ShellProtocols in the system to be sure that

+  the current shell is in control.

+

+  This must be removed via calling CleanUpShellProtocol().

+

+  @param[in, out] NewShell   The pointer to the pointer to the structure

+  to install.

+

+  @retval EFI_SUCCESS     The operation was successful.

+  @return                 An error from LocateHandle, CreateEvent, or other core function.

+**/

+EFI_STATUS

+EFIAPI

+CreatePopulateInstallShellProtocol (

+  IN OUT EFI_SHELL_PROTOCOL  **NewShell

+  )

+{

+  EFI_STATUS                  Status;

+  UINTN                       BufferSize;

+  EFI_HANDLE                  *Buffer;

+  UINTN                       HandleCounter;

+  SHELL_PROTOCOL_HANDLE_LIST  *OldProtocolNode;

+

+  if (NewShell == NULL) {

+    return (EFI_INVALID_PARAMETER);

+  }

+

+  BufferSize = 0;

+  Buffer = NULL;

+  OldProtocolNode = NULL;

+  InitializeListHead(&ShellInfoObject.OldShellList.Link);

+

+  //

+  // Initialize EfiShellProtocol object...

+  //

+  Status = gBS->CreateEvent(0,

+                            0,

+                            NULL,

+                            NULL,

+                            &mShellProtocol.ExecutionBreak);

+  if (EFI_ERROR(Status)) {

+    return (Status);

+  }

+

+  //

+  // Get the size of the buffer we need.

+  //

+  Status = gBS->LocateHandle(ByProtocol,

+                             &gEfiShellProtocolGuid,

+                             NULL,

+                             &BufferSize,

+                             Buffer);

+  if (Status == EFI_BUFFER_TOO_SMALL) {

+    //

+    // Allocate and recall with buffer of correct size

+    //

+    Buffer = AllocateZeroPool(BufferSize);

+    if (Buffer == NULL) {

+      return (EFI_OUT_OF_RESOURCES);

+    }

+    Status = gBS->LocateHandle(ByProtocol,

+                               &gEfiShellProtocolGuid,

+                               NULL,

+                               &BufferSize,

+                               Buffer);

+    if (EFI_ERROR(Status)) {

+      FreePool(Buffer);

+      return (Status);

+    }

+    //

+    // now overwrite each of them, but save the info to restore when we end.

+    //

+    for (HandleCounter = 0 ; HandleCounter < (BufferSize/sizeof(EFI_HANDLE)) ; HandleCounter++) {

+      OldProtocolNode = AllocateZeroPool(sizeof(SHELL_PROTOCOL_HANDLE_LIST));

+      ASSERT(OldProtocolNode != NULL);

+      Status = gBS->OpenProtocol(Buffer[HandleCounter],

+                                &gEfiShellProtocolGuid,

+                                (VOID **) &(OldProtocolNode->Interface),

+                                gImageHandle,

+                                NULL,

+                                EFI_OPEN_PROTOCOL_GET_PROTOCOL

+                               );

+      if (!EFI_ERROR(Status)) {

+        //

+        // reinstall over the old one...

+        //

+        OldProtocolNode->Handle = Buffer[HandleCounter];

+        Status = gBS->ReinstallProtocolInterface(

+                            OldProtocolNode->Handle,

+                            &gEfiShellProtocolGuid,

+                            OldProtocolNode->Interface,

+                            (VOID*)(&mShellProtocol));

+        if (!EFI_ERROR(Status)) {

+          //

+          // we reinstalled sucessfully.  log this so we can reverse it later.

+          //

+

+          //

+          // add to the list for subsequent...

+          //

+          InsertTailList(&ShellInfoObject.OldShellList.Link, &OldProtocolNode->Link);

+        }

+      }

+    }

+    FreePool(Buffer);

+  } else if (Status == EFI_NOT_FOUND) {

+    ASSERT(IsListEmpty(&ShellInfoObject.OldShellList.Link));

+    //

+    // no one else published yet.  just publish it ourselves.

+    //

+    Status = gBS->InstallProtocolInterface (

+                      &gImageHandle,

+                      &gEfiShellProtocolGuid,

+                      EFI_NATIVE_INTERFACE,

+                      (VOID*)(&mShellProtocol));

+  }

+

+  if (PcdGetBool(PcdShellSupportOldProtocols)){

+    ///@todo support ShellEnvironment2

+    ///@todo do we need to support ShellEnvironment (not ShellEnvironment2) also?

+  }

+

+  if (!EFI_ERROR(Status)) {

+    *NewShell = &mShellProtocol;

+  }

+  return (Status);

+}

+

+/**

+  Opposite of CreatePopulateInstallShellProtocol.

+

+  Free all memory and restore the system to the state it was in before calling

+  CreatePopulateInstallShellProtocol.

+

+  @param[in, out] NewShell   The pointer to the new shell protocol structure.

+

+  @retval EFI_SUCCESS       The operation was successful.

+**/

+EFI_STATUS

+EFIAPI

+CleanUpShellProtocol (

+  IN OUT EFI_SHELL_PROTOCOL  *NewShell

+  )

+{

+  EFI_STATUS                        Status;

+  SHELL_PROTOCOL_HANDLE_LIST        *Node2;

+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;

+

+  //

+  // if we need to restore old protocols...

+  //

+  if (!IsListEmpty(&ShellInfoObject.OldShellList.Link)) {

+    for (Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link)

+         ; !IsListEmpty (&ShellInfoObject.OldShellList.Link)

+         ; Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link)

+        ){

+      RemoveEntryList(&Node2->Link);

+      Status = gBS->ReinstallProtocolInterface(Node2->Handle,

+                                               &gEfiShellProtocolGuid,

+                                               NewShell,

+                                               Node2->Interface);

+      FreePool(Node2);

+    }

+  } else {

+    //

+    // no need to restore

+    //

+    Status = gBS->UninstallProtocolInterface(gImageHandle,

+                                             &gEfiShellProtocolGuid,

+                                             NewShell);

+  }

+  Status = gBS->CloseEvent(NewShell->ExecutionBreak);

+  NewShell->ExecutionBreak = NULL;

+

+  Status = gBS->OpenProtocol(

+    gST->ConsoleInHandle,

+    &gEfiSimpleTextInputExProtocolGuid,

+    (VOID**)&SimpleEx,

+    gImageHandle,

+    NULL,

+    EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+

+  if (!EFI_ERROR (Status)) {

+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle1);

+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle2);

+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle3);

+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle4);

+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle1);

+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle2);

+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle3);

+    Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle4);

+  }

+  return (Status);

+}

+

+/**

+  Notification function for keystrokes.

+

+  @param[in] KeyData    The key that was pressed.

+

+  @retval EFI_SUCCESS   The operation was successful.

+**/

+EFI_STATUS

+EFIAPI

+NotificationFunction(

+  IN EFI_KEY_DATA *KeyData

+  )

+{

+  if ( ((KeyData->Key.UnicodeChar == L'c') &&

+        (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))) ||

+      (KeyData->Key.UnicodeChar == 3)

+      ){ 

+    if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {

+      return (EFI_UNSUPPORTED);

+    }

+    return (gBS->SignalEvent(ShellInfoObject.NewEfiShellProtocol->ExecutionBreak));

+  } else if  ((KeyData->Key.UnicodeChar == L's') &&

+              (KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState  == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))

+              ){ 

+    ShellInfoObject.HaltOutput = TRUE;

+  }

+  return (EFI_SUCCESS);

+}

+

+/**

+  Function to start monitoring for CTRL-C using SimpleTextInputEx.  This 

+  feature's enabled state was not known when the shell initially launched.

+

+  @retval EFI_SUCCESS           The feature is enabled.

+  @retval EFI_OUT_OF_RESOURCES  There is not enough mnemory available.

+**/

+EFI_STATUS

+EFIAPI

+InernalEfiShellStartMonitor(

+  VOID

+  )

+{

+  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;

+  EFI_KEY_DATA                      KeyData;

+  EFI_STATUS                        Status;

+

+  Status = gBS->OpenProtocol(

+    gST->ConsoleInHandle,

+    &gEfiSimpleTextInputExProtocolGuid,

+    (VOID**)&SimpleEx,

+    gImageHandle,

+    NULL,

+    EFI_OPEN_PROTOCOL_GET_PROTOCOL);

+  if (EFI_ERROR(Status)) {

+    ShellPrintHiiEx(

+      -1, 

+      -1, 

+      NULL,

+      STRING_TOKEN (STR_SHELL_NO_IN_EX),

+      ShellInfoObject.HiiHandle);

+    return (EFI_SUCCESS);

+  }

+

+  if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {

+    return (EFI_UNSUPPORTED);

+  }

+

+  KeyData.KeyState.KeyToggleState = 0;

+  KeyData.Key.ScanCode            = 0;

+  KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;

+  KeyData.Key.UnicodeChar         = L'c';

+

+  Status = SimpleEx->RegisterKeyNotify(

+    SimpleEx,

+    &KeyData,

+    NotificationFunction,

+    &ShellInfoObject.CtrlCNotifyHandle1);

+  

+  KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;

+  if (!EFI_ERROR(Status)) {

+    Status = SimpleEx->RegisterKeyNotify(

+      SimpleEx,

+      &KeyData,

+      NotificationFunction,

+      &ShellInfoObject.CtrlCNotifyHandle2);

+  }

+  KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;

+  KeyData.Key.UnicodeChar         = 3;

+  if (!EFI_ERROR(Status)) {

+    Status = SimpleEx->RegisterKeyNotify(

+      SimpleEx,

+      &KeyData,

+      NotificationFunction,

+      &ShellInfoObject.CtrlCNotifyHandle3);

+  }

+  KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;

+  if (!EFI_ERROR(Status)) {

+    Status = SimpleEx->RegisterKeyNotify(

+      SimpleEx,

+      &KeyData,

+      NotificationFunction,

+      &ShellInfoObject.CtrlCNotifyHandle4);

+  }

+  return (Status);

+}

+