REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the ShellPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
		
			
				
	
	
		
			4042 lines
		
	
	
		
			132 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			4042 lines
		
	
	
		
			132 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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>
 | 
						|
  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
 | 
						|
  Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Shell.h"
 | 
						|
 | 
						|
#define INIT_NAME_BUFFER_SIZE  128
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
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
 | 
						|
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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function creates a mapping for a device path.
 | 
						|
 | 
						|
  If both DevicePath 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);
 | 
						|
        SHELL_FREE_NON_NULL (MapListNode->DevicePath);
 | 
						|
        SHELL_FREE_NON_NULL (MapListNode->MapName);
 | 
						|
        SHELL_FREE_NON_NULL (MapListNode->CurrentDirectoryPath);
 | 
						|
        FreePool (MapListNode);
 | 
						|
        return (EFI_SUCCESS);
 | 
						|
      }
 | 
						|
    } // for loop
 | 
						|
 | 
						|
    //
 | 
						|
    // We didn't 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 separated 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)
 | 
						|
            )
 | 
						|
      {
 | 
						|
        //
 | 
						|
        // If any node is not a file path node, then the conversion can not be completed
 | 
						|
        //
 | 
						|
        if ((DevicePathType (&FilePath->Header) != MEDIA_DEVICE_PATH) ||
 | 
						|
            (DevicePathSubType (&FilePath->Header) != MEDIA_FILEPATH_DP))
 | 
						|
        {
 | 
						|
          FreePool (PathForReturn);
 | 
						|
          return NULL;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // append the path part onto the filepath.
 | 
						|
        //
 | 
						|
        ASSERT ((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));
 | 
						|
 | 
						|
        AlignedNode = AllocateCopyPool (DevicePathNodeLength (FilePath), FilePath);
 | 
						|
        if (AlignedNode == NULL) {
 | 
						|
          FreePool (PathForReturn);
 | 
						|
          return 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 / sizeof (CHAR16) - 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);
 | 
						|
    NewPath = AllocateZeroPool (Size);
 | 
						|
    if (NewPath == NULL) {
 | 
						|
      return (NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    StrCpyS (NewPath, Size/sizeof (CHAR16), Cwd);
 | 
						|
    StrCatS (NewPath, Size/sizeof (CHAR16), L"\\");
 | 
						|
    if (*Path == L'\\') {
 | 
						|
      Path++;
 | 
						|
      while (PathRemoveLastItem (NewPath)) {
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    StrCatS (NewPath, Size/sizeof (CHAR16), Path);
 | 
						|
    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)) != CHAR_NULL) &&
 | 
						|
      (*(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.
 | 
						|
  @retval Others                Error status returned from EFI_SIMPLE_FILE_SYSTEM_PROTOCOL->OpenVolume().
 | 
						|
**/
 | 
						|
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);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  *FileHandle = ConvertEfiFileProtocolToShellHandle (RealFileHandle, EfiShellGetMapFromDevicePath (&DevPath));
 | 
						|
  return (EFI_SUCCESS);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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 contained non-path elements
 | 
						|
  @retval other                   an error occurred.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
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 beginning 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 attributes.  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 device, 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;
 | 
						|
  BOOLEAN                   Volatile;
 | 
						|
 | 
						|
  //
 | 
						|
  // Is this for an environment variable
 | 
						|
  // do we start with >v
 | 
						|
  //
 | 
						|
  if (StrStr (FileName, L">v") == FileName) {
 | 
						|
    Status = IsVolatileEnv (FileName + 2, &Volatile);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!Volatile) {
 | 
						|
      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;
 | 
						|
  BOOLEAN                   Volatile;
 | 
						|
 | 
						|
  *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 / NULL file
 | 
						|
  //
 | 
						|
  if ((gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)FileName, L"NUL") == 0) ||
 | 
						|
      (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)FileName, L"NULL") == 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) {
 | 
						|
    Status = IsVolatileEnv (FileName + 2, &Volatile);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!Volatile &&
 | 
						|
        ((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);
 | 
						|
 | 
						|
  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
 | 
						|
  //
 | 
						|
  ShellFileHandleRemove (FileHandle);
 | 
						|
  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
 | 
						|
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);
 | 
						|
  ZeroMem (&ShellParamsProtocol, sizeof (EFI_SHELL_PARAMETERS_PROTOCOL));
 | 
						|
 | 
						|
  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);
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (NewCmdLine);
 | 
						|
    return (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  NewHandle,
 | 
						|
                  &gEfiLoadedImageProtocolGuid,
 | 
						|
                  (VOID **)&LoadedImage,
 | 
						|
                  gImageHandle,
 | 
						|
                  NULL,
 | 
						|
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                  );
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // If the image is not an app abort it.
 | 
						|
    //
 | 
						|
    if (LoadedImage->ImageCodeType != EfiLoaderCode) {
 | 
						|
      ShellPrintHiiEx (
 | 
						|
        -1,
 | 
						|
        -1,
 | 
						|
        NULL,
 | 
						|
        STRING_TOKEN (STR_SHELL_IMAGE_NOT_APP),
 | 
						|
        ShellInfoObject.HiiHandle
 | 
						|
        );
 | 
						|
      goto UnloadImage;
 | 
						|
    }
 | 
						|
 | 
						|
    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, Efi_Application, NULL, NULL);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto UnloadImage;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // 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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  internal worker function to load and run an image in the current shell.
 | 
						|
 | 
						|
  @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 the command line.
 | 
						|
 | 
						|
  @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
 | 
						|
InternalShellExecute (
 | 
						|
  IN CONST CHAR16  *CommandLine OPTIONAL,
 | 
						|
  IN CONST CHAR16  **Environment OPTIONAL,
 | 
						|
  OUT EFI_STATUS   *StartImageStatus OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  EFI_STATUS  CleanupStatus;
 | 
						|
  LIST_ENTRY  OrigEnvs;
 | 
						|
 | 
						|
  InitializeListHead (&OrigEnvs);
 | 
						|
 | 
						|
  //
 | 
						|
  // Save our current environment settings for later restoration if necessary
 | 
						|
  //
 | 
						|
  if (Environment != NULL) {
 | 
						|
    Status = GetEnvironmentVariableList (&OrigEnvs);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Status = SetEnvironmentVariables (Environment);
 | 
						|
    } else {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = RunShellCommand (CommandLine, StartImageStatus);
 | 
						|
 | 
						|
  // Restore environment variables
 | 
						|
  if (!IsListEmpty (&OrigEnvs)) {
 | 
						|
    CleanupStatus = SetEnvironmentVariableList (&OrigEnvs);
 | 
						|
    ASSERT_EFI_ERROR (CleanupStatus);
 | 
						|
  }
 | 
						|
 | 
						|
  return (Status);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Determine if the UEFI Shell is currently running with nesting enabled or disabled.
 | 
						|
 | 
						|
  @retval FALSE   nesting is required
 | 
						|
  @retval other   nesting is enabled
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
BOOLEAN
 | 
						|
NestingEnabled (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  CHAR16      *Temp;
 | 
						|
  CHAR16      *Temp2;
 | 
						|
  UINTN       TempSize;
 | 
						|
  BOOLEAN     RetVal;
 | 
						|
 | 
						|
  RetVal = TRUE;
 | 
						|
  Temp   = NULL;
 | 
						|
  Temp2  = NULL;
 | 
						|
 | 
						|
  if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) {
 | 
						|
    TempSize = 0;
 | 
						|
    Temp     = NULL;
 | 
						|
    Status   = SHELL_GET_ENVIRONMENT_VARIABLE (mNoNestingEnvVarName, &TempSize, Temp);
 | 
						|
    if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
      Temp = AllocateZeroPool (TempSize + sizeof (CHAR16));
 | 
						|
      if (Temp != NULL) {
 | 
						|
        Status = SHELL_GET_ENVIRONMENT_VARIABLE (mNoNestingEnvVarName, &TempSize, Temp);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    Temp2 = StrnCatGrow (&Temp2, NULL, mNoNestingTrue, 0);
 | 
						|
    if ((Temp != NULL) && (Temp2 != NULL) && (StringNoCaseCompare (&Temp, &Temp2) == 0)) {
 | 
						|
      //
 | 
						|
      // Use the no nesting method.
 | 
						|
      //
 | 
						|
      RetVal = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  SHELL_FREE_NON_NULL (Temp);
 | 
						|
  SHELL_FREE_NON_NULL (Temp2);
 | 
						|
  return (RetVal);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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 CommandLine.
 | 
						|
 | 
						|
  @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);
 | 
						|
  }
 | 
						|
 | 
						|
  if (NestingEnabled ()) {
 | 
						|
    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);
 | 
						|
  } else {
 | 
						|
    Status = InternalShellExecute (
 | 
						|
               (CONST CHAR16 *)CommandLine,
 | 
						|
               (CONST CHAR16 **)Environment,
 | 
						|
               StatusCode
 | 
						|
               );
 | 
						|
  }
 | 
						|
 | 
						|
  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
 | 
						|
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_STATUS           Status;
 | 
						|
  EFI_SHELL_FILE_INFO  *Duplicates;
 | 
						|
  EFI_SHELL_FILE_INFO  *ShellFileListItem;
 | 
						|
  EFI_SHELL_FILE_INFO  *ShellFileListItem2;
 | 
						|
  EFI_SHELL_FILE_INFO  *TempNode;
 | 
						|
 | 
						|
  if ((FileList == NULL) || (*FileList == NULL)) {
 | 
						|
    return (EFI_INVALID_PARAMETER);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = ShellSortFileList (
 | 
						|
             FileList,
 | 
						|
             &Duplicates,
 | 
						|
             ShellSortFileListByFullName
 | 
						|
             );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    EfiShellFreeFileList (&Duplicates);
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Fall back to the slow method that needs no extra memory, and so cannot
 | 
						|
  // fail.
 | 
						|
  //
 | 
						|
  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 occurred
 | 
						|
  @return != NULL     a pointer to the new node
 | 
						|
**/
 | 
						|
EFI_SHELL_FILE_INFO *
 | 
						|
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 occurred.
 | 
						|
  @return                     a pointer to the newly allocated structure.
 | 
						|
**/
 | 
						|
EFI_SHELL_FILE_INFO *
 | 
						|
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)
 | 
						|
        )
 | 
						|
  {
 | 
						|
    if (ShellFileList == NULL) {
 | 
						|
      ShellFileList = (EFI_SHELL_FILE_INFO *)AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));
 | 
						|
      if (ShellFileList == NULL) {
 | 
						|
        SHELL_FREE_NON_NULL (BasePath);
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
 | 
						|
      InitializeListHead (&ShellFileList->Link);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // allocate a new EFI_SHELL_FILE_INFO and populate it...
 | 
						|
    //
 | 
						|
    ShellFileListItem = CreateAndPopulateShellFileInfo (
 | 
						|
                          BasePath,
 | 
						|
                          EFI_SUCCESS, // success since we didn't fail to open it...
 | 
						|
                          FileInfo->FileName,
 | 
						|
                          NULL, // no handle since not open
 | 
						|
                          FileInfo
 | 
						|
                          );
 | 
						|
    if (ShellFileListItem == NULL) {
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
      //
 | 
						|
      // Free resources outside the loop.
 | 
						|
      //
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    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 (Guid, NewGuid);
 | 
						|
  }
 | 
						|
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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
 | 
						|
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));
 | 
						|
  if (CurrentFilePattern == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  StrnCpyS (CurrentFilePattern, NextFilePatternStart-FilePattern+1, 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) + StrSize (MapName);
 | 
						|
            NewFullName = AllocateZeroPool (Size);
 | 
						|
            if (NewFullName == NULL) {
 | 
						|
              Status = EFI_OUT_OF_RESOURCES;
 | 
						|
            } else {
 | 
						|
              StrCpyS (NewFullName, Size / sizeof (CHAR16), MapName);
 | 
						|
              StrCatS (NewFullName, Size / sizeof (CHAR16), ShellInfoNode->FullName);
 | 
						|
              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);
 | 
						|
              EfiShellClose (ShellInfoNode->Handle);
 | 
						|
              ShellInfoNode->Handle = NULL;
 | 
						|
            }
 | 
						|
          } else if (!EFI_ERROR (Status)) {
 | 
						|
            //
 | 
						|
            // should be a file
 | 
						|
            //
 | 
						|
 | 
						|
            //
 | 
						|
            // copy the information we need into a new Node
 | 
						|
            //
 | 
						|
            NewShellNode = InternalDuplicateShellFileInfo (ShellInfoNode, FALSE);
 | 
						|
            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);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((*FileList == NULL) || ((*FileList != NULL) && IsListEmpty (&(*FileList)->Link))) {
 | 
						|
    Status = EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  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 + 1;
 | 
						|
  ASSERT (Count <= StrLen (PatternCopy));
 | 
						|
 | 
						|
  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);
 | 
						|
        EfiShellClose (RootFileHandle);
 | 
						|
      }
 | 
						|
 | 
						|
      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);
 | 
						|
    StrnCatGrow (&Path2, &Path2Size, L"\\", 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;
 | 
						|
  ENV_VAR_LIST  *Node;
 | 
						|
  CHAR16        *CurrentWriteLocation;
 | 
						|
 | 
						|
  Size   = 0;
 | 
						|
  Buffer = NULL;
 | 
						|
 | 
						|
  if (Name == NULL) {
 | 
						|
    //
 | 
						|
    // Build the semi-colon delimited list. (2 passes)
 | 
						|
    //
 | 
						|
    for ( Node = (ENV_VAR_LIST *)GetFirstNode (&gShellEnvVarList.Link)
 | 
						|
          ; !IsNull (&gShellEnvVarList.Link, &Node->Link)
 | 
						|
          ; Node = (ENV_VAR_LIST *)GetNextNode (&gShellEnvVarList.Link, &Node->Link)
 | 
						|
          )
 | 
						|
    {
 | 
						|
      ASSERT (Node->Key != NULL);
 | 
						|
      Size += StrSize (Node->Key);
 | 
						|
    }
 | 
						|
 | 
						|
    Size += 2*sizeof (CHAR16);
 | 
						|
 | 
						|
    Buffer = AllocateZeroPool (Size);
 | 
						|
    if (Buffer == NULL) {
 | 
						|
      return (NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    CurrentWriteLocation = (CHAR16 *)Buffer;
 | 
						|
 | 
						|
    for ( Node = (ENV_VAR_LIST *)GetFirstNode (&gShellEnvVarList.Link)
 | 
						|
          ; !IsNull (&gShellEnvVarList.Link, &Node->Link)
 | 
						|
          ; Node = (ENV_VAR_LIST *)GetNextNode (&gShellEnvVarList.Link, &Node->Link)
 | 
						|
          )
 | 
						|
    {
 | 
						|
      ASSERT (Node->Key != NULL);
 | 
						|
      StrCpyS (
 | 
						|
        CurrentWriteLocation,
 | 
						|
        (Size)/sizeof (CHAR16) - (CurrentWriteLocation - ((CHAR16 *)Buffer)),
 | 
						|
        Node->Key
 | 
						|
        );
 | 
						|
      CurrentWriteLocation += StrLen (CurrentWriteLocation) + 1;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // We are doing a specific environment variable
 | 
						|
    //
 | 
						|
    Status = ShellFindEnvVarInList (Name, (CHAR16 **)&Buffer, &Size, Attributes);
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // 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 didn't 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);
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // If we did not find the environment variable in the gShellEnvVarList
 | 
						|
        // but get it from UEFI variable storage successfully then we need update
 | 
						|
        // the gShellEnvVarList.
 | 
						|
        //
 | 
						|
        ShellFreeEnvVarList ();
 | 
						|
        Status = ShellInitEnvVarList ();
 | 
						|
        ASSERT (Status == EFI_SUCCESS);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // 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
 | 
						|
InternalEfiShellSetEnv (
 | 
						|
  IN CONST CHAR16  *Name,
 | 
						|
  IN CONST CHAR16  *Value,
 | 
						|
  IN BOOLEAN       Volatile
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if ((Value == NULL) || (StrLen (Value) == 0)) {
 | 
						|
    Status = SHELL_DELETE_ENVIRONMENT_VARIABLE (Name);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      ShellRemvoeEnvVarFromList (Name);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    SHELL_DELETE_ENVIRONMENT_VARIABLE (Name);
 | 
						|
    Status = ShellAddEnvVarToList (
 | 
						|
               Name,
 | 
						|
               Value,
 | 
						|
               StrSize (Value),
 | 
						|
               EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE)
 | 
						|
               );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Status = Volatile
 | 
						|
             ? SHELL_SET_ENVIRONMENT_VARIABLE_V (Name, StrSize (Value) - sizeof (CHAR16), Value)
 | 
						|
             : SHELL_SET_ENVIRONMENT_VARIABLE_NV (Name, StrSize (Value) - sizeof (CHAR16), Value);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        ShellRemvoeEnvVarFromList (Name);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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 ((StrCmp (Name, L"cwd") == 0) ||
 | 
						|
      (StrCmp (Name, L"lasterror") == 0) ||
 | 
						|
      (StrCmp (Name, L"profiles") == 0) ||
 | 
						|
      (StrCmp (Name, L"uefishellsupport") == 0) ||
 | 
						|
      (StrCmp (Name, L"uefishellversion") == 0) ||
 | 
						|
      (StrCmp (Name, L"uefiversion") == 0) ||
 | 
						|
      (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest &&
 | 
						|
       (StrCmp (Name, mNoNestingEnvVarName) == 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).
 | 
						|
 | 
						|
  Note that the current directory string should exclude the tailing backslash character.
 | 
						|
 | 
						|
  @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
 | 
						|
 | 
						|
  Note that the current directory string should exclude the tailing backslash character.
 | 
						|
 | 
						|
  @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 successful
 | 
						|
  @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) {
 | 
						|
        gShellCurMapping = MapListItem;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      MapListItem = gShellCurMapping;
 | 
						|
    }
 | 
						|
 | 
						|
    if (MapListItem == NULL) {
 | 
						|
      FreePool (DirectoryName);
 | 
						|
      SHELL_FREE_NON_NULL (MapName);
 | 
						|
      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);
 | 
						|
      }
 | 
						|
 | 
						|
      FreePool (MapName);
 | 
						|
    } 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));
 | 
						|
      if (MapListItem->CurrentDirectoryPath != NULL) {
 | 
						|
        MapListItem->CurrentDirectoryPath[StrLen (MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // cant have a mapping in the directory...
 | 
						|
    //
 | 
						|
    if (StrStr (DirectoryName, L":") != NULL) {
 | 
						|
      FreePool (DirectoryName);
 | 
						|
      return (EFI_INVALID_PARAMETER);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // FileSystem != NULL
 | 
						|
    //
 | 
						|
    MapListItem = ShellCommandFindMapItem (FileSystem);
 | 
						|
    if (MapListItem == NULL) {
 | 
						|
      FreePool (DirectoryName);
 | 
						|
      return (EFI_INVALID_PARAMETER);
 | 
						|
    }
 | 
						|
 | 
						|
    //    gShellCurMapping = 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[StrLen (MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (DirectoryName);
 | 
						|
  //
 | 
						|
  // if updated the current directory then update the environment variable
 | 
						|
  //
 | 
						|
  if (MapListItem == gShellCurMapping) {
 | 
						|
    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));
 | 
						|
      if (FixCommand == NULL) {
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
 | 
						|
      StrnCpyS (
 | 
						|
        FixCommand,
 | 
						|
        (StrSize (Command) - 4 * sizeof (CHAR16))/sizeof (CHAR16),
 | 
						|
        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 delimited 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 occurred getting alias'
 | 
						|
  @return !NULL   a list of all alias'
 | 
						|
**/
 | 
						|
CHAR16 *
 | 
						|
InternalEfiShellGetListAlias (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  EFI_GUID    Guid;
 | 
						|
  CHAR16      *VariableName;
 | 
						|
  UINTN       NameSize;
 | 
						|
  UINTN       NameBufferSize;
 | 
						|
  CHAR16      *RetVal;
 | 
						|
  UINTN       RetSize;
 | 
						|
 | 
						|
  NameBufferSize = INIT_NAME_BUFFER_SIZE;
 | 
						|
  VariableName   = AllocateZeroPool (NameBufferSize);
 | 
						|
  RetSize        = 0;
 | 
						|
  RetVal         = NULL;
 | 
						|
 | 
						|
  if (VariableName == NULL) {
 | 
						|
    return (NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  VariableName[0] = CHAR_NULL;
 | 
						|
 | 
						|
  while (TRUE) {
 | 
						|
    NameSize = NameBufferSize;
 | 
						|
    Status   = gRT->GetNextVariableName (&NameSize, VariableName, &Guid);
 | 
						|
    if (Status == EFI_NOT_FOUND) {
 | 
						|
      break;
 | 
						|
    } else if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
      NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;
 | 
						|
      SHELL_FREE_NON_NULL (VariableName);
 | 
						|
      VariableName = AllocateZeroPool (NameBufferSize);
 | 
						|
      if (VariableName == NULL) {
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        SHELL_FREE_NON_NULL (RetVal);
 | 
						|
        RetVal = NULL;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      NameSize = NameBufferSize;
 | 
						|
      Status   = gRT->GetNextVariableName (&NameSize, VariableName, &Guid);
 | 
						|
    }
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      SHELL_FREE_NON_NULL (RetVal);
 | 
						|
      RetVal = NULL;
 | 
						|
      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
 | 
						|
 | 
						|
  SHELL_FREE_NON_NULL (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 occurred
 | 
						|
  @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;
 | 
						|
  CHAR16      *AliasVal;
 | 
						|
 | 
						|
  // Convert to lowercase to make aliases case-insensitive
 | 
						|
  if (Alias != NULL) {
 | 
						|
    AliasLower = AllocateCopyPool (StrSize (Alias), Alias);
 | 
						|
    if (AliasLower == NULL) {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    ToLower (AliasLower);
 | 
						|
 | 
						|
    if (Volatile == NULL) {
 | 
						|
      GetVariable2 (AliasLower, &gShellAliasGuid, (VOID **)&AliasVal, NULL);
 | 
						|
      FreePool (AliasLower);
 | 
						|
      return (AddBufferToFreeList (AliasVal));
 | 
						|
    }
 | 
						|
 | 
						|
    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);
 | 
						|
      }
 | 
						|
 | 
						|
      FreePool (AliasLower);
 | 
						|
      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
 | 
						|
InternalSetAlias (
 | 
						|
  IN CONST CHAR16  *Command,
 | 
						|
  IN CONST CHAR16  *Alias,
 | 
						|
  IN BOOLEAN       Volatile
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  CHAR16      *AliasLower;
 | 
						|
  BOOLEAN     DeleteAlias;
 | 
						|
 | 
						|
  DeleteAlias = FALSE;
 | 
						|
  if (Alias == NULL) {
 | 
						|
    //
 | 
						|
    // We must be trying to remove one if Alias is NULL
 | 
						|
    // remove an alias (but passed in COMMAND parameter)
 | 
						|
    //
 | 
						|
    Alias       = Command;
 | 
						|
    DeleteAlias = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (Alias != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Convert to lowercase to make aliases case-insensitive
 | 
						|
  //
 | 
						|
  AliasLower = AllocateCopyPool (StrSize (Alias), Alias);
 | 
						|
  if (AliasLower == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  ToLower (AliasLower);
 | 
						|
 | 
						|
  if (DeleteAlias) {
 | 
						|
    Status = gRT->SetVariable (AliasLower, &gShellAliasGuid, 0, 0, NULL);
 | 
						|
  } else {
 | 
						|
    Status = gRT->SetVariable (
 | 
						|
                    AliasLower,
 | 
						|
                    &gShellAliasGuid,
 | 
						|
                    EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE),
 | 
						|
                    StrSize (Command),
 | 
						|
                    (VOID *)Command
 | 
						|
                    );
 | 
						|
  }
 | 
						|
 | 
						|
  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
 | 
						|
CreatePopulateInstallShellProtocol (
 | 
						|
  IN OUT EFI_SHELL_PROTOCOL  **NewShell
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  UINTN                       BufferSize;
 | 
						|
  EFI_HANDLE                  *Buffer;
 | 
						|
  UINTN                       HandleCounter;
 | 
						|
  SHELL_PROTOCOL_HANDLE_LIST  *OldProtocolNode;
 | 
						|
  EFI_SHELL_PROTOCOL          *OldShell;
 | 
						|
 | 
						|
  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++) {
 | 
						|
      Status = gBS->OpenProtocol (
 | 
						|
                      Buffer[HandleCounter],
 | 
						|
                      &gEfiShellProtocolGuid,
 | 
						|
                      (VOID **)&OldShell,
 | 
						|
                      gImageHandle,
 | 
						|
                      NULL,
 | 
						|
                      EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                      );
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        OldProtocolNode = AllocateZeroPool (sizeof (SHELL_PROTOCOL_HANDLE_LIST));
 | 
						|
        if (OldProtocolNode == NULL) {
 | 
						|
          if (!IsListEmpty (&ShellInfoObject.OldShellList.Link)) {
 | 
						|
            CleanUpShellProtocol (&mShellProtocol);
 | 
						|
          }
 | 
						|
 | 
						|
          Status = EFI_OUT_OF_RESOURCES;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // reinstall over the old one...
 | 
						|
        //
 | 
						|
        OldProtocolNode->Handle    = Buffer[HandleCounter];
 | 
						|
        OldProtocolNode->Interface = OldShell;
 | 
						|
        Status                     = gBS->ReinstallProtocolInterface (
 | 
						|
                                            OldProtocolNode->Handle,
 | 
						|
                                            &gEfiShellProtocolGuid,
 | 
						|
                                            OldProtocolNode->Interface,
 | 
						|
                                            (VOID *)(&mShellProtocol)
 | 
						|
                                            );
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          //
 | 
						|
          // we reinstalled successfully.  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
 | 
						|
CleanUpShellProtocol (
 | 
						|
  IN OUT EFI_SHELL_PROTOCOL  *NewShell
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_PROTOCOL_HANDLE_LIST  *Node2;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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);
 | 
						|
      gBS->ReinstallProtocolInterface (Node2->Handle, &gEfiShellProtocolGuid, NewShell, Node2->Interface);
 | 
						|
      FreePool (Node2);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // no need to restore
 | 
						|
    //
 | 
						|
    gBS->UninstallProtocolInterface (gImageHandle, &gEfiShellProtocolGuid, NewShell);
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Cleanup the shell environment.
 | 
						|
 | 
						|
  @param[in, out] NewShell   The pointer to the new shell protocol structure.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       The operation was successful.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CleanUpShellEnvironment (
 | 
						|
  IN OUT EFI_SHELL_PROTOCOL  *NewShell
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                         Status;
 | 
						|
  EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL  *SimpleEx;
 | 
						|
 | 
						|
  CleanUpShellProtocol (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 memory available.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
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);
 | 
						|
}
 |