git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10874 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1512 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1512 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Provides interface to shell internal functions for shell commands.
 | 
						|
 | 
						|
  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "UefiShellCommandLib.h"
 | 
						|
 | 
						|
/// The tag for use in identifying UNICODE files.
 | 
						|
/// If the file is UNICODE, the first 16 bits of the file will equal this value.
 | 
						|
enum {
 | 
						|
  UnicodeFileTag = 0xFEFF
 | 
						|
};
 | 
						|
 | 
						|
// STATIC local variables
 | 
						|
STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY  mCommandList;
 | 
						|
STATIC SCRIPT_FILE_LIST                   mScriptList;
 | 
						|
STATIC ALIAS_LIST                         mAliasList;
 | 
						|
STATIC BOOLEAN                            mEchoState;
 | 
						|
STATIC BOOLEAN                            mExitRequested;
 | 
						|
STATIC BOOLEAN                            mExitScript;
 | 
						|
STATIC CHAR16                             *mProfileList;
 | 
						|
STATIC UINTN                              mProfileListSize;
 | 
						|
STATIC UINTN                              mFsMaxCount = 0;
 | 
						|
STATIC UINTN                              mBlkMaxCount = 0;
 | 
						|
STATIC BUFFER_LIST                        mFileHandleList;
 | 
						|
 | 
						|
// global variables required by library class.
 | 
						|
EFI_SHELL_PROTOCOL                *gEfiShellProtocol            = NULL;
 | 
						|
EFI_SHELL_PARAMETERS_PROTOCOL     *gEfiShellParametersProtocol  = NULL;
 | 
						|
EFI_UNICODE_COLLATION_PROTOCOL    *gUnicodeCollation            = NULL;
 | 
						|
EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *gDevPathToText               = NULL;
 | 
						|
SHELL_MAP_LIST                    gShellMapList;
 | 
						|
SHELL_MAP_LIST                    *gShellCurDir                 = NULL;
 | 
						|
 | 
						|
CONST CHAR16* SupportLevel[] = {
 | 
						|
  L"Minimal",
 | 
						|
  L"Scripting",
 | 
						|
  L"Basic",
 | 
						|
  L"Interactive"
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Function to make sure that the global protocol pointers are valid.
 | 
						|
  must be called after constructor before accessing the pointers.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CommandInit(
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS Status;
 | 
						|
  if (gEfiShellParametersProtocol == NULL) {
 | 
						|
    Status = gBS->OpenProtocol(gImageHandle,
 | 
						|
                               &gEfiShellParametersProtocolGuid,
 | 
						|
                               (VOID **)&gEfiShellParametersProtocol,
 | 
						|
                               gImageHandle,
 | 
						|
                               NULL,
 | 
						|
                               EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                              );
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      return (EFI_DEVICE_ERROR);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (gEfiShellProtocol == NULL) {
 | 
						|
    Status = gBS->LocateProtocol(&gEfiShellProtocolGuid, NULL, (VOID**)&gEfiShellProtocol);
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      return (EFI_DEVICE_ERROR);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (gUnicodeCollation == NULL) {
 | 
						|
    Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      return (EFI_DEVICE_ERROR);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (gDevPathToText == NULL) {
 | 
						|
    Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID**)&gDevPathToText);
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      return (EFI_DEVICE_ERROR);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (EFI_SUCCESS);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Constructor for the Shell Command library.
 | 
						|
 | 
						|
  Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
 | 
						|
 | 
						|
  @param ImageHandle    the image handle of the process
 | 
						|
  @param SystemTable    the EFI System Table pointer
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   the initialization was complete sucessfully
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
ShellCommandLibConstructor (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  InitializeListHead(&gShellMapList.Link);
 | 
						|
  InitializeListHead(&mCommandList.Link);
 | 
						|
  InitializeListHead(&mAliasList.Link);
 | 
						|
  InitializeListHead(&mScriptList.Link);
 | 
						|
  InitializeListHead(&mFileHandleList.Link);
 | 
						|
  mEchoState = TRUE;
 | 
						|
 | 
						|
  mExitRequested    = FALSE;
 | 
						|
  mExitScript       = FALSE;
 | 
						|
  mProfileListSize  = 0;
 | 
						|
  mProfileList      = NULL;
 | 
						|
 | 
						|
  if (gUnicodeCollation == NULL) {
 | 
						|
    Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      return (EFI_DEVICE_ERROR);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return (RETURN_SUCCESS);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Destructor for the library.  free any resources.
 | 
						|
 | 
						|
  @param ImageHandle    the image handle of the process
 | 
						|
  @param SystemTable    the EFI System Table pointer
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS this function always returns success
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
ShellCommandLibDestructor (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
 | 
						|
  COMMAND_LIST                      *Node2;
 | 
						|
  SCRIPT_FILE_LIST                  *Node3;
 | 
						|
  SHELL_MAP_LIST                    *MapNode;
 | 
						|
  //
 | 
						|
  // enumerate throught the list and free all the memory
 | 
						|
  //
 | 
						|
  while (!IsListEmpty (&mCommandList.Link)) {
 | 
						|
    Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link);
 | 
						|
    RemoveEntryList(&Node->Link);
 | 
						|
    SHELL_FREE_NON_NULL(Node->CommandString);
 | 
						|
    FreePool(Node);
 | 
						|
    DEBUG_CODE(Node = NULL;);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // enumerate through the init command list and free all memory
 | 
						|
  //
 | 
						|
  while (!IsListEmpty (&mAliasList.Link)) {
 | 
						|
    Node2 = (COMMAND_LIST *)GetFirstNode(&mAliasList.Link);
 | 
						|
    RemoveEntryList(&Node2->Link);
 | 
						|
    SHELL_FREE_NON_NULL(Node2->CommandString);
 | 
						|
    FreePool(Node2);
 | 
						|
    DEBUG_CODE(Node2 = NULL;);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // enumerate throught the list and free all the memory
 | 
						|
  //
 | 
						|
  while (!IsListEmpty (&mScriptList.Link)) {
 | 
						|
    Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);
 | 
						|
    RemoveEntryList(&Node3->Link);
 | 
						|
    DeleteScriptFileStruct(Node3->Data);
 | 
						|
    FreePool(Node3);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // enumerate throught the mappings list and free all the memory
 | 
						|
  //
 | 
						|
  if (!IsListEmpty(&gShellMapList.Link)) {
 | 
						|
    for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
 | 
						|
         ; !IsListEmpty (&gShellMapList.Link)
 | 
						|
         ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
 | 
						|
        ){
 | 
						|
      ASSERT(MapNode != NULL);
 | 
						|
      RemoveEntryList(&MapNode->Link);
 | 
						|
      SHELL_FREE_NON_NULL(MapNode->DevicePath);
 | 
						|
      SHELL_FREE_NON_NULL(MapNode->MapName);
 | 
						|
      SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath);
 | 
						|
      FreePool(MapNode);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (!IsListEmpty(&mFileHandleList.Link)){
 | 
						|
    FreeBufferList(&mFileHandleList);
 | 
						|
  }
 | 
						|
 | 
						|
  if (mProfileList != NULL) {
 | 
						|
    FreePool(mProfileList);
 | 
						|
  }
 | 
						|
 | 
						|
  return (RETURN_SUCCESS);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Checks if a command is already on the list.
 | 
						|
 | 
						|
  @param[in] CommandString        The command string to check for on the list.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ShellCommandIsCommandOnList (
 | 
						|
  IN CONST  CHAR16                      *CommandString
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
 | 
						|
 | 
						|
  //
 | 
						|
  // assert for NULL parameter
 | 
						|
  //
 | 
						|
  ASSERT(CommandString != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // check for the command
 | 
						|
  //
 | 
						|
  for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
 | 
						|
      ; !IsNull(&mCommandList.Link, &Node->Link)
 | 
						|
      ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
 | 
						|
     ){
 | 
						|
    ASSERT(Node->CommandString != NULL);
 | 
						|
    if (gUnicodeCollation->StriColl(
 | 
						|
          gUnicodeCollation,
 | 
						|
          (CHAR16*)CommandString,
 | 
						|
          Node->CommandString) == 0
 | 
						|
       ){
 | 
						|
      return (TRUE);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (FALSE);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get the help text for a command.
 | 
						|
 | 
						|
  @param[in] CommandString        The command name.
 | 
						|
 | 
						|
  @retval NULL  No help text was found.
 | 
						|
  @return       String of help text. Caller reuiqred to free.
 | 
						|
**/
 | 
						|
CHAR16*
 | 
						|
EFIAPI
 | 
						|
ShellCommandGetCommandHelp (
 | 
						|
  IN CONST  CHAR16                      *CommandString
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
 | 
						|
 | 
						|
  //
 | 
						|
  // assert for NULL parameter
 | 
						|
  //
 | 
						|
  ASSERT(CommandString != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // check for the command
 | 
						|
  //
 | 
						|
  for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
 | 
						|
      ; !IsNull(&mCommandList.Link, &Node->Link)
 | 
						|
      ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
 | 
						|
     ){
 | 
						|
    ASSERT(Node->CommandString != NULL);
 | 
						|
    if (gUnicodeCollation->StriColl(
 | 
						|
          gUnicodeCollation,
 | 
						|
          (CHAR16*)CommandString,
 | 
						|
          Node->CommandString) == 0
 | 
						|
       ){
 | 
						|
      return (HiiGetString(Node->HiiHandle, Node->ManFormatHelp, NULL));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Registers handlers of type SHELL_RUN_COMMAND and
 | 
						|
  SHELL_GET_MAN_FILENAME for each shell command.
 | 
						|
 | 
						|
  If the ShellSupportLevel is greater than the value of the
 | 
						|
  PcdShellSupportLevel then return RETURN_UNSUPPORTED.
 | 
						|
 | 
						|
  Registers the handlers specified by GetHelpInfoHandler and CommandHandler
 | 
						|
  with the command specified by CommandString. If the command named by
 | 
						|
  CommandString has already been registered, then return
 | 
						|
  RETURN_ALREADY_STARTED.
 | 
						|
 | 
						|
  If there are not enough resources available to register the handlers then
 | 
						|
  RETURN_OUT_OF_RESOURCES is returned.
 | 
						|
 | 
						|
  If CommandString is NULL, then ASSERT().
 | 
						|
  If GetHelpInfoHandler is NULL, then ASSERT().
 | 
						|
  If CommandHandler is NULL, then ASSERT().
 | 
						|
  If ProfileName is NULL, then ASSERT().
 | 
						|
 | 
						|
  @param[in]  CommandString         Pointer to the command name.  This is the
 | 
						|
                                    name to look for on the command line in
 | 
						|
                                    the shell.
 | 
						|
  @param[in]  CommandHandler        Pointer to a function that runs the
 | 
						|
                                    specified command.
 | 
						|
  @param[in]  GetManFileName        Pointer to a function that provides man
 | 
						|
                                    filename.
 | 
						|
  @param[in]  ShellMinSupportLevel  minimum Shell Support Level which has this
 | 
						|
                                    function.
 | 
						|
  @param[in]  ProfileName           profile name to require for support of this
 | 
						|
                                    function.
 | 
						|
  @param[in]  CanAffectLE           indicates whether this command's return value
 | 
						|
                                    can change the LASTERROR environment variable.
 | 
						|
  @param[in]  HiiHandle             Handle of this command's HII entry.
 | 
						|
  @param[in]  ManFormatHelp         HII locator for the help text.
 | 
						|
 | 
						|
  @retval  RETURN_SUCCESS           The handlers were registered.
 | 
						|
  @retval  RETURN_OUT_OF_RESOURCES  There are not enough resources available to
 | 
						|
                                    register the shell command.
 | 
						|
  @retval RETURN_UNSUPPORTED        the ShellMinSupportLevel was higher than the
 | 
						|
                                    currently allowed support level.
 | 
						|
  @retval RETURN_ALREADY_STARTED    The CommandString represents a command that
 | 
						|
                                    is already registered.  Only 1 handler set for
 | 
						|
                                    a given command is allowed.
 | 
						|
  @sa SHELL_GET_MAN_FILENAME
 | 
						|
  @sa SHELL_RUN_COMMAND
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
ShellCommandRegisterCommandName (
 | 
						|
  IN CONST  CHAR16                      *CommandString,
 | 
						|
  IN        SHELL_RUN_COMMAND           CommandHandler,
 | 
						|
  IN        SHELL_GET_MAN_FILENAME      GetManFileName,
 | 
						|
  IN        UINT32                      ShellMinSupportLevel,
 | 
						|
  IN CONST  CHAR16                      *ProfileName,
 | 
						|
  IN CONST  BOOLEAN                     CanAffectLE,
 | 
						|
  IN CONST  EFI_HANDLE                  HiiHandle,
 | 
						|
  IN CONST  EFI_STRING_ID               ManFormatHelp
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
 | 
						|
 | 
						|
  //
 | 
						|
  // ASSERTs for NULL parameters
 | 
						|
  //
 | 
						|
  ASSERT(CommandString  != NULL);
 | 
						|
  ASSERT(GetManFileName != NULL);
 | 
						|
  ASSERT(CommandHandler != NULL);
 | 
						|
  ASSERT(ProfileName    != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // check for shell support level
 | 
						|
  //
 | 
						|
  if (PcdGet8(PcdShellSupportLevel) < ShellMinSupportLevel) {
 | 
						|
    return (RETURN_UNSUPPORTED);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // check for already on the list
 | 
						|
  //
 | 
						|
  if (ShellCommandIsCommandOnList(CommandString)) {
 | 
						|
    return (RETURN_ALREADY_STARTED);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // allocate memory for new struct
 | 
						|
  //
 | 
						|
  Node = AllocatePool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY));
 | 
						|
  ASSERT(Node != NULL);
 | 
						|
  Node->CommandString = AllocatePool(StrSize(CommandString));
 | 
						|
  ASSERT(Node->CommandString != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // populate the new struct
 | 
						|
  //
 | 
						|
  StrCpy(Node->CommandString, CommandString);
 | 
						|
 | 
						|
  Node->GetManFileName  = GetManFileName;
 | 
						|
  Node->CommandHandler  = CommandHandler;
 | 
						|
  Node->LastError       = CanAffectLE;
 | 
						|
  Node->HiiHandle       = HiiHandle;
 | 
						|
  Node->ManFormatHelp   = ManFormatHelp;
 | 
						|
 | 
						|
  if ( StrLen(ProfileName)>0
 | 
						|
    && ((mProfileList != NULL
 | 
						|
    && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL)
 | 
						|
   ){
 | 
						|
    ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL));
 | 
						|
    if (mProfileList == NULL) {
 | 
						|
      //
 | 
						|
      // If this is the first make a leading ';'
 | 
						|
      //
 | 
						|
      StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);
 | 
						|
    }
 | 
						|
    StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0);
 | 
						|
    StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // add the new struct to the list
 | 
						|
  //
 | 
						|
  InsertTailList (&mCommandList.Link, &Node->Link);
 | 
						|
 | 
						|
  return (RETURN_SUCCESS);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to get the current Profile string.
 | 
						|
 | 
						|
  @retval NULL  There are no installed profiles.
 | 
						|
  @return       A semi-colon delimited list of profiles.
 | 
						|
**/
 | 
						|
CONST CHAR16 *
 | 
						|
EFIAPI
 | 
						|
ShellCommandGetProfileList (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (mProfileList);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Checks if a command string has been registered for CommandString and if so it runs
 | 
						|
  the previously registered handler for that command with the command line.
 | 
						|
 | 
						|
  If CommandString is NULL, then ASSERT().
 | 
						|
 | 
						|
  If Sections is specified, then each section name listed will be compared in a casesensitive
 | 
						|
  manner, to the section names described in Appendix B UEFI Shell 2.0 spec. 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          Sections          pointer to string representing which section to get help on.
 | 
						|
 | 
						|
  @param[in]  CommandString         Pointer to the command name.  This is the name
 | 
						|
                                    found on the command line in the shell.
 | 
						|
  @param[in,out] RetVal             Pointer to the return vaule from the command handler.
 | 
						|
 | 
						|
  @param[in,out]  CanAffectLE       indicates whether this command's return value
 | 
						|
                                    needs to be placed into LASTERROR environment variable.
 | 
						|
 | 
						|
  @retval RETURN_SUCCESS            The handler was run.
 | 
						|
  @retval RETURN_NOT_FOUND          The CommandString did not match a registered
 | 
						|
                                    command name.
 | 
						|
  @sa SHELL_RUN_COMMAND
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
ShellCommandRunCommandHandler (
 | 
						|
  IN CONST CHAR16               *CommandString,
 | 
						|
  IN OUT SHELL_STATUS           *RetVal,
 | 
						|
  IN OUT BOOLEAN                *CanAffectLE OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
 | 
						|
 | 
						|
  //
 | 
						|
  // assert for NULL parameters
 | 
						|
  //
 | 
						|
  ASSERT(CommandString != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // check for the command
 | 
						|
  //
 | 
						|
  for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
 | 
						|
      ; !IsNull(&mCommandList.Link, &Node->Link)
 | 
						|
      ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
 | 
						|
     ){
 | 
						|
    ASSERT(Node->CommandString != NULL);
 | 
						|
    if (gUnicodeCollation->StriColl(
 | 
						|
          gUnicodeCollation,
 | 
						|
          (CHAR16*)CommandString,
 | 
						|
          Node->CommandString) == 0
 | 
						|
       ){
 | 
						|
      if (CanAffectLE != NULL) {
 | 
						|
        *CanAffectLE = Node->LastError;
 | 
						|
      }
 | 
						|
      if (RetVal != NULL) {
 | 
						|
        *RetVal = Node->CommandHandler(NULL, gST);
 | 
						|
      } else {
 | 
						|
        Node->CommandHandler(NULL, gST);
 | 
						|
      }
 | 
						|
      return (RETURN_SUCCESS);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (RETURN_NOT_FOUND);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Checks if a command string has been registered for CommandString and if so it
 | 
						|
  returns the MAN filename specified for that command.
 | 
						|
 | 
						|
  If CommandString is NULL, then ASSERT().
 | 
						|
 | 
						|
  @param[in]  CommandString         Pointer to the command name.  This is the name
 | 
						|
                                    found on the command line in the shell.\
 | 
						|
 | 
						|
  @retval NULL                      the commandString was not a registered command.
 | 
						|
  @return other                     the name of the MAN file.
 | 
						|
  @sa SHELL_GET_MAN_FILENAME
 | 
						|
**/
 | 
						|
CONST CHAR16*
 | 
						|
EFIAPI
 | 
						|
ShellCommandGetManFileNameHandler (
 | 
						|
  IN CONST CHAR16               *CommandString
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;
 | 
						|
 | 
						|
  //
 | 
						|
  // assert for NULL parameters
 | 
						|
  //
 | 
						|
  ASSERT(CommandString != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // check for the command
 | 
						|
  //
 | 
						|
  for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)
 | 
						|
      ; !IsNull(&mCommandList.Link, &Node->Link)
 | 
						|
      ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)
 | 
						|
     ){
 | 
						|
    ASSERT(Node->CommandString != NULL);
 | 
						|
    if (gUnicodeCollation->StriColl(
 | 
						|
          gUnicodeCollation,
 | 
						|
          (CHAR16*)CommandString,
 | 
						|
          Node->CommandString) == 0
 | 
						|
       ){
 | 
						|
      return (Node->GetManFileName());
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get the list of all available shell internal commands.  This is a linked list
 | 
						|
  (via LIST_ENTRY structure).  enumerate through it using the BaseLib linked
 | 
						|
  list functions.  do not modify the values.
 | 
						|
 | 
						|
  @return a Linked list of all available shell commands.
 | 
						|
**/
 | 
						|
CONST COMMAND_LIST*
 | 
						|
EFIAPI
 | 
						|
ShellCommandGetCommandList (
 | 
						|
  )
 | 
						|
{
 | 
						|
  return ((COMMAND_LIST*)(&mCommandList));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Registers aliases to be set as part of the initialization of the shell application.
 | 
						|
 | 
						|
  If Command is NULL, then ASSERT().
 | 
						|
  If Alias is NULL, then ASSERT().
 | 
						|
 | 
						|
  @param[in]  Command               Pointer to the Command
 | 
						|
  @param[in]  Alias                 Pointer to Alias
 | 
						|
 | 
						|
  @retval  RETURN_SUCCESS           The handlers were registered.
 | 
						|
  @retval  RETURN_OUT_OF_RESOURCES  There are not enough resources available to
 | 
						|
                                    register the shell command.
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
ShellCommandRegisterAlias (
 | 
						|
  IN CONST CHAR16                       *Command,
 | 
						|
  IN CONST CHAR16                       *Alias
 | 
						|
  )
 | 
						|
{
 | 
						|
  ALIAS_LIST *Node;
 | 
						|
 | 
						|
  //
 | 
						|
  // Asserts for NULL
 | 
						|
  //
 | 
						|
  ASSERT(Command != NULL);
 | 
						|
  ASSERT(Alias   != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // allocate memory for new struct
 | 
						|
  //
 | 
						|
  Node = AllocatePool(sizeof(ALIAS_LIST));
 | 
						|
  ASSERT(Node != NULL);
 | 
						|
  Node->CommandString = AllocatePool(StrSize(Command));
 | 
						|
  Node->Alias = AllocatePool(StrSize(Alias));
 | 
						|
  ASSERT(Node->CommandString != NULL);
 | 
						|
  ASSERT(Node->Alias != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // populate the new struct
 | 
						|
  //
 | 
						|
  StrCpy(Node->CommandString, Command);
 | 
						|
  StrCpy(Node->Alias        , Alias );
 | 
						|
 | 
						|
  //
 | 
						|
  // add the new struct to the list
 | 
						|
  //
 | 
						|
  InsertTailList (&mAliasList.Link, &Node->Link);
 | 
						|
 | 
						|
  return (RETURN_SUCCESS);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get the list of all shell alias commands.  This is a linked list
 | 
						|
  (via LIST_ENTRY structure).  enumerate through it using the BaseLib linked
 | 
						|
  list functions.  do not modify the values.
 | 
						|
 | 
						|
  @return a Linked list of all requested shell alias'.
 | 
						|
**/
 | 
						|
CONST ALIAS_LIST*
 | 
						|
EFIAPI
 | 
						|
ShellCommandGetInitAliasList (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
    return (&mAliasList);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Determine if a given alias is on the list of built in alias'
 | 
						|
 | 
						|
  @param[in] Alias              The alias to test for
 | 
						|
 | 
						|
  @retval TRUE                  The alias is a built in alias
 | 
						|
  @retval FALSE                 The alias is not a built in alias
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ShellCommandIsOnAliasList(
 | 
						|
  IN CONST CHAR16 *Alias
 | 
						|
  )
 | 
						|
{
 | 
						|
  ALIAS_LIST *Node;
 | 
						|
 | 
						|
  //
 | 
						|
  // assert for NULL parameter
 | 
						|
  //
 | 
						|
  ASSERT(Alias != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // check for the Alias
 | 
						|
  //
 | 
						|
  for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link)
 | 
						|
      ; !IsNull(&mAliasList.Link, &Node->Link)
 | 
						|
      ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link)
 | 
						|
     ){
 | 
						|
    ASSERT(Node->CommandString != NULL);
 | 
						|
    ASSERT(Node->Alias != NULL);
 | 
						|
    if (gUnicodeCollation->StriColl(
 | 
						|
          gUnicodeCollation,
 | 
						|
          (CHAR16*)Alias,
 | 
						|
          Node->CommandString) == 0
 | 
						|
       ){
 | 
						|
      return (TRUE);
 | 
						|
    }
 | 
						|
    if (gUnicodeCollation->StriColl(
 | 
						|
          gUnicodeCollation,
 | 
						|
          (CHAR16*)Alias,
 | 
						|
          Node->Alias) == 0
 | 
						|
       ){
 | 
						|
      return (TRUE);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (FALSE);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to determine current state of ECHO.  Echo determins if lines from scripts
 | 
						|
  and ECHO commands are enabled.
 | 
						|
 | 
						|
  @retval TRUE    Echo is currently enabled
 | 
						|
  @retval FALSE   Echo is currently disabled
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ShellCommandGetEchoState(
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (mEchoState);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to set current state of ECHO.  Echo determins if lines from scripts
 | 
						|
  and ECHO commands are enabled.
 | 
						|
 | 
						|
  If State is TRUE, Echo will be enabled.
 | 
						|
  If State is FALSE, Echo will be disabled.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
ShellCommandSetEchoState(
 | 
						|
  IN BOOLEAN State
 | 
						|
  )
 | 
						|
{
 | 
						|
  mEchoState = State;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Indicate that the current shell or script should exit.
 | 
						|
 | 
						|
  @param[in] ScriptOnly   TRUE if only exiting a script, FALSE othrwise.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
ShellCommandRegisterExit (
 | 
						|
  IN BOOLEAN ScriptOnly
 | 
						|
  )
 | 
						|
{
 | 
						|
  mExitRequested = (BOOLEAN)(!mExitRequested);
 | 
						|
  if (mExitRequested) {
 | 
						|
    mExitScript    = ScriptOnly;
 | 
						|
  } else {
 | 
						|
    mExitScript    = FALSE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the Exit indicator.
 | 
						|
 | 
						|
  @retval TRUE      Exit was indicated.
 | 
						|
  @retval FALSE     Exis was not indicated.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ShellCommandGetExit (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (mExitRequested);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve the Exit script indicator.
 | 
						|
 | 
						|
  If ShellCommandGetExit returns FALSE than the return from this is undefined.
 | 
						|
 | 
						|
  @retval TRUE      ScriptOnly was indicated.
 | 
						|
  @retval FALSE     ScriptOnly was not indicated.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ShellCommandGetScriptExit (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  return (mExitScript);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to cleanup all memory from a SCRIPT_FILE structure.
 | 
						|
 | 
						|
  @param[in] Script     The pointer to the structure to cleanup.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
DeleteScriptFileStruct (
 | 
						|
  IN SCRIPT_FILE *Script
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8       LoopVar;
 | 
						|
  ASSERT(Script             != NULL);
 | 
						|
  ASSERT(Script->ScriptName != NULL);
 | 
						|
  for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) {
 | 
						|
    FreePool(Script->Argv[LoopVar]);
 | 
						|
  }
 | 
						|
  if (Script->Argv != NULL) {
 | 
						|
    FreePool(Script->Argv);
 | 
						|
  }
 | 
						|
  Script->CurrentCommand = NULL;
 | 
						|
  while (!IsListEmpty (&Script->CommandList)) {
 | 
						|
    Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList);
 | 
						|
    if (Script->CurrentCommand != NULL) {
 | 
						|
      RemoveEntryList(&Script->CurrentCommand->Link);
 | 
						|
      if (Script->CurrentCommand->Cl != NULL) {
 | 
						|
        FreePool(Script->CurrentCommand->Cl);
 | 
						|
      }
 | 
						|
      if (Script->CurrentCommand->Data != NULL) {
 | 
						|
        FreePool(Script->CurrentCommand->Data);
 | 
						|
      }
 | 
						|
      FreePool(Script->CurrentCommand);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  FreePool(Script->ScriptName);
 | 
						|
  FreePool(Script);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to return a pointer to the currently running script file object.
 | 
						|
 | 
						|
  @retval NULL        A script file is not currently running.
 | 
						|
  @return             A pointer to the current script file object.
 | 
						|
**/
 | 
						|
SCRIPT_FILE*
 | 
						|
EFIAPI
 | 
						|
ShellCommandGetCurrentScriptFile (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  SCRIPT_FILE_LIST *List;
 | 
						|
  if (IsListEmpty (&mScriptList.Link)) {
 | 
						|
    return (NULL);
 | 
						|
  }
 | 
						|
  List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link));
 | 
						|
  return (List->Data);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to set a new script as the currently running one.
 | 
						|
 | 
						|
  This function will correctly stack and unstack nested scripts.
 | 
						|
 | 
						|
  @param[in] Script   Pointer to new script information structure.  if NULL
 | 
						|
                      will remove and de-allocate the top-most Script structure.
 | 
						|
 | 
						|
  @return             A pointer to the current running script file after this
 | 
						|
                      change.  NULL if removing the final script.
 | 
						|
**/
 | 
						|
SCRIPT_FILE*
 | 
						|
EFIAPI
 | 
						|
ShellCommandSetNewScript (
 | 
						|
  IN SCRIPT_FILE *Script OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  SCRIPT_FILE_LIST *Node;
 | 
						|
  if (Script == NULL) {
 | 
						|
    if (IsListEmpty (&mScriptList.Link)) {
 | 
						|
      ASSERT(FALSE);
 | 
						|
      return (NULL);
 | 
						|
    }
 | 
						|
    Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);
 | 
						|
    RemoveEntryList(&Node->Link);
 | 
						|
    DeleteScriptFileStruct(Node->Data);
 | 
						|
    FreePool(Node);
 | 
						|
  } else {
 | 
						|
    Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST));
 | 
						|
    Node->Data = Script;
 | 
						|
    InsertHeadList(&mScriptList.Link, &Node->Link);
 | 
						|
  }
 | 
						|
  return (ShellCommandGetCurrentScriptFile());
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to generate the next default mapping name.
 | 
						|
 | 
						|
  If the return value is not NULL then it must be callee freed.
 | 
						|
 | 
						|
  @param Type                   What kind of mapping name to make.
 | 
						|
 | 
						|
  @retval NULL                  a memory allocation failed.
 | 
						|
  @return a new map name string
 | 
						|
**/
 | 
						|
CHAR16*
 | 
						|
EFIAPI
 | 
						|
ShellCommandCreateNewMappingName(
 | 
						|
  IN CONST SHELL_MAPPING_TYPE Type
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16  *String;
 | 
						|
  ASSERT(Type < MappingTypeMax);
 | 
						|
 | 
						|
  String = NULL;
 | 
						|
 | 
						|
  String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0]));
 | 
						|
  UnicodeSPrint(
 | 
						|
    String,
 | 
						|
    PcdGet8(PcdShellMapNameLength) * sizeof(String[0]),
 | 
						|
    Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:",
 | 
						|
    Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++);
 | 
						|
 | 
						|
  return (String);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to add a map node to the list of map items and update the "path" environment variable (optionally).
 | 
						|
 | 
						|
  If Path is TRUE (during initialization only), the path environment variable will also be updated to include
 | 
						|
  default paths on the new map name...
 | 
						|
 | 
						|
  Path should be FALSE when this function is called from the protocol SetMap function.
 | 
						|
 | 
						|
  @param[in] Name               The human readable mapped name.
 | 
						|
  @param[in] DevicePath         The Device Path for this map.
 | 
						|
  @param[in] Flags              The Flags attribute for this map item.
 | 
						|
  @param[in] Path               TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The addition was sucessful.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
 | 
						|
  @retval EFI_INVALID_PARAMETER A parameter was invalid.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
ShellCommandAddMapItemAndUpdatePath(
 | 
						|
  IN CONST CHAR16                   *Name,
 | 
						|
  IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
 | 
						|
  IN CONST UINT64                   Flags,
 | 
						|
  IN CONST BOOLEAN                  Path
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS      Status;
 | 
						|
  SHELL_MAP_LIST  *MapListNode;
 | 
						|
  CONST CHAR16    *OriginalPath;
 | 
						|
  CHAR16          *NewPath;
 | 
						|
  UINTN           NewPathSize;
 | 
						|
 | 
						|
  NewPathSize = 0;
 | 
						|
  NewPath = NULL;
 | 
						|
  OriginalPath = NULL;
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST));
 | 
						|
  if (MapListNode == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
  } else {
 | 
						|
    MapListNode->Flags = Flags;
 | 
						|
    MapListNode->MapName = AllocateZeroPool(StrSize(Name));
 | 
						|
    MapListNode->DevicePath = DuplicateDevicePath(DevicePath);
 | 
						|
    if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){
 | 
						|
      Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    } else {
 | 
						|
      StrCpy(MapListNode->MapName, Name);
 | 
						|
      InsertTailList(&gShellMapList.Link, &MapListNode->Link);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (EFI_ERROR(Status)) {
 | 
						|
    if (MapListNode != NULL) {
 | 
						|
      if (MapListNode->DevicePath != NULL) {
 | 
						|
        FreePool(MapListNode->DevicePath);
 | 
						|
      }
 | 
						|
      if (MapListNode->MapName != NULL) {
 | 
						|
        FreePool(MapListNode->MapName);
 | 
						|
      }
 | 
						|
      FreePool(MapListNode);
 | 
						|
    }
 | 
						|
  } else if (Path) {
 | 
						|
    //
 | 
						|
    // Since there was no error and Path was TRUE
 | 
						|
    // Now add the correct path for that mapping
 | 
						|
    //
 | 
						|
    OriginalPath = gEfiShellProtocol->GetEnv(L"path");
 | 
						|
    ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));
 | 
						|
    if (OriginalPath != NULL) {
 | 
						|
      StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);
 | 
						|
    } else {
 | 
						|
      StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0);
 | 
						|
    }
 | 
						|
    StrnCatGrow(&NewPath, &NewPathSize, L";", 0);
 | 
						|
    StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
 | 
						|
    StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);
 | 
						|
    StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
 | 
						|
    StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);
 | 
						|
    StrnCatGrow(&NewPath, &NewPathSize, Name, 0);
 | 
						|
    StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0);
 | 
						|
 | 
						|
    Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE);
 | 
						|
    ASSERT_EFI_ERROR(Status);
 | 
						|
    FreePool(NewPath);
 | 
						|
  }
 | 
						|
  return (Status);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Creates the default map names for each device path in the system with
 | 
						|
  a protocol depending on the Type.
 | 
						|
 | 
						|
  Creates the consistent map names for each device path in the system with
 | 
						|
  a protocol depending on the Type.
 | 
						|
 | 
						|
  Note: This will reset all mappings in the system("map -r").
 | 
						|
 | 
						|
  Also sets up the default path environment variable if Type is FileSystem.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           All map names were created sucessfully.
 | 
						|
  @retval EFI_NOT_FOUND         No protocols were found in the system.
 | 
						|
  @return                       Error returned from gBS->LocateHandle().
 | 
						|
 | 
						|
  @sa LocateHandle
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
ShellCommandCreateInitialMappingsAndPaths(
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_HANDLE                *HandleList;
 | 
						|
  UINTN                     Count;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  **DevicePathList;
 | 
						|
  CHAR16                    *NewDefaultName;
 | 
						|
  CHAR16                    *NewConsistName;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  **ConsistMappingTable;
 | 
						|
  SHELL_MAP_LIST            *MapListNode;
 | 
						|
 | 
						|
  HandleList  = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Reset the static members back to zero
 | 
						|
  //
 | 
						|
  mFsMaxCount = 0;
 | 
						|
  mBlkMaxCount = 0;
 | 
						|
 | 
						|
  gEfiShellProtocol->SetEnv(L"path", L"", TRUE);
 | 
						|
 | 
						|
  //
 | 
						|
  // First empty out the existing list.
 | 
						|
  //
 | 
						|
  if (!IsListEmpty(&gShellMapList.Link)) {
 | 
						|
    for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
 | 
						|
        ; !IsListEmpty(&gShellMapList.Link)
 | 
						|
        ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
 | 
						|
       ){
 | 
						|
          RemoveEntryList(&MapListNode->Link);
 | 
						|
          FreePool(MapListNode);
 | 
						|
    } // for loop
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Find each handle with Simple File System
 | 
						|
  //
 | 
						|
  HandleList = GetHandleListByPotocol(&gEfiSimpleFileSystemProtocolGuid);
 | 
						|
  if (HandleList != NULL) {
 | 
						|
    //
 | 
						|
    // Do a count of the handles
 | 
						|
    //
 | 
						|
    for (Count = 0 ; HandleList[Count] != NULL ; Count++);
 | 
						|
 | 
						|
    //
 | 
						|
    // Get all Device Paths
 | 
						|
    //
 | 
						|
    DevicePathList = AllocatePool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
 | 
						|
    ASSERT(DevicePathList != NULL);
 | 
						|
 | 
						|
    for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
 | 
						|
      DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Sort all DevicePaths
 | 
						|
    //
 | 
						|
    PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
 | 
						|
 | 
						|
    ShellCommandConsistMappingInitialize(&ConsistMappingTable);
 | 
						|
    //
 | 
						|
    // Assign new Mappings to all...
 | 
						|
    //
 | 
						|
    for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
 | 
						|
      //
 | 
						|
      // Get default name first
 | 
						|
      //
 | 
						|
      NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);
 | 
						|
      ASSERT(NewDefaultName != NULL);
 | 
						|
      Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE);
 | 
						|
      ASSERT_EFI_ERROR(Status);
 | 
						|
      FreePool(NewDefaultName);
 | 
						|
 | 
						|
      //
 | 
						|
      // Now do consistent name
 | 
						|
      //
 | 
						|
      NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);
 | 
						|
      if (NewConsistName != NULL) {
 | 
						|
        Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE);
 | 
						|
        ASSERT_EFI_ERROR(Status);
 | 
						|
        FreePool(NewConsistName);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    ShellCommandConsistMappingUnInitialize(ConsistMappingTable);
 | 
						|
 | 
						|
    SHELL_FREE_NON_NULL(HandleList);
 | 
						|
    SHELL_FREE_NON_NULL(DevicePathList);
 | 
						|
 | 
						|
    HandleList = NULL;
 | 
						|
  } else {
 | 
						|
    Count = (UINTN)-1;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Find each handle with Block Io
 | 
						|
  //
 | 
						|
  HandleList = GetHandleListByPotocol(&gEfiBlockIoProtocolGuid);
 | 
						|
  if (HandleList != NULL) {
 | 
						|
    for (Count = 0 ; HandleList[Count] != NULL ; Count++);
 | 
						|
 | 
						|
    //
 | 
						|
    // Get all Device Paths
 | 
						|
    //
 | 
						|
    DevicePathList = AllocatePool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);
 | 
						|
    ASSERT(DevicePathList != NULL);
 | 
						|
 | 
						|
    for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
 | 
						|
      DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Sort all DevicePaths
 | 
						|
    //
 | 
						|
    PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);
 | 
						|
 | 
						|
    //
 | 
						|
    // Assign new Mappings to all...
 | 
						|
    //
 | 
						|
    for (Count = 0 ; HandleList[Count] != NULL ; Count++) {
 | 
						|
      //
 | 
						|
      // Get default name first
 | 
						|
      //
 | 
						|
      NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo);
 | 
						|
      ASSERT(NewDefaultName != NULL);
 | 
						|
      Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE);
 | 
						|
      ASSERT_EFI_ERROR(Status);
 | 
						|
      FreePool(NewDefaultName);
 | 
						|
    }
 | 
						|
 | 
						|
    SHELL_FREE_NON_NULL(HandleList);
 | 
						|
    SHELL_FREE_NON_NULL(DevicePathList);
 | 
						|
  } else if (Count == (UINTN)-1) {
 | 
						|
    return (EFI_NOT_FOUND);
 | 
						|
  }
 | 
						|
 | 
						|
  return (EFI_SUCCESS);
 | 
						|
}
 | 
						|
 | 
						|
CHAR16*
 | 
						|
EFIAPI
 | 
						|
ShellCommandCleanPath (
 | 
						|
  IN OUT CHAR16 *Path
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16  *Path2;
 | 
						|
 | 
						|
  for (Path2 = Path ; Path2 != NULL && *Path2 != CHAR_NULL ; Path2++) {
 | 
						|
    if (*Path2 == L'/') {
 | 
						|
      *Path2 = L'\\';
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return (Path);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
 | 
						|
 | 
						|
  @param[in] Handle     The SHELL_FILE_HANDLE to convert.
 | 
						|
 | 
						|
  @return a EFI_FILE_PROTOCOL* representing the same file.
 | 
						|
**/
 | 
						|
EFI_FILE_PROTOCOL*
 | 
						|
EFIAPI
 | 
						|
ConvertShellHandleToEfiFileProtocol(
 | 
						|
  IN CONST SHELL_FILE_HANDLE Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  return ((EFI_FILE_PROTOCOL*)(Handle));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
 | 
						|
 | 
						|
  @param[in] Handle     The pointer to EFI_FILE_PROTOCOL to convert.
 | 
						|
  @param[in] Path       The path to the file for verification.
 | 
						|
 | 
						|
  @return a SHELL_FILE_HANDLE representing the same file.
 | 
						|
**/
 | 
						|
SHELL_FILE_HANDLE
 | 
						|
EFIAPI
 | 
						|
ConvertEfiFileProtocolToShellHandle(
 | 
						|
  IN CONST EFI_FILE_PROTOCOL *Handle,
 | 
						|
  IN CONST CHAR16            *Path
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_COMMAND_FILE_HANDLE *Buffer;
 | 
						|
  BUFFER_LIST               *NewNode;
 | 
						|
 | 
						|
  if (Path != NULL) {
 | 
						|
    Buffer              = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE));
 | 
						|
    ASSERT(Buffer  != NULL);
 | 
						|
    NewNode             = AllocatePool(sizeof(BUFFER_LIST));
 | 
						|
    ASSERT(NewNode != NULL);
 | 
						|
    Buffer->FileHandle  = (EFI_FILE_PROTOCOL*)Handle;
 | 
						|
    Buffer->Path        = StrnCatGrow(&Buffer->Path, NULL, Path, 0);
 | 
						|
    NewNode->Buffer     = Buffer;
 | 
						|
 | 
						|
    InsertHeadList(&mFileHandleList.Link, &NewNode->Link);
 | 
						|
  }
 | 
						|
  return ((SHELL_FILE_HANDLE)(Handle));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find the path that was logged with the specified SHELL_FILE_HANDLE.
 | 
						|
 | 
						|
  @param[in] Handle     The SHELL_FILE_HANDLE to query on.
 | 
						|
 | 
						|
  @return A pointer to the path for the file.
 | 
						|
**/
 | 
						|
CONST CHAR16*
 | 
						|
EFIAPI
 | 
						|
ShellFileHandleGetPath(
 | 
						|
  IN CONST SHELL_FILE_HANDLE Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  BUFFER_LIST               *Node;
 | 
						|
 | 
						|
  for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
 | 
						|
    ;  !IsNull(&mFileHandleList.Link, &Node->Link)
 | 
						|
    ;  Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
 | 
						|
   ){
 | 
						|
    if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
 | 
						|
      return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Remove a SHELL_FILE_HANDLE frmo the list of SHELL_FILE_HANDLES.
 | 
						|
 | 
						|
  @param[in] Handle     The SHELL_FILE_HANDLE to remove.
 | 
						|
 | 
						|
  @retval TRUE          The item was removed.
 | 
						|
  @retval FALSE         The item was not found.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ShellFileHandleRemove(
 | 
						|
  IN CONST SHELL_FILE_HANDLE Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  BUFFER_LIST               *Node;
 | 
						|
 | 
						|
  for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)
 | 
						|
    ;  !IsNull(&mFileHandleList.Link, &Node->Link)
 | 
						|
    ;  Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)
 | 
						|
   ){
 | 
						|
    if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){
 | 
						|
      SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);
 | 
						|
      RemoveEntryList(&Node->Link);
 | 
						|
      return (TRUE);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return (FALSE);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
 | 
						|
 | 
						|
  This will NOT work on directories.
 | 
						|
 | 
						|
  If Handle is NULL, then ASSERT.
 | 
						|
 | 
						|
  @param[in] Handle     the file handle
 | 
						|
 | 
						|
  @retval TRUE          the position is at the end of the file
 | 
						|
  @retval FALSE         the position is not at the end of the file
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ShellFileHandleEof(
 | 
						|
  IN SHELL_FILE_HANDLE Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FILE_INFO *Info;
 | 
						|
  UINT64        Pos;
 | 
						|
  BOOLEAN       RetVal;
 | 
						|
 | 
						|
  //
 | 
						|
  // ASSERT if Handle is NULL
 | 
						|
  //
 | 
						|
  ASSERT(Handle != NULL);
 | 
						|
 | 
						|
  gEfiShellProtocol->GetFilePosition(Handle, &Pos);
 | 
						|
  Info = gEfiShellProtocol->GetFileInfo (Handle);
 | 
						|
  ASSERT(Info != NULL);
 | 
						|
  gEfiShellProtocol->SetFilePosition(Handle, Pos);
 | 
						|
 | 
						|
  if (Info == NULL) {
 | 
						|
    return (FALSE);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Pos == Info->FileSize) {
 | 
						|
    RetVal = TRUE;
 | 
						|
  } else {
 | 
						|
    RetVal = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Info);
 | 
						|
 | 
						|
  return (RetVal);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned
 | 
						|
  buffer.  The returned buffer must be callee freed.
 | 
						|
 | 
						|
  If the position upon start is 0, then the Ascii Boolean will be set.  This should be
 | 
						|
  maintained and not changed for all operations with the same file.
 | 
						|
 | 
						|
  @param[in]      Handle        SHELL_FILE_HANDLE to read from.
 | 
						|
  @param[in,out]  Ascii         Boolean value for indicating whether the file is
 | 
						|
                                Ascii (TRUE) or UCS2 (FALSE).
 | 
						|
 | 
						|
  @return                       The line of text from the file.
 | 
						|
 | 
						|
  @sa ShellFileHandleReadLine
 | 
						|
**/
 | 
						|
CHAR16*
 | 
						|
EFIAPI
 | 
						|
ShellFileHandleReturnLine(
 | 
						|
  IN SHELL_FILE_HANDLE            Handle,
 | 
						|
  IN OUT BOOLEAN                *Ascii
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16          *RetVal;
 | 
						|
  UINTN           Size;
 | 
						|
  EFI_STATUS      Status;
 | 
						|
 | 
						|
  Size = 0;
 | 
						|
  RetVal = NULL;
 | 
						|
 | 
						|
  Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
 | 
						|
  if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
    RetVal = AllocatePool(Size);
 | 
						|
    Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
 | 
						|
  }
 | 
						|
  ASSERT_EFI_ERROR(Status);
 | 
						|
  if (EFI_ERROR(Status) && (RetVal != NULL)) {
 | 
						|
    FreePool(RetVal);
 | 
						|
    RetVal = NULL;
 | 
						|
  }
 | 
						|
  return (RetVal);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.
 | 
						|
 | 
						|
  If the position upon start is 0, then the Ascii Boolean will be set.  This should be
 | 
						|
  maintained and not changed for all operations with the same file.
 | 
						|
 | 
						|
  @param[in]      Handle        SHELL_FILE_HANDLE to read from.
 | 
						|
  @param[in,out]  Buffer        The pointer to buffer to read into.
 | 
						|
  @param[in,out]  Size          The pointer to number of bytes in Buffer.
 | 
						|
  @param[in]      Truncate      If the buffer is large enough, this has no effect.
 | 
						|
                                If the buffer is is too small and Truncate is TRUE,
 | 
						|
                                the line will be truncated.
 | 
						|
                                If the buffer is is too small and Truncate is FALSE,
 | 
						|
                                then no read will occur.
 | 
						|
 | 
						|
  @param[in,out]  Ascii         Boolean value for indicating whether the file is
 | 
						|
                                Ascii (TRUE) or UCS2 (FALSE).
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The operation was successful.  The line is stored in
 | 
						|
                                Buffer.
 | 
						|
  @retval EFI_INVALID_PARAMETER Handle was NULL.
 | 
						|
  @retval EFI_INVALID_PARAMETER Size was NULL.
 | 
						|
  @retval EFI_BUFFER_TOO_SMALL  Size was not large enough to store the line.
 | 
						|
                                Size was updated to the minimum space required.
 | 
						|
  @sa ShellFileHandleRead
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
ShellFileHandleReadLine(
 | 
						|
  IN SHELL_FILE_HANDLE          Handle,
 | 
						|
  IN OUT CHAR16                 *Buffer,
 | 
						|
  IN OUT UINTN                  *Size,
 | 
						|
  IN BOOLEAN                    Truncate,
 | 
						|
  IN OUT BOOLEAN                *Ascii
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  CHAR16      CharBuffer;
 | 
						|
  UINTN       CharSize;
 | 
						|
  UINTN       CountSoFar;
 | 
						|
  UINT64      OriginalFilePosition;
 | 
						|
 | 
						|
 | 
						|
  if (Handle == NULL
 | 
						|
    ||Size   == NULL
 | 
						|
   ){
 | 
						|
    return (EFI_INVALID_PARAMETER);
 | 
						|
  }
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    ASSERT(*Size == 0);
 | 
						|
  } else {
 | 
						|
    *Buffer = CHAR_NULL;
 | 
						|
  }
 | 
						|
  gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition);
 | 
						|
  if (OriginalFilePosition == 0) {
 | 
						|
    CharSize = sizeof(CHAR16);
 | 
						|
    Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
 | 
						|
    ASSERT_EFI_ERROR(Status);
 | 
						|
    if (CharBuffer == UnicodeFileTag) {
 | 
						|
      *Ascii = FALSE;
 | 
						|
    } else {
 | 
						|
      *Ascii = TRUE;
 | 
						|
      gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (CountSoFar = 0;;CountSoFar++){
 | 
						|
    CharBuffer = 0;
 | 
						|
    if (*Ascii) {
 | 
						|
      CharSize = sizeof(CHAR8);
 | 
						|
    } else {
 | 
						|
      CharSize = sizeof(CHAR16);
 | 
						|
    }
 | 
						|
    Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
 | 
						|
    if (  EFI_ERROR(Status)
 | 
						|
       || CharSize == 0
 | 
						|
       || (CharBuffer == L'\n' && !(*Ascii))
 | 
						|
       || (CharBuffer ==  '\n' && *Ascii)
 | 
						|
     ){
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // if we have space save it...
 | 
						|
    //
 | 
						|
    if ((CountSoFar+1)*sizeof(CHAR16) < *Size){
 | 
						|
      ASSERT(Buffer != NULL);
 | 
						|
      ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;
 | 
						|
      ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // if we ran out of space tell when...
 | 
						|
  //
 | 
						|
  if ((CountSoFar+1)*sizeof(CHAR16) > *Size){
 | 
						|
    *Size = (CountSoFar+1)*sizeof(CHAR16);
 | 
						|
    if (!Truncate) {
 | 
						|
      gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
 | 
						|
    } else {
 | 
						|
      DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));
 | 
						|
    }
 | 
						|
    return (EFI_BUFFER_TOO_SMALL);
 | 
						|
  }
 | 
						|
  while(Buffer[StrLen(Buffer)-1] == L'\r') {
 | 
						|
    Buffer[StrLen(Buffer)-1] = CHAR_NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  return (Status);
 | 
						|
}
 | 
						|
/**
 | 
						|
  Frees any BUFFER_LIST defined type.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
FreeBufferList (
 | 
						|
  IN BUFFER_LIST *List
 | 
						|
  )
 | 
						|
{
 | 
						|
  BUFFER_LIST               *BufferListEntry;
 | 
						|
 | 
						|
  if (List == NULL){
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // enumerate through the buffer list and free all memory
 | 
						|
  //
 | 
						|
  for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)
 | 
						|
      ; !IsListEmpty (&List->Link)
 | 
						|
      ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)
 | 
						|
     ){
 | 
						|
    RemoveEntryList(&BufferListEntry->Link);
 | 
						|
    ASSERT(BufferListEntry->Buffer != NULL);
 | 
						|
    if (BufferListEntry->Buffer != NULL) {
 | 
						|
      FreePool(BufferListEntry->Buffer);
 | 
						|
    }
 | 
						|
    FreePool(BufferListEntry);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Chops off last directory or file entry in a path leaving the trailing slash
 | 
						|
 | 
						|
  @param[in,out] Path
 | 
						|
 | 
						|
  @retval FALSE     No directory was found to chop off.
 | 
						|
  @retval TRUE      A directory was chopped off.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
ChopLastSlash(
 | 
						|
  IN OUT CHAR16 *PathToReturn
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16        *Walker;
 | 
						|
  CHAR16        *LastSlash = NULL;
 | 
						|
  //
 | 
						|
  // get directory name from path... ('chop' off extra)
 | 
						|
  //
 | 
						|
  for ( Walker = PathToReturn
 | 
						|
      ; Walker != NULL && *Walker != CHAR_NULL
 | 
						|
      ; Walker++
 | 
						|
     ){
 | 
						|
    if (*Walker == L'\\' && *(Walker + 1) != CHAR_NULL) {
 | 
						|
      LastSlash = Walker+1;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (LastSlash != NULL) {
 | 
						|
    *LastSlash = CHAR_NULL;
 | 
						|
    return (TRUE);
 | 
						|
  }
 | 
						|
  return (FALSE);
 | 
						|
}
 | 
						|
 |