summaryrefslogtreecommitdiff
path: root/ShellPkg/Application/Shell/ShellProtocol.c
diff options
context:
space:
mode:
authorkx <kx@radix.pro>2024-06-04 06:43:08 +0300
committerkx <kx@radix.pro>2024-06-04 06:43:08 +0300
commit7e2ccccace24636f29ddc210b94606abd4c7e42b (patch)
tree545d43ea12671048956cafeb12303e84d601e571 /ShellPkg/Application/Shell/ShellProtocol.c
parent27b044605cd5f6b33a3d231576003850b3fe305b (diff)
downloadedk2-trunk.tar.xz
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'ShellPkg/Application/Shell/ShellProtocol.c')
-rw-r--r--ShellPkg/Application/Shell/ShellProtocol.c8098
1 files changed, 4049 insertions, 4049 deletions
diff --git a/ShellPkg/Application/Shell/ShellProtocol.c b/ShellPkg/Application/Shell/ShellProtocol.c
index da8c31cb03..031a876a3e 100644
--- a/ShellPkg/Application/Shell/ShellProtocol.c
+++ b/ShellPkg/Application/Shell/ShellProtocol.c
@@ -1,4049 +1,4049 @@
-/** @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);
- }
-
- //
- // Do not call SetDevicePathEndNode() if the device path node is already the
- // end of an entire device path.
- //
- if (!IsDevicePathEnd (*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.
- //
- Status = PARSE_HANDLE_DATABASE_PARENTS (DeviceHandle, &ParentControllerCount, &ParentControllerBuffer);
- if ((DeviceNameToReturn == NULL) && !EFI_ERROR (Status)) {
- for (LoopVar = 0; LoopVar < ParentControllerCount; LoopVar++) {
- Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (ParentControllerBuffer[LoopVar], &ParentDriverCount, &ParentDriverBuffer);
- if (!EFI_ERROR (Status)) {
- 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);
-}
+/** @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);
+ }
+
+ //
+ // Do not call SetDevicePathEndNode() if the device path node is already the
+ // end of an entire device path.
+ //
+ if (!IsDevicePathEnd (*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.
+ //
+ Status = PARSE_HANDLE_DATABASE_PARENTS (DeviceHandle, &ParentControllerCount, &ParentControllerBuffer);
+ if ((DeviceNameToReturn == NULL) && !EFI_ERROR (Status)) {
+ for (LoopVar = 0; LoopVar < ParentControllerCount; LoopVar++) {
+ Status = PARSE_HANDLE_DATABASE_UEFI_DRIVERS (ParentControllerBuffer[LoopVar], &ParentDriverCount, &ParentDriverBuffer);
+ if (!EFI_ERROR (Status)) {
+ 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);
+}