+/** @file\r
+ Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
+ manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Shell.h"\r
+#include <Library/FileHandleLib.h>\r
+\r
+/**\r
+ Close an open file handle.\r
+\r
+ This function closes a specified file handle. All "dirty" cached file data is\r
+ flushed to the device, and the file is closed. In all cases the handle is\r
+ closed.\r
+\r
+ @param[in] FileHandle The file handle to close.\r
+\r
+ @retval EFI_SUCCESS The file handle was closed successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellClose (\r
+ IN SHELL_FILE_HANDLE FileHandle\r
+ )\r
+{\r
+ ShellFileHandleRemove(FileHandle);\r
+ return (FileHandleClose(FileHandle));\r
+}\r
+\r
+/**\r
+ Internal worker to determine whether there is a file system somewhere\r
+ upon the device path specified.\r
+\r
+ @param[in] DevicePath The device path to test.\r
+\r
+ @retval TRUE gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path\r
+ @retval FALSE gEfiSimpleFileSystemProtocolGuid was not found.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+InternalShellProtocolIsSimpleFileSystemPresent(\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+\r
+ Handle = NULL;\r
+\r
+ DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath;\r
+ Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);\r
+\r
+ if ((Handle != NULL) && (!EFI_ERROR(Status))) {\r
+ return (TRUE);\r
+ }\r
+ return (FALSE);\r
+}\r
+\r
+/**\r
+ Internal worker debug helper function to print out maps as they are added.\r
+\r
+ @param[in] Mapping string mapping that has been added\r
+ @param[in] DevicePath pointer to device path that has been mapped.\r
+\r
+ @retval EFI_SUCCESS the operation was successful.\r
+ @return other an error ocurred\r
+\r
+ @sa LocateHandle\r
+ @sa OpenProtocol\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InternalShellProtocolDebugPrintMessage (\r
+ IN CONST CHAR16 *Mapping,\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathToText;\r
+ EFI_STATUS Status;\r
+ CHAR16 *Temp;\r
+\r
+ Status = EFI_SUCCESS;\r
+ DEBUG_CODE_BEGIN();\r
+ DevicePathToText = NULL;\r
+\r
+ Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid,\r
+ NULL,\r
+ (VOID**)&DevicePathToText);\r
+ if (Mapping != NULL) {\r
+ DEBUG((EFI_D_INFO, "Added new map item:\"%S\"\r\n", Mapping));\r
+ }\r
+ if (!EFI_ERROR(Status)) {\r
+ if (DevicePath != NULL) {\r
+ Temp = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
+ DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp));\r
+ FreePool(Temp);\r
+ }\r
+ }\r
+ DEBUG_CODE_END();\r
+ return (Status);\r
+}\r
+\r
+/**\r
+ This function creates a mapping for a device path.\r
+\r
+ If both DeviecPath and Mapping are NULL, this will reset the mapping to default values.\r
+\r
+ @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping,\r
+ then the mapping will be deleted.\r
+ @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':'\r
+\r
+ @retval EFI_SUCCESS Mapping created or deleted successfully.\r
+ @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the\r
+ boot service function LocateDevicePath().\r
+ @retval EFI_ACCESS_DENIED The mapping is a built-in alias.\r
+ @retval EFI_INVALID_PARAMETER Mapping was NULL\r
+ @retval EFI_INVALID_PARAMETER Mapping did not end with a ':'\r
+ @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed.\r
+ @retval EFI_NOT_FOUND There was no mapping found to delete\r
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellSetMap(\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,\r
+ IN CONST CHAR16 *Mapping\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SHELL_MAP_LIST *MapListNode;\r
+\r
+ if (Mapping == NULL){\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ if (Mapping[StrLen(Mapping)-1] != ':') {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ //\r
+ // Delete the mapping\r
+ //\r
+ if (DevicePath == NULL) {\r
+ if (IsListEmpty(&gShellMapList.Link)) {\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+ for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
+ ; !IsNull(&gShellMapList.Link, &MapListNode->Link)\r
+ ; MapListNode = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListNode->Link)\r
+ ){\r
+ if (StringNoCaseCompare(&MapListNode->MapName, &Mapping) == 0) {\r
+ RemoveEntryList(&MapListNode->Link);\r
+ FreePool(MapListNode);\r
+ return (EFI_SUCCESS);\r
+ }\r
+ } // for loop\r
+\r
+ //\r
+ // We didnt find one to delete\r
+ //\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+\r
+ //\r
+ // make sure this is a valid to add device path\r
+ //\r
+ ///@todo add BlockIo to this test...\r
+ if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath)) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ //\r
+ // First make sure there is no old mapping\r
+ //\r
+ Status = EfiShellSetMap(NULL, Mapping);\r
+ if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_FOUND)) {\r
+ return (Status);\r
+ }\r
+\r
+ //\r
+ // now add the new one.\r
+ //\r
+ Status = ShellCommandAddMapItemAndUpdatePath(Mapping, DevicePath, 0, FALSE);\r
+\r
+ return(Status);\r
+}\r
+\r
+/**\r
+ Gets the device path from the mapping.\r
+\r
+ This function gets the device path associated with a mapping.\r
+\r
+ @param Mapping A pointer to the mapping\r
+\r
+ @retval !=NULL Pointer to the device path that corresponds to the\r
+ device mapping. The returned pointer does not need\r
+ to be freed.\r
+ @retval NULL There is no device path associated with the\r
+ specified mapping.\r
+**/\r
+CONST EFI_DEVICE_PATH_PROTOCOL *\r
+EFIAPI\r
+EfiShellGetDevicePathFromMap(\r
+ IN CONST CHAR16 *Mapping\r
+ )\r
+{\r
+ SHELL_MAP_LIST *MapListItem;\r
+ CHAR16 *NewName;\r
+ UINTN Size;\r
+\r
+ NewName = NULL;\r
+ Size = 0;\r
+\r
+ StrnCatGrow(&NewName, &Size, Mapping, 0);\r
+ if (Mapping[StrLen(Mapping)-1] != L':') {\r
+ StrnCatGrow(&NewName, &Size, L":", 0);\r
+ }\r
+\r
+ MapListItem = ShellCommandFindMapItem(NewName);\r
+\r
+ FreePool(NewName);\r
+\r
+ if (MapListItem != NULL) {\r
+ return (MapListItem->DevicePath);\r
+ }\r
+ return(NULL);\r
+}\r
+\r
+/**\r
+ Gets the mapping(s) that most closely matches the device path.\r
+\r
+ This function gets the mapping which corresponds to the device path *DevicePath. If\r
+ there is no exact match, then the mapping which most closely matches *DevicePath\r
+ is returned, and *DevicePath is updated to point to the remaining portion of the\r
+ device path. If there is an exact match, the mapping is returned and *DevicePath\r
+ points to the end-of-device-path node.\r
+\r
+ If there are multiple map names they will be semi-colon seperated in the\r
+ NULL-terminated string.\r
+\r
+ @param DevicePath On entry, points to a device path pointer. On\r
+ exit, updates the pointer to point to the\r
+ portion of the device path after the mapping.\r
+\r
+ @retval NULL No mapping was found.\r
+ @return !=NULL Pointer to NULL-terminated mapping. The buffer\r
+ is callee allocated and should be freed by the caller.\r
+**/\r
+CONST CHAR16 *\r
+EFIAPI\r
+EfiShellGetMapFromDevicePath(\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ )\r
+{\r
+ SHELL_MAP_LIST *Node;\r
+ CHAR16 *PathForReturn;\r
+ UINTN PathSize;\r
+// EFI_HANDLE PathHandle;\r
+// EFI_HANDLE MapHandle;\r
+// EFI_STATUS Status;\r
+// EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
+// EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;\r
+\r
+ if (DevicePath == NULL || *DevicePath == NULL) {\r
+ return (NULL);\r
+ }\r
+\r
+ PathForReturn = NULL;\r
+ PathSize = 0;\r
+\r
+ for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
+ ; !IsNull(&gShellMapList.Link, &Node->Link)\r
+ ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
+ ){\r
+ //\r
+ // check for exact match\r
+ //\r
+ if (DevicePathCompare(DevicePath, &Node->DevicePath) == 0) {\r
+ ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
+ if (PathSize != 0) {\r
+ PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
+ }\r
+ PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
+ }\r
+ }\r
+ if (PathForReturn != NULL) {\r
+ while (!IsDevicePathEndType (*DevicePath)) {\r
+ *DevicePath = NextDevicePathNode (*DevicePath);\r
+ }\r
+ SetDevicePathEndNode (*DevicePath);\r
+ }\r
+/*\r
+ ///@todo finish code for inexact matches.\r
+ if (PathForReturn == NULL) {\r
+ PathSize = 0;\r
+\r
+ DevicePathCopy = DuplicateDevicePath(*DevicePath);\r
+ ASSERT(DevicePathCopy != NULL);\r
+ Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);\r
+ ASSERT_EFI_ERROR(Status);\r
+ //\r
+ // check each of the device paths we have to get the root of the path for consist mappings\r
+ //\r
+ for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
+ ; !IsNull(&gShellMapList.Link, &Node->Link)\r
+ ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
+ ){\r
+ if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) {\r
+ continue;\r
+ }\r
+ MapPathCopy = DuplicateDevicePath(Node->DevicePath);\r
+ ASSERT(MapPathCopy != NULL);\r
+ Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
+ if (MapHandle == PathHandle) {\r
+\r
+ *DevicePath = DevicePathCopy;\r
+\r
+ MapPathCopy = NULL;\r
+ DevicePathCopy = NULL;\r
+ PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
+ PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // now add on the non-consistent mappings\r
+ //\r
+ for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
+ ; !IsNull(&gShellMapList.Link, &Node->Link)\r
+ ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
+ ){\r
+ if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) {\r
+ continue;\r
+ }\r
+ MapPathCopy = Node->DevicePath;\r
+ ASSERT(MapPathCopy != NULL);\r
+ Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
+ if (MapHandle == PathHandle) {\r
+ PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
+ PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+*/\r
+\r
+ return (AddBufferToFreeList(PathForReturn));\r
+}\r
+\r
+/**\r
+ Converts a device path to a file system-style path.\r
+\r
+ This function converts a device path to a file system path by replacing part, or all, of\r
+ the device path with the file-system mapping. If there are more than one application\r
+ file system mappings, the one that most closely matches Path will be used.\r
+\r
+ @param Path The pointer to the device path\r
+\r
+ @retval NULL the device path could not be found.\r
+ @return all The pointer of the NULL-terminated file path. The path\r
+ is callee-allocated and should be freed by the caller.\r
+**/\r
+CHAR16 *\r
+EFIAPI\r
+EfiShellGetFilePathFromDevicePath(\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *Path\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
+ EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;\r
+ SHELL_MAP_LIST *MapListItem;\r
+ CHAR16 *PathForReturn;\r
+ UINTN PathSize;\r
+ EFI_HANDLE PathHandle;\r
+ EFI_HANDLE MapHandle;\r
+ EFI_STATUS Status;\r
+ FILEPATH_DEVICE_PATH *FilePath;\r
+\r
+ PathForReturn = NULL;\r
+ PathSize = 0;\r
+\r
+ DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)Path;\r
+ ASSERT(DevicePathCopy != NULL);\r
+ if (DevicePathCopy == NULL) {\r
+ return (NULL);\r
+ }\r
+ ///@todo BlockIo?\r
+ Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return (NULL);\r
+ }\r
+ //\r
+ // check each of the device paths we have to get the root of the path\r
+ //\r
+ for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
+ ; !IsNull(&gShellMapList.Link, &MapListItem->Link)\r
+ ; MapListItem = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListItem->Link)\r
+ ){\r
+ MapPathCopy = (EFI_DEVICE_PATH_PROTOCOL*)MapListItem->DevicePath;\r
+ ASSERT(MapPathCopy != NULL);\r
+ ///@todo BlockIo?\r
+ Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
+ if (MapHandle == PathHandle) {\r
+ ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
+ PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, MapListItem->MapName, 0);\r
+ //\r
+ // go through all the remaining nodes in the device path\r
+ //\r
+ for ( FilePath = (FILEPATH_DEVICE_PATH*)DevicePathCopy\r
+ ; !IsDevicePathEnd (&FilePath->Header)\r
+ ; FilePath = (FILEPATH_DEVICE_PATH*)NextDevicePathNode (&FilePath->Header)\r
+ ){\r
+ //\r
+ // all the rest should be file path nodes\r
+ //\r
+ if ((DevicePathType(&FilePath->Header) != MEDIA_DEVICE_PATH) ||\r
+ (DevicePathSubType(&FilePath->Header) != MEDIA_FILEPATH_DP)) {\r
+ FreePool(PathForReturn);\r
+ PathForReturn = NULL;\r
+ ASSERT(FALSE);\r
+ } else {\r
+ //\r
+ // append the path part onto the filepath.\r
+ //\r
+ ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
+ PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L"\\", 1);\r
+ PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, FilePath->PathName, 0);\r
+ }\r
+ } // for loop of remaining nodes\r
+ }\r
+ if (PathForReturn != NULL) {\r
+ break;\r
+ }\r
+ } // for loop of paths to check\r
+ return(PathForReturn);\r
+}\r
+\r
+/**\r
+ Converts a file system style name to a device path.\r
+\r
+ This function converts a file system style name to a device path, by replacing any\r
+ mapping references to the associated device path.\r
+\r
+ @param Path the pointer to the path\r
+\r
+ @return all The pointer of the file path. The file path is callee\r
+ allocated and should be freed by the caller.\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+EFIAPI\r
+EfiShellGetDevicePathFromFilePath(\r
+ IN CONST CHAR16 *Path\r
+ )\r
+{\r
+ CHAR16 *MapName;\r
+ CHAR16 *NewPath;\r
+ CONST CHAR16 *Cwd;\r
+ UINTN Size;\r
+ CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathCopyForFree;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathForReturn;\r
+ EFI_HANDLE Handle;\r
+ EFI_STATUS Status;\r
+\r
+ MapName = NULL;\r
+ ASSERT(Path != NULL);\r
+\r
+ if (StrStr(Path, L":") == NULL) {\r
+ Cwd = EfiShellGetCurDir(NULL);\r
+ if (Cwd == NULL) {\r
+ return (NULL);\r
+ }\r
+ Size = StrSize(Cwd);\r
+ Size += StrSize(Path);\r
+ NewPath = AllocateZeroPool(Size);\r
+ ASSERT(NewPath != NULL);\r
+ StrCpy(NewPath, Cwd);\r
+ if (NewPath[StrLen(NewPath)-1] == Path[0] == (CHAR16)L'\\') {\r
+ ((CHAR16*)NewPath)[StrLen(NewPath)-1] = CHAR_NULL;\r
+ }\r
+ StrCat(NewPath, Path);\r
+ DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath);\r
+ FreePool(NewPath);\r
+ return (DevicePathForReturn);\r
+ }\r
+\r
+ Size = 0;\r
+ //\r
+ // find the part before (but including) the : for the map name\r
+ //\r
+ ASSERT((MapName == NULL && Size == 0) || (MapName != NULL));\r
+ MapName = StrnCatGrow(&MapName, &Size, Path, (StrStr(Path, L":")-Path+1));\r
+ if (MapName[StrLen(MapName)-1] != L':') {\r
+ ASSERT(FALSE);\r
+ return (NULL);\r
+ }\r
+\r
+ //\r
+ // look up the device path in the map\r
+ //\r
+ DevicePath = EfiShellGetDevicePathFromMap(MapName);\r
+ if (DevicePath == NULL) {\r
+ //\r
+ // Must have been a bad Mapname\r
+ //\r
+ return (NULL);\r
+ }\r
+\r
+ //\r
+ // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with)\r
+ //\r
+ DevicePathCopyForFree = DevicePathCopy = DuplicateDevicePath(DevicePath);\r
+ if (DevicePathCopy == NULL) {\r
+ ASSERT(FALSE);\r
+ FreePool(MapName);\r
+ return (NULL);\r
+ }\r
+\r
+ //\r
+ // get the handle\r
+ //\r
+ ///@todo BlockIo?\r
+ Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);\r
+ if (EFI_ERROR(Status)) {\r
+ if (DevicePathCopyForFree != NULL) {\r
+ FreePool(DevicePathCopyForFree);\r
+ }\r
+ FreePool(MapName);\r
+ return (NULL);\r
+ }\r
+\r
+ //\r
+ // build the full device path\r
+ //\r
+ DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName)+1);\r
+\r
+ FreePool(MapName);\r
+ if (DevicePathCopyForFree != NULL) {\r
+ FreePool(DevicePathCopyForFree);\r
+ }\r
+\r
+ return (DevicePathForReturn);\r
+}\r
+\r
+/**\r
+ Gets the name of the device specified by the device handle.\r
+\r
+ This function gets the user-readable name of the device specified by the device\r
+ handle. If no user-readable name could be generated, then *BestDeviceName will be\r
+ NULL and EFI_NOT_FOUND will be returned.\r
+\r
+ If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the\r
+ device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on\r
+ DeviceHandle.\r
+\r
+ If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the\r
+ device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle.\r
+ If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and\r
+ EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then\r
+ EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority.\r
+\r
+ @param DeviceHandle The handle of the device.\r
+ @param Flags Determines the possible sources of component names.\r
+ Valid bits are:\r
+ EFI_DEVICE_NAME_USE_COMPONENT_NAME\r
+ EFI_DEVICE_NAME_USE_DEVICE_PATH\r
+ @param Language A pointer to the language specified for the device\r
+ name, in the same format as described in the UEFI\r
+ specification, Appendix M\r
+ @param BestDeviceName On return, points to the callee-allocated NULL-\r
+ terminated name of the device. If no device name\r
+ could be found, points to NULL. The name must be\r
+ freed by the caller...\r
+\r
+ @retval EFI_SUCCESS Get the name successfully.\r
+ @retval EFI_NOT_FOUND Fail to get the device name.\r
+ @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set.\r
+ @retval EFI_INVALID_PARAMETER BestDeviceName was NULL\r
+ @retval EFI_INVALID_PARAMETER DeviceHandle was NULL\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellGetDeviceName(\r
+ IN EFI_HANDLE DeviceHandle,\r
+ IN EFI_SHELL_DEVICE_NAME_FLAGS Flags,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **BestDeviceName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_COMPONENT_NAME2_PROTOCOL *CompName2;\r
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathToText;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_HANDLE *HandleList;\r
+ UINTN HandleCount;\r
+ UINTN LoopVar;\r
+ CHAR16 *DeviceNameToReturn;\r
+ CHAR8 *Lang;\r
+ CHAR8 *TempChar;\r
+\r
+ if (BestDeviceName == NULL ||\r
+ DeviceHandle == NULL\r
+ ){\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ //\r
+ // make sure one of the 2 supported bits is on\r
+ //\r
+ if (((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) == 0) &&\r
+ ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) == 0)) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ DeviceNameToReturn = NULL;\r
+ *BestDeviceName = NULL;\r
+ HandleList = NULL;\r
+ HandleCount = 0;\r
+ Lang = NULL;\r
+\r
+ if ((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) != 0) {\r
+ Status = ParseHandleDatabaseByRelationship(\r
+ NULL,\r
+ DeviceHandle,\r
+ HR_DRIVER_BINDING_HANDLE|HR_DEVICE_DRIVER,\r
+ &HandleCount,\r
+ &HandleList);\r
+ for (LoopVar = 0; LoopVar < HandleCount ; LoopVar++){\r
+ //\r
+ // Go through those handles until we get one that passes for GetComponentName\r
+ //\r
+ Status = gBS->OpenProtocol(\r
+ HandleList[LoopVar],\r
+ &gEfiComponentName2ProtocolGuid,\r
+ (VOID**)&CompName2,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+ if (EFI_ERROR(Status)) {\r
+ Status = gBS->OpenProtocol(\r
+ HandleList[LoopVar],\r
+ &gEfiComponentNameProtocolGuid,\r
+ (VOID**)&CompName2,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+ if (Language == NULL) {\r
+ Lang = AllocatePool(AsciiStrSize(CompName2->SupportedLanguages));\r
+ AsciiStrCpy(Lang, CompName2->SupportedLanguages);\r
+ TempChar = AsciiStrStr(Lang, ";");\r
+ if (TempChar != NULL){\r
+ *TempChar = CHAR_NULL;\r
+ }\r
+ } else {\r
+ Lang = AllocatePool(AsciiStrSize(Language));\r
+ AsciiStrCpy(Lang, Language);\r
+ }\r
+ Status = CompName2->GetControllerName(CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn);\r
+ FreePool(Lang);\r
+ Lang = NULL;\r
+ if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {\r
+ break;\r
+ }\r
+ }\r
+ if (HandleList != NULL) {\r
+ FreePool(HandleList);\r
+ }\r
+ if (DeviceNameToReturn != NULL){\r
+ ASSERT(BestDeviceName == NULL);\r
+ StrnCatGrow(BestDeviceName, NULL, DeviceNameToReturn, 0);\r
+ return (EFI_SUCCESS);\r
+ }\r
+ //\r
+ // dont return on fail since we will try device path if that bit is on\r
+ //\r
+ }\r
+ if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) {\r
+ Status = gBS->LocateProtocol(\r
+ &gEfiDevicePathToTextProtocolGuid,\r
+ NULL,\r
+ (VOID**)&DevicePathToText);\r
+ //\r
+ // we now have the device path to text protocol\r
+ //\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = gBS->OpenProtocol(\r
+ DeviceHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID**)&DevicePath,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // use device path to text on the device path\r
+ //\r
+ *BestDeviceName = DevicePathToText->ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
+ return (EFI_SUCCESS);\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // none of the selected bits worked.\r
+ //\r
+ return (EFI_NOT_FOUND);\r
+}\r
+\r
+/**\r
+ Opens the root directory of a device on a handle\r
+\r
+ This function opens the root directory of a device and returns a file handle to it.\r
+\r
+ @param DeviceHandle The handle of the device that contains the volume.\r
+ @param FileHandle On exit, points to the file handle corresponding to the root directory on the\r
+ device.\r
+\r
+ @retval EFI_SUCCESS Root opened successfully.\r
+ @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory\r
+ could not be opened.\r
+ @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.\r
+ @retval EFI_DEVICE_ERROR The device had an error\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellOpenRootByHandle(\r
+ IN EFI_HANDLE DeviceHandle,\r
+ OUT SHELL_FILE_HANDLE *FileHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;\r
+ EFI_FILE_PROTOCOL *RealFileHandle;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
+\r
+ //\r
+ // get the simple file system interface\r
+ //\r
+ Status = gBS->OpenProtocol(DeviceHandle,\r
+ &gEfiSimpleFileSystemProtocolGuid,\r
+ (VOID**)&SimpleFileSystem,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+ if (EFI_ERROR(Status)) {\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+\r
+ Status = gBS->OpenProtocol(DeviceHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID**)&DevPath,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+ if (EFI_ERROR(Status)) {\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+ //\r
+ // Open the root volume now...\r
+ //\r
+ Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &RealFileHandle);\r
+ *FileHandle = ConvertEfiFileProtocolToShellHandle(RealFileHandle, EfiShellGetMapFromDevicePath(&DevPath));\r
+ return (Status);\r
+}\r
+\r
+/**\r
+ Opens the root directory of a device.\r
+\r
+ This function opens the root directory of a device and returns a file handle to it.\r
+\r
+ @param DevicePath Points to the device path corresponding to the device where the\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed.\r
+ @param FileHandle On exit, points to the file handle corresponding to the root directory on the\r
+ device.\r
+\r
+ @retval EFI_SUCCESS Root opened successfully.\r
+ @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory\r
+ could not be opened.\r
+ @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.\r
+ @retval EFI_DEVICE_ERROR The device had an error\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellOpenRoot(\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT SHELL_FILE_HANDLE *FileHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE Handle;\r
+\r
+ //\r
+ // find the handle of the device with that device handle and the file system\r
+ //\r
+ ///@todo BlockIo?\r
+ Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,\r
+ &DevicePath,\r
+ &Handle);\r
+ if (EFI_ERROR(Status)) {\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+\r
+ return (EfiShellOpenRootByHandle(Handle, FileHandle));\r
+}\r
+\r
+/**\r
+ Returns whether any script files are currently being processed.\r
+\r
+ @retval TRUE There is at least one script file active.\r
+ @retval FALSE No script files are active now.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+EfiShellBatchIsActive (\r
+ VOID\r
+ )\r
+{\r
+ if (ShellCommandGetCurrentScriptFile() == NULL) {\r
+ return (FALSE);\r
+ }\r
+ return (TRUE);\r
+}\r
+\r
+/**\r
+ Worker function to open a file based on a device path. this will open the root\r
+ of the volume and then traverse down to the file itself.\r
+\r
+ @param DevicePath Device Path of the file.\r
+ @param FileHandle Pointer to the file upon a successful return.\r
+ @param OpenMode mode to open file in.\r
+ @param Attributes the File Attributes to use when creating a new file.\r
+\r
+ @retval EFI_SUCCESS the file is open and FileHandle is valid\r
+ @retval EFI_UNSUPPORTED the device path cotained non-path elements\r
+ @retval other an error ocurred.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InternalOpenFileDevicePath(\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT SHELL_FILE_HANDLE *FileHandle,\r
+ IN UINT64 OpenMode,\r
+ IN UINT64 Attributes OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FILEPATH_DEVICE_PATH *FilePathNode;\r
+ EFI_HANDLE Handle;\r
+ SHELL_FILE_HANDLE ShellHandle;\r
+ EFI_FILE_PROTOCOL *Handle1;\r
+ EFI_FILE_PROTOCOL *Handle2;\r
+ EFI_DEVICE_PATH_PROTOCOL *DpCopy;\r
+\r
+ ASSERT(FileHandle != NULL);\r
+ *FileHandle = NULL;\r
+ Handle1 = NULL;\r
+ DpCopy = DevicePath;\r
+\r
+ Status = EfiShellOpenRoot(DevicePath, &ShellHandle);\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ Handle1 = ConvertShellHandleToEfiFileProtocol(ShellHandle);\r
+ //\r
+ // chop off the begining part before the file system part...\r
+ //\r
+ ///@todo BlockIo?\r
+ Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,\r
+ &DevicePath,\r
+ &Handle);\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // To access as a file system, the file path should only\r
+ // contain file path components. Follow the file path nodes\r
+ // and find the target file\r
+ //\r
+ for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath\r
+ ; !IsDevicePathEnd (&FilePathNode->Header)\r
+ ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header)\r
+ ){\r
+ //\r
+ // For file system access each node should be a file path component\r
+ //\r
+ if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||\r
+ DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP\r
+ ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Open this file path node\r
+ //\r
+ Handle2 = Handle1;\r
+ Handle1 = NULL;\r
+\r
+ //\r
+ // if this is the last node in the DevicePath always create (if that was requested).\r
+ //\r
+ if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) {\r
+ Status = Handle2->Open (\r
+ Handle2,\r
+ &Handle1,\r
+ FilePathNode->PathName,\r
+ OpenMode,\r
+ Attributes\r
+ );\r
+ } else {\r
+\r
+ //\r
+ // This is not the last node and we dont want to 'create' existing\r
+ // directory entries...\r
+ //\r
+\r
+ //\r
+ // open without letting it create\r
+ // prevents error on existing files/directories\r
+ //\r
+ Status = Handle2->Open (\r
+ Handle2,\r
+ &Handle1,\r
+ FilePathNode->PathName,\r
+ OpenMode &~EFI_FILE_MODE_CREATE,\r
+ Attributes\r
+ );\r
+ //\r
+ // if above failed now open and create the 'item'\r
+ // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)\r
+ //\r
+ if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {\r
+ Status = Handle2->Open (\r
+ Handle2,\r
+ &Handle1,\r
+ FilePathNode->PathName,\r
+ OpenMode,\r
+ Attributes\r
+ );\r
+ }\r
+ }\r
+ //\r
+ // Close the last node\r
+ //\r
+ Handle2->Close (Handle2);\r
+\r
+ //\r
+ // If there's been an error, stop\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ } // for loop\r
+ }\r
+ }\r
+ if (EFI_ERROR(Status)) {\r
+ if (Handle1 != NULL) {\r
+ Handle1->Close(Handle1);\r
+ }\r
+ } else {\r
+ *FileHandle = ConvertEfiFileProtocolToShellHandle(Handle1, ShellFileHandleGetPath(ShellHandle));\r
+ }\r
+ return (Status);\r
+}\r
+\r
+/**\r
+ Creates a file or directory by name.\r
+\r
+ This function creates an empty new file or directory with the specified attributes and\r
+ returns the new file's handle. If the file already exists and is read-only, then\r
+ EFI_INVALID_PARAMETER will be returned.\r
+\r
+ If the file already existed, it is truncated and its attributes updated. If the file is\r
+ created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL.\r
+\r
+ If the file name begins with >v, then the file handle which is returned refers to the\r
+ shell environment variable with the specified name. If the shell environment variable\r
+ already exists and is non-volatile then EFI_INVALID_PARAMETER is returned.\r
+\r
+ @param FileName Pointer to NULL-terminated file path\r
+ @param FileAttribs The new file's attrbiutes. the different attributes are\r
+ described in EFI_FILE_PROTOCOL.Open().\r
+ @param FileHandle On return, points to the created file handle or directory's handle\r
+\r
+ @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle.\r
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
+ @retval EFI_UNSUPPORTED could not open the file path\r
+ @retval EFI_NOT_FOUND the specified file could not be found on the devide, or could not\r
+ file the file system on the device.\r
+ @retval EFI_NO_MEDIA the device has no medium.\r
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no\r
+ longer supported.\r
+ @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according\r
+ the DirName.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write\r
+ when the media is write-protected.\r
+ @retval EFI_ACCESS_DENIED The service denied access to the file.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.\r
+ @retval EFI_VOLUME_FULL The volume is full.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellCreateFile(\r
+ IN CONST CHAR16 *FileName,\r
+ IN UINT64 FileAttribs,\r
+ OUT SHELL_FILE_HANDLE *FileHandle\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Is this for an environment variable\r
+ // do we start with >v\r
+ //\r
+ if (StrStr(FileName, L">v") == FileName) {\r
+ if (!IsVolatileEnv(FileName+2)) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ *FileHandle = CreateFileInterfaceEnv(FileName+2);\r
+ return (EFI_SUCCESS);\r
+ }\r
+\r
+ //\r
+ // We are opening a regular file.\r
+ //\r
+ DevicePath = EfiShellGetDevicePathFromFilePath(FileName);\r
+ if (DevicePath == NULL) {\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+\r
+ Status = InternalOpenFileDevicePath(DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs); // 0 = no specific file attributes\r
+ FreePool(DevicePath);\r
+\r
+ return(Status);\r
+}\r
+\r
+/**\r
+ Opens a file or a directory by file name.\r
+\r
+ This function opens the specified file in the specified OpenMode and returns a file\r
+ handle.\r
+ If the file name begins with >v, then the file handle which is returned refers to the\r
+ shell environment variable with the specified name. If the shell environment variable\r
+ exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then\r
+ EFI_INVALID_PARAMETER is returned.\r
+\r
+ If the file name is >i, then the file handle which is returned refers to the standard\r
+ input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+\r
+ If the file name is >o, then the file handle which is returned refers to the standard\r
+ output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+\r
+ If the file name is >e, then the file handle which is returned refers to the standard\r
+ error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+\r
+ If the file name is NUL, then the file handle that is returned refers to the standard NUL\r
+ file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is\r
+ returned.\r
+\r
+ If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the\r
+ FileHandle is NULL.\r
+\r
+ @param FileName Points to the NULL-terminated UCS-2 encoded file name.\r
+ @param FileHandle On return, points to the file handle.\r
+ @param OpenMode File open mode. Either EFI_FILE_MODE_READ or\r
+ EFI_FILE_MODE_WRITE from section 12.4 of the UEFI\r
+ Specification.\r
+ @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle.\r
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL.\r
+ @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL.\r
+ @retval EFI_NOT_FOUND The specified file could not be found on the device or the file\r
+ system could not be found on the device. FileHandle is NULL.\r
+ @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL.\r
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no\r
+ longer supported. FileHandle is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according\r
+ the FileName. FileHandle is NULL.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL.\r
+ @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write\r
+ when the media is write-protected. FileHandle is NULL.\r
+ @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle\r
+ is NULL.\r
+ @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellOpenFileByName(\r
+ IN CONST CHAR16 *FileName,\r
+ OUT SHELL_FILE_HANDLE *FileHandle,\r
+ IN UINT64 OpenMode\r
+ )\r
+{\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_STATUS Status;\r
+\r
+ *FileHandle = NULL;\r
+\r
+ //\r
+ // Is this for StdIn\r
+ //\r
+ if (StrCmp(FileName, L">i") == 0) {\r
+ //\r
+ // make sure not writing to StdIn\r
+ //\r
+ if ((OpenMode & EFI_FILE_MODE_WRITE) != 0) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ *FileHandle = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
+ ASSERT(*FileHandle != NULL);\r
+ return (EFI_SUCCESS);\r
+ }\r
+\r
+ //\r
+ // Is this for StdOut\r
+ //\r
+ if (StrCmp(FileName, L">o") == 0) {\r
+ //\r
+ // make sure not writing to StdIn\r
+ //\r
+ if ((OpenMode & EFI_FILE_MODE_READ) != 0) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ *FileHandle = &FileInterfaceStdOut;\r
+ return (EFI_SUCCESS);\r
+ }\r
+\r
+ //\r
+ // Is this for NUL file\r
+ //\r
+ if (StrCmp(FileName, L"NUL") == 0) {\r
+ *FileHandle = &FileInterfaceNulFile;\r
+ return (EFI_SUCCESS);\r
+ }\r
+\r
+ //\r
+ // Is this for StdErr\r
+ //\r
+ if (StrCmp(FileName, L">e") == 0) {\r
+ //\r
+ // make sure not writing to StdIn\r
+ //\r
+ if ((OpenMode & EFI_FILE_MODE_READ) != 0) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ *FileHandle = &FileInterfaceStdErr;\r
+ return (EFI_SUCCESS);\r
+ }\r
+\r
+ //\r
+ // Is this for an environment variable\r
+ // do we start with >v\r
+ //\r
+ if (StrStr(FileName, L">v") == FileName) {\r
+ if (!IsVolatileEnv(FileName+2) &&\r
+ ((OpenMode & EFI_FILE_MODE_WRITE) != 0)) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ *FileHandle = CreateFileInterfaceEnv(FileName+2);\r
+ return (EFI_SUCCESS);\r
+ }\r
+\r
+ //\r
+ // We are opening a regular file.\r
+ //\r
+ DevicePath = EfiShellGetDevicePathFromFilePath(FileName);\r
+// DEBUG_CODE(InternalShellProtocolDebugPrintMessage (NULL, DevicePath););\r
+ if (DevicePath == NULL) {\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+\r
+ //\r
+ // Copy the device path, open the file, then free the memory\r
+ //\r
+ Status = InternalOpenFileDevicePath(DevicePath, FileHandle, OpenMode, 0); // 0 = no specific file attributes\r
+ FreePool(DevicePath);\r
+\r
+ return(Status);\r
+}\r
+\r
+/**\r
+ Deletes the file specified by the file name.\r
+\r
+ This function deletes a file.\r
+\r
+ @param FileName Points to the NULL-terminated file name.\r
+\r
+ @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed.\r
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.\r
+ @sa EfiShellCreateFile\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellDeleteFileByName(\r
+ IN CONST CHAR16 *FileName\r
+ )\r
+{\r
+ SHELL_FILE_HANDLE FileHandle;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // get a handle to the file\r
+ //\r
+ Status = EfiShellCreateFile(FileName,\r
+ 0,\r
+ &FileHandle);\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+ //\r
+ // now delete the file\r
+ //\r
+ return (ShellInfoObject.NewEfiShellProtocol->DeleteFile(FileHandle));\r
+}\r
+\r
+/**\r
+ Disables the page break output mode.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiShellDisablePageBreak (\r
+ VOID\r
+ )\r
+{\r
+ ShellInfoObject.PageBreakEnabled = FALSE;\r
+}\r
+\r
+/**\r
+ Enables the page break output mode.\r
+**/\r
+VOID\r
+EFIAPI\r
+EfiShellEnablePageBreak (\r
+ VOID\r
+ )\r
+{\r
+ ShellInfoObject.PageBreakEnabled = TRUE;\r
+}\r
+\r
+/**\r
+ internal worker function to load and run an image via device path.\r
+\r
+ @param ParentImageHandle A handle of the image that is executing the specified\r
+ command line.\r
+ @param DevicePath device path of the file to execute\r
+ @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
+ containing the command line. If NULL then the command-\r
+ line will be empty.\r
+ @param Environment Points to a NULL-terminated array of environment\r
+ variables with the format 'x=y', where x is the\r
+ environment variable name and y is the value. If this\r
+ is NULL, then the current shell environment is used.\r
+ @param StatusCode Points to the status code returned by the command.\r
+\r
+ @retval EFI_SUCCESS The command executed successfully. The status code\r
+ returned by the command is pointed to by StatusCode.\r
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Out of resources.\r
+ @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InternalShellExecuteDevicePath(\r
+ IN CONST EFI_HANDLE *ParentImageHandle,\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN CONST CHAR16 *CommandLine OPTIONAL,\r
+ IN CONST CHAR16 **Environment OPTIONAL,\r
+ OUT EFI_STATUS *StatusCode OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE NewHandle;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+ LIST_ENTRY OrigEnvs;\r
+ EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;\r
+\r
+ if (ParentImageHandle == NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ InitializeListHead(&OrigEnvs);\r
+\r
+ NewHandle = NULL;\r
+\r
+ //\r
+ // Load the image with:\r
+ // FALSE - not from boot manager and NULL, 0 being not already in memory\r
+ //\r
+ Status = gBS->LoadImage(\r
+ FALSE,\r
+ *ParentImageHandle,\r
+ (EFI_DEVICE_PATH_PROTOCOL*)DevicePath,\r
+ NULL,\r
+ 0,\r
+ &NewHandle);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ if (NewHandle != NULL) {\r
+ gBS->UnloadImage(NewHandle);\r
+ }\r
+ return (Status);\r
+ }\r
+ Status = gBS->OpenProtocol(\r
+ NewHandle,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID**)&LoadedImage,\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ ASSERT(LoadedImage->LoadOptionsSize == 0);\r
+ if (CommandLine != NULL) {\r
+ LoadedImage->LoadOptionsSize = (UINT32)StrSize(CommandLine);\r
+ LoadedImage->LoadOptions = (VOID*)CommandLine;\r
+ }\r
+\r
+ //\r
+ // Save our current environment settings for later restoration if necessary\r
+ //\r
+ if (Environment != NULL) {\r
+ Status = GetEnvironmentVariableList(&OrigEnvs);\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = SetEnvironmentVariables(Environment);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Initialize and install a shell parameters protocol on the image.\r
+ //\r
+ ShellParamsProtocol.StdIn = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
+ ShellParamsProtocol.StdOut = ShellInfoObject.NewShellParametersProtocol->StdOut;\r
+ ShellParamsProtocol.StdErr = ShellInfoObject.NewShellParametersProtocol->StdErr;\r
+ Status = UpdateArgcArgv(&ShellParamsProtocol, CommandLine, NULL, NULL);\r
+ ASSERT_EFI_ERROR(Status);\r
+ Status = gBS->InstallProtocolInterface(&NewHandle, &gEfiShellParametersProtocolGuid, EFI_NATIVE_INTERFACE, &ShellParamsProtocol);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ ///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)\r
+\r
+ //\r
+ // now start the image and if the caller wanted the return code pass it to them...\r
+ //\r
+ if (!EFI_ERROR(Status)) {\r
+ if (StatusCode != NULL) {\r
+ *StatusCode = gBS->StartImage(NewHandle, NULL, NULL);\r
+ } else {\r
+ Status = gBS->StartImage(NewHandle, NULL, NULL);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Cleanup (and dont overwrite errors)\r
+ //\r
+ if (EFI_ERROR(Status)) {\r
+ gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
+ } else {\r
+ Status = gBS->UninstallProtocolInterface(NewHandle, &gEfiShellParametersProtocolGuid, &ShellParamsProtocol);\r
+ ASSERT_EFI_ERROR(Status);\r
+ }\r
+ }\r
+\r
+ if (!IsListEmpty(&OrigEnvs)) {\r
+ if (EFI_ERROR(Status)) {\r
+ SetEnvironmentVariableList(&OrigEnvs);\r
+ } else {\r
+ Status = SetEnvironmentVariableList(&OrigEnvs);\r
+ }\r
+ }\r
+\r
+ return(Status);\r
+}\r
+/**\r
+ Execute the command line.\r
+\r
+ This function creates a nested instance of the shell and executes the specified\r
+ command (CommandLine) with the specified environment (Environment). Upon return,\r
+ the status code returned by the specified command is placed in StatusCode.\r
+\r
+ If Environment is NULL, then the current environment is used and all changes made\r
+ by the commands executed will be reflected in the current environment. If the\r
+ Environment is non-NULL, then the changes made will be discarded.\r
+\r
+ The CommandLine is executed from the current working directory on the current\r
+ device.\r
+\r
+ @param ParentImageHandle A handle of the image that is executing the specified\r
+ command line.\r
+ @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
+ containing the command line. If NULL then the command-\r
+ line will be empty.\r
+ @param Environment Points to a NULL-terminated array of environment\r
+ variables with the format 'x=y', where x is the\r
+ environment variable name and y is the value. If this\r
+ is NULL, then the current shell environment is used.\r
+ @param StatusCode Points to the status code returned by the command.\r
+\r
+ @retval EFI_SUCCESS The command executed successfully. The status code\r
+ returned by the command is pointed to by StatusCode.\r
+ @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Out of resources.\r
+ @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
+ @retval EFI_UNSUPPORTED The support level required for this function is not present.\r
+\r
+ @sa InternalShellExecuteDevicePath\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellExecute(\r
+ IN EFI_HANDLE *ParentImageHandle,\r
+ IN CHAR16 *CommandLine OPTIONAL,\r
+ IN CHAR16 **Environment OPTIONAL,\r
+ OUT EFI_STATUS *StatusCode OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 *Temp;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
+ UINTN Size;\r
+\r
+ if ((PcdGet8(PcdShellSupportLevel) < 1)) {\r
+ return (EFI_UNSUPPORTED);\r
+ }\r
+\r
+ DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
+\r
+ DEBUG_CODE_BEGIN();\r
+ Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
+ FreePool(Temp);\r
+ Temp = gDevPathToText->ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
+ FreePool(Temp);\r
+ Temp = gDevPathToText->ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
+ FreePool(Temp);\r
+ DEBUG_CODE_END();\r
+\r
+ Temp = NULL;\r
+ Size = 0;\r
+ ASSERT((Temp == NULL && Size == 0) || (Temp != NULL));\r
+ StrnCatGrow(&Temp, &Size, L"Shell.efi ", 0);\r
+ StrnCatGrow(&Temp, &Size, CommandLine, 0);\r
+\r
+ Status = InternalShellExecuteDevicePath(\r
+ ParentImageHandle,\r
+ DevPath,\r
+ Temp,\r
+ (CONST CHAR16**)Environment,\r
+ StatusCode);\r
+\r
+ //\r
+ // de-allocate and return\r
+ //\r
+ FreePool(DevPath);\r
+ FreePool(Temp);\r
+ return(Status);\r
+}\r
+\r
+/**\r
+ Utility cleanup function for EFI_SHELL_FILE_INFO objects.\r
+\r
+ 1) frees all pointers (non-NULL)\r
+ 2) Closes the SHELL_FILE_HANDLE\r
+\r
+ @param FileListNode pointer to the list node to free\r
+**/\r
+VOID\r
+EFIAPI\r
+InternalFreeShellFileInfoNode(\r
+ IN EFI_SHELL_FILE_INFO *FileListNode\r
+ )\r
+{\r
+ if (FileListNode->Info != NULL) {\r
+ FreePool((VOID*)FileListNode->Info);\r
+ }\r
+ if (FileListNode->FileName != NULL) {\r
+ FreePool((VOID*)FileListNode->FileName);\r
+ }\r
+ if (FileListNode->FullName != NULL) {\r
+ FreePool((VOID*)FileListNode->FullName);\r
+ }\r
+ if (FileListNode->Handle != NULL) {\r
+ ShellInfoObject.NewEfiShellProtocol->CloseFile(FileListNode->Handle);\r
+ }\r
+ FreePool(FileListNode);\r
+}\r
+/**\r
+ Frees the file list.\r
+\r
+ This function cleans up the file list and any related data structures. It has no\r
+ impact on the files themselves.\r
+\r
+ @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is\r
+ defined in OpenFileList()\r
+\r
+ @retval EFI_SUCCESS Free the file list successfully.\r
+ @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellFreeFileList(\r
+ IN EFI_SHELL_FILE_INFO **FileList\r
+ )\r
+{\r
+ EFI_SHELL_FILE_INFO *ShellFileListItem;\r
+\r
+ if (FileList == NULL || *FileList == NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)\r
+ ; !IsListEmpty(&(*FileList)->Link)\r
+ ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)\r
+ ){\r
+ RemoveEntryList(&ShellFileListItem->Link);\r
+ InternalFreeShellFileInfoNode(ShellFileListItem);\r
+ }\r
+ return(EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ Deletes the duplicate file names files in the given file list.\r
+\r
+ This function deletes the reduplicate files in the given file list.\r
+\r
+ @param FileList A pointer to the first entry in the file list.\r
+\r
+ @retval EFI_SUCCESS Always success.\r
+ @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellRemoveDupInFileList(\r
+ IN EFI_SHELL_FILE_INFO **FileList\r
+ )\r
+{\r
+ EFI_SHELL_FILE_INFO *ShellFileListItem;\r
+ EFI_SHELL_FILE_INFO *ShellFileListItem2;\r
+\r
+ if (FileList == NULL || *FileList == NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)\r
+ ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link)\r
+ ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)\r
+ ){\r
+ for ( ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)\r
+ ; !IsNull(&(*FileList)->Link, &ShellFileListItem2->Link)\r
+ ; ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem2->Link)\r
+ ){\r
+ if (gUnicodeCollation->StriColl(\r
+ gUnicodeCollation,\r
+ (CHAR16*)ShellFileListItem->FullName,\r
+ (CHAR16*)ShellFileListItem2->FullName) == 0\r
+ ){\r
+ RemoveEntryList(&ShellFileListItem2->Link);\r
+ InternalFreeShellFileInfoNode(ShellFileListItem2);\r
+ }\r
+ }\r
+ }\r
+ return (EFI_SUCCESS);\r
+}\r
+/**\r
+ Allocates and duplicates a EFI_SHELL_FILE_INFO node.\r
+\r
+ @param[in] Node The node to copy from.\r
+ @param[in] Save TRUE to set Node->Handle to NULL, FALSE otherwise.\r
+\r
+ @retval NULL a memory allocation error ocurred\r
+ @return != NULL a pointer to the new node\r
+**/\r
+EFI_SHELL_FILE_INFO*\r
+EFIAPI\r
+InternalDuplicateShellFileInfo(\r
+ IN EFI_SHELL_FILE_INFO *Node,\r
+ IN BOOLEAN Save\r
+ )\r
+{\r
+ EFI_SHELL_FILE_INFO *NewNode;\r
+\r
+ NewNode = AllocatePool(sizeof(EFI_SHELL_FILE_INFO));\r
+ if (NewNode == NULL) {\r
+ return (NULL);\r
+ }\r
+ NewNode->FullName = AllocateZeroPool(StrSize(Node->FullName));\r
+\r
+ NewNode->FileName = AllocateZeroPool(StrSize(Node->FileName));\r
+ NewNode->Info = AllocatePool((UINTN)Node->Info->Size);\r
+ if ( NewNode->FullName == NULL\r
+ || NewNode->FileName == NULL\r
+ || NewNode->Info == NULL\r
+ ){\r
+ return(NULL);\r
+ }\r
+ NewNode->Status = Node->Status;\r
+ NewNode->Handle = Node->Handle;\r
+ if (!Save) {\r
+ Node->Handle = NULL;\r
+ }\r
+ StrCpy((CHAR16*)NewNode->FullName, Node->FullName);\r
+ StrCpy((CHAR16*)NewNode->FileName, Node->FileName);\r
+ CopyMem(NewNode->Info, Node->Info, (UINTN)Node->Info->Size);\r
+\r
+ return(NewNode);\r
+}\r
+\r
+/**\r
+ Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation\r
+ failed it will return NULL.\r
+\r
+ @param[in] BasePath the Path to prepend onto filename for FullPath\r
+ @param[in] Status Status member initial value.\r
+ @param[in] FullName FullName member initial value.\r
+ @param[in] FileName FileName member initial value.\r
+ @param[in] Handle Handle member initial value.\r
+ @param[in] Info Info struct to copy.\r
+\r
+ @retval NULL An error ocurred.\r
+ @return a pointer to the newly allocated structure.\r
+**/\r
+EFI_SHELL_FILE_INFO *\r
+EFIAPI\r
+CreateAndPopulateShellFileInfo(\r
+ IN CONST CHAR16 *BasePath,\r
+ IN CONST EFI_STATUS Status,\r
+ IN CONST CHAR16 *FullName,\r
+ IN CONST CHAR16 *FileName,\r
+ IN CONST SHELL_FILE_HANDLE Handle,\r
+ IN CONST EFI_FILE_INFO *Info\r
+ )\r
+{\r
+ EFI_SHELL_FILE_INFO *ShellFileListItem;\r
+ CHAR16 *TempString;\r
+ UINTN Size;\r
+\r
+ TempString = NULL;\r
+ Size = 0;\r
+\r
+ ShellFileListItem = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
+ if (ShellFileListItem == NULL) {\r
+ return (NULL);\r
+ }\r
+ if (Info != NULL) {\r
+ ShellFileListItem->Info = AllocateZeroPool((UINTN)Info->Size);\r
+ if (ShellFileListItem->Info == NULL) {\r
+ FreePool(ShellFileListItem);\r
+ return (NULL);\r
+ }\r
+ CopyMem(ShellFileListItem->Info, Info, (UINTN)Info->Size);\r
+ } else {\r
+ ShellFileListItem->Info = NULL;\r
+ }\r
+ if (FileName != NULL) {\r
+ ASSERT(TempString == NULL);\r
+ ShellFileListItem->FileName = StrnCatGrow(&TempString, 0, FileName, 0);\r
+ if (ShellFileListItem->FileName == NULL) {\r
+ FreePool(ShellFileListItem->Info);\r
+ FreePool(ShellFileListItem);\r
+ return (NULL);\r
+ }\r
+ } else {\r
+ ShellFileListItem->FileName = NULL;\r
+ }\r
+ Size = 0;\r
+ TempString = NULL;\r
+ if (BasePath != NULL) {\r
+ ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
+ TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
+ if (TempString == NULL) {\r
+ FreePool((VOID*)ShellFileListItem->FileName);\r
+ FreePool(ShellFileListItem->Info);\r
+ FreePool(ShellFileListItem);\r
+ return (NULL);\r
+ }\r
+ }\r
+ if (ShellFileListItem->FileName != NULL) {\r
+ ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
+ TempString = StrnCatGrow(&TempString, &Size, ShellFileListItem->FileName, 0);\r
+ if (TempString == NULL) {\r
+ FreePool((VOID*)ShellFileListItem->FileName);\r
+ FreePool(ShellFileListItem->Info);\r
+ FreePool(ShellFileListItem);\r
+ return (NULL);\r
+ }\r
+ }\r
+\r
+ ShellFileListItem->FullName = TempString;\r
+ ShellFileListItem->Status = Status;\r
+ ShellFileListItem->Handle = Handle;\r
+\r
+ return (ShellFileListItem);\r
+}\r
+\r
+/**\r
+ Find all files in a specified directory.\r
+\r
+ @param FileDirHandle Handle of the directory to search.\r
+ @param FileList On return, points to the list of files in the directory\r
+ or NULL if there are no files in the directory.\r
+\r
+ @retval EFI_SUCCESS File information was returned successfully.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_NO_MEDIA The device media is not present.\r
+ @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory.\r
+ @return An error from FileHandleGetFileName().\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellFindFilesInDir(\r
+ IN SHELL_FILE_HANDLE FileDirHandle,\r
+ OUT EFI_SHELL_FILE_INFO **FileList\r
+ )\r
+{\r
+ EFI_SHELL_FILE_INFO *ShellFileList;\r
+ EFI_SHELL_FILE_INFO *ShellFileListItem;\r
+ EFI_FILE_INFO *FileInfo;\r
+ EFI_STATUS Status;\r
+ BOOLEAN NoFile;\r
+ CHAR16 *TempString;\r
+ CHAR16 *BasePath;\r
+ UINTN Size;\r
+ CHAR16 *TempSpot;\r
+\r
+ Status = FileHandleGetFileName(FileDirHandle, &BasePath);\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+\r
+ if (ShellFileHandleGetPath(FileDirHandle) != NULL) {\r
+ TempString = NULL;\r
+ Size = 0;\r
+ TempString = StrnCatGrow(&TempString, &Size, ShellFileHandleGetPath(FileDirHandle), 0);\r
+ TempSpot = StrStr(TempString, L";");\r
+\r
+ if (TempSpot != NULL) {\r
+ *TempSpot = CHAR_NULL;\r
+ }\r
+\r
+ TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
+ BasePath = TempString;\r
+ }\r
+\r
+ NoFile = FALSE;\r
+ ShellFileList = NULL;\r
+ ShellFileListItem = NULL;\r
+ FileInfo = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+\r
+ for ( Status = FileHandleFindFirstFile(FileDirHandle, &FileInfo)\r
+ ; !EFI_ERROR(Status) && !NoFile\r
+ ; Status = FileHandleFindNextFile(FileDirHandle, FileInfo, &NoFile)\r
+ ){\r
+ TempString = NULL;\r
+ Size = 0;\r
+ //\r
+ // allocate a new EFI_SHELL_FILE_INFO and populate it...\r
+ //\r
+ ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
+ TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
+ TempString = StrnCatGrow(&TempString, &Size, FileInfo->FileName, 0);\r
+ ShellFileListItem = CreateAndPopulateShellFileInfo(\r
+ BasePath,\r
+ EFI_SUCCESS, // success since we didnt fail to open it...\r
+ TempString,\r
+ FileInfo->FileName,\r
+ NULL, // no handle since not open\r
+ FileInfo);\r
+\r
+ if (ShellFileList == NULL) {\r
+ ShellFileList = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
+ ASSERT(ShellFileList != NULL);\r
+ InitializeListHead(&ShellFileList->Link);\r
+ }\r
+ InsertTailList(&ShellFileList->Link, &ShellFileListItem->Link);\r
+ }\r
+ if (EFI_ERROR(Status)) {\r
+ EfiShellFreeFileList(&ShellFileList);\r
+ *FileList = NULL;\r
+ } else {\r
+ *FileList = ShellFileList;\r
+ }\r
+ SHELL_FREE_NON_NULL(BasePath);\r
+ return(Status);\r
+}\r
+\r
+/**\r
+ Updates a file name to be preceeded by the mapped drive name\r
+\r
+ @param[in] BasePath the Mapped drive name to prepend\r
+ @param[in,out] Path pointer to pointer to the file name to update.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_OUT_OF_RESOURCES\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UpdateFileName(\r
+ IN CONST CHAR16 *BasePath,\r
+ IN OUT CHAR16 **Path\r
+ )\r
+{\r
+ CHAR16 *Path2;\r
+ UINTN Path2Size;\r
+\r
+ Path2Size = 0;\r
+ Path2 = NULL;\r
+\r
+ ASSERT(Path != NULL);\r
+ ASSERT(*Path != NULL);\r
+ ASSERT(BasePath != NULL);\r
+\r
+ //\r
+ // convert a local path to an absolute path\r
+ //\r
+ if (StrStr(*Path, L":") == NULL) {\r
+ ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
+ StrnCatGrow(&Path2, &Path2Size, BasePath, 0);\r
+ if (Path2 == NULL) {\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+ ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
+ StrnCatGrow(&Path2, &Path2Size, (*Path)[0] == L'\\'?(*Path) + 1 :*Path, 0);\r
+ if (Path2 == NULL) {\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+ }\r
+\r
+ FreePool(*Path);\r
+ (*Path) = Path2;\r
+\r
+ return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ If FileHandle is a directory then the function reads from FileHandle and reads in\r
+ each of the FileInfo structures. If one of them matches the Pattern's first\r
+ "level" then it opens that handle and calls itself on that handle.\r
+\r
+ If FileHandle is a file and matches all of the remaining Pattern (which would be\r
+ on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList.\r
+\r
+ if FileList is NULL, then ASSERT\r
+ if FilePattern is NULL, then ASSERT\r
+ if UnicodeCollation is NULL, then ASSERT\r
+ if FileHandle is NULL, then ASSERT\r
+\r
+ Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call\r
+ FreeFileList with FileList.\r
+\r
+ @param[in] FilePattern The FilePattern to check against.\r
+ @param[in] UnicodeCollation The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure\r
+ @param[in] FileHandle The FileHandle to start with\r
+ @param[in,out] FileList pointer to pointer to list of found files.\r
+ @param[in] ParentNode The node for the parent. Same file as identified by HANDLE.\r
+\r
+ @retval EFI_SUCCESS all files were found and the FileList contains a list.\r
+ @retval EFI_NOT_FOUND no files were found\r
+ @retval EFI_OUT_OF_RESOURCES a memory allocation failed\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellSearchHandle(\r
+ IN CONST CHAR16 *FilePattern,\r
+ IN EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation,\r
+ IN SHELL_FILE_HANDLE FileHandle,\r
+ IN OUT EFI_SHELL_FILE_INFO **FileList,\r
+ IN CONST EFI_SHELL_FILE_INFO *ParentNode OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CONST CHAR16 *NextFilePatternStart;\r
+ CHAR16 *CurrentFilePattern;\r
+ EFI_SHELL_FILE_INFO *ShellInfo;\r
+ EFI_SHELL_FILE_INFO *ShellInfoNode;\r
+ EFI_SHELL_FILE_INFO *NewShellNode;\r
+ BOOLEAN Directory;\r
+\r
+ if ( FilePattern == NULL\r
+ || UnicodeCollation == NULL\r
+ || FileList == NULL\r
+ ){\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ ShellInfo = NULL;\r
+ CurrentFilePattern = NULL;\r
+\r
+ if (*FilePattern == L'\\') {\r
+ FilePattern++;\r
+ }\r
+\r
+ for( NextFilePatternStart = FilePattern\r
+ ; *NextFilePatternStart != CHAR_NULL && *NextFilePatternStart != L'\\'\r
+ ; NextFilePatternStart++);\r
+\r
+ CurrentFilePattern = AllocateZeroPool((NextFilePatternStart-FilePattern+1)*sizeof(CHAR16));\r
+ ASSERT(CurrentFilePattern != NULL);\r
+ StrnCpy(CurrentFilePattern, FilePattern, NextFilePatternStart-FilePattern);\r
+\r
+ if (CurrentFilePattern[0] == CHAR_NULL\r
+ &&NextFilePatternStart[0] == CHAR_NULL\r
+ ){\r
+ //\r
+ // Add the current parameter FileHandle to the list, then end...\r
+ //\r
+ if (ParentNode == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ NewShellNode = InternalDuplicateShellFileInfo((EFI_SHELL_FILE_INFO*)ParentNode, TRUE);\r
+ if (NewShellNode == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ } else {\r
+ NewShellNode->Handle = NULL;\r
+ if (*FileList == NULL) {\r
+ *FileList = AllocatePool(sizeof(EFI_SHELL_FILE_INFO));\r
+ InitializeListHead(&((*FileList)->Link));\r
+ }\r
+\r
+ //\r
+ // Add to the returning to use list\r
+ //\r
+ InsertTailList(&(*FileList)->Link, &NewShellNode->Link);\r
+\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+ } else {\r
+ Status = EfiShellFindFilesInDir(FileHandle, &ShellInfo);\r
+\r
+ if (!EFI_ERROR(Status)){\r
+ if (StrStr(NextFilePatternStart, L"\\") != NULL){\r
+ Directory = TRUE;\r
+ } else {\r
+ Directory = FALSE;\r
+ }\r
+ for ( ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetFirstNode(&ShellInfo->Link)\r
+ ; !IsNull (&ShellInfo->Link, &ShellInfoNode->Link)\r
+ ; ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ShellInfo->Link, &ShellInfoNode->Link)\r
+ ){\r
+ if (UnicodeCollation->MetaiMatch(UnicodeCollation, (CHAR16*)ShellInfoNode->FileName, CurrentFilePattern)){\r
+ if (Directory){\r
+ //\r
+ // should be a directory\r
+ //\r
+\r
+ //\r
+ // don't open the . and .. directories\r
+ //\r
+ if ( (StrCmp(ShellInfoNode->FileName, L".") != 0)\r
+ && (StrCmp(ShellInfoNode->FileName, L"..") != 0)\r
+ ){\r
+ //\r
+ //\r
+ //\r
+ ASSERT_EFI_ERROR(Status);\r
+ if (EFI_ERROR(Status)) {\r
+ break;\r
+ }\r
+ //\r
+ // Open the directory since we need that handle in the next recursion.\r
+ //\r
+ ShellInfoNode->Status = EfiShellOpenFileByName (ShellInfoNode->FullName, &ShellInfoNode->Handle, EFI_FILE_MODE_READ);\r
+\r
+ //\r
+ // recurse with the next part of the pattern\r
+ //\r
+ Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode);\r
+ }\r
+ } else {\r
+ //\r
+ // should be a file\r
+ //\r
+\r
+ //\r
+ // copy the information we need into a new Node\r
+ //\r
+ NewShellNode = InternalDuplicateShellFileInfo(ShellInfoNode, FALSE);\r
+ ASSERT(NewShellNode != NULL);\r
+ if (NewShellNode == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ if (*FileList == NULL) {\r
+ *FileList = AllocatePool(sizeof(EFI_SHELL_FILE_INFO));\r
+ InitializeListHead(&((*FileList)->Link));\r
+ }\r
+\r
+ //\r
+ // Add to the returning to use list\r
+ //\r
+ InsertTailList(&(*FileList)->Link, &NewShellNode->Link);\r
+ }\r
+ }\r
+ if (EFI_ERROR(Status)) {\r
+ break;\r
+ }\r
+ }\r
+ if (EFI_ERROR(Status)) {\r
+ EfiShellFreeFileList(&ShellInfo);\r
+ } else {\r
+ Status = EfiShellFreeFileList(&ShellInfo);\r
+ }\r
+ }\r
+ }\r
+\r
+ FreePool(CurrentFilePattern);\r
+ return (Status);\r
+}\r
+\r
+/**\r
+ Find files that match a specified pattern.\r
+\r
+ This function searches for all files and directories that match the specified\r
+ FilePattern. The FilePattern can contain wild-card characters. The resulting file\r
+ information is placed in the file list FileList.\r
+\r
+ Wildcards are processed\r
+ according to the rules specified in UEFI Shell 2.0 spec section 3.7.1.\r
+\r
+ The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo\r
+ field is set to NULL.\r
+\r
+ if *FileList is not NULL then it must be a pre-existing and properly initialized list.\r
+\r
+ @param FilePattern Points to a NULL-terminated shell file path, including wildcards.\r
+ @param FileList On return, points to the start of a file list containing the names\r
+ of all matching files or else points to NULL if no matching files\r
+ were found. only on a EFI_SUCCESS return will; this be non-NULL.\r
+\r
+ @retval EFI_SUCCESS Files found. FileList is a valid list.\r
+ @retval EFI_NOT_FOUND No files found.\r
+ @retval EFI_NO_MEDIA The device has no media\r
+ @retval EFI_DEVICE_ERROR The device reported an error\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellFindFiles(\r
+ IN CONST CHAR16 *FilePattern,\r
+ OUT EFI_SHELL_FILE_INFO **FileList\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 *PatternCopy;\r
+ CHAR16 *PatternCurrentLocation;\r
+ EFI_DEVICE_PATH_PROTOCOL *RootDevicePath;\r
+ SHELL_FILE_HANDLE RootFileHandle;\r
+ CHAR16 *MapName;\r
+ UINTN Count;\r
+\r
+ if ( FilePattern == NULL\r
+ || FileList == NULL\r
+ || StrStr(FilePattern, L":") == NULL\r
+ ){\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ Status = EFI_SUCCESS;\r
+ RootDevicePath = NULL;\r
+ RootFileHandle = NULL;\r
+ MapName = NULL;\r
+ PatternCopy = AllocatePool(StrSize(FilePattern));\r
+ if (PatternCopy == NULL) {\r
+ return (EFI_OUT_OF_RESOURCES);\r
+ }\r
+ StrCpy(PatternCopy, FilePattern);\r
+\r
+ PatternCopy = CleanPath(PatternCopy);\r
+\r
+ Count = StrStr(PatternCopy, L":") - PatternCopy;\r
+ Count += 2;\r
+\r
+ ASSERT(MapName == NULL);\r
+ MapName = StrnCatGrow(&MapName, NULL, PatternCopy, Count);\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ RootDevicePath = EfiShellGetDevicePathFromFilePath(PatternCopy);\r
+ if (RootDevicePath == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ } else {\r
+ Status = EfiShellOpenRoot(RootDevicePath, &RootFileHandle);\r
+ if (!EFI_ERROR(Status)) {\r
+ for ( PatternCurrentLocation = PatternCopy\r
+ ; *PatternCurrentLocation != ':'\r
+ ; PatternCurrentLocation++);\r
+ PatternCurrentLocation++;\r
+ Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL);\r
+ }\r
+ FreePool(RootDevicePath);\r
+ }\r
+ }\r
+\r
+ if (PatternCopy != NULL) {\r
+ FreePool(PatternCopy);\r
+ }\r
+ if (MapName != NULL) {\r
+ FreePool(MapName);\r
+ }\r
+\r
+ return(Status);\r
+}\r
+\r
+/**\r
+ Opens the files that match the path specified.\r
+\r
+ This function opens all of the files specified by Path. Wildcards are processed\r
+ according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each\r
+ matching file has an EFI_SHELL_FILE_INFO structure created in a linked list.\r
+\r
+ @param Path A pointer to the path string.\r
+ @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or\r
+ EFI_FILE_MODE_WRITE.\r
+ @param FileList Points to the start of a list of files opened.\r
+\r
+ @retval EFI_SUCCESS Create the file list successfully.\r
+ @return Others Can't create the file list.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellOpenFileList(\r
+ IN CHAR16 *Path,\r
+ IN UINT64 OpenMode,\r
+ IN OUT EFI_SHELL_FILE_INFO **FileList\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SHELL_FILE_INFO *ShellFileListItem;\r
+ CHAR16 *Path2;\r
+ UINTN Path2Size;\r
+ CONST CHAR16 *CurDir;\r
+\r
+ ShellCommandCleanPath(Path);\r
+\r
+ Path2Size = 0;\r
+ Path2 = NULL;\r
+\r
+ ASSERT(FileList != NULL);\r
+ ASSERT(*FileList != NULL);\r
+\r
+ if (*Path == L'.' && *(Path+1) == L'\\') {\r
+ Path++;\r
+ }\r
+\r
+ //\r
+ // convert a local path to an absolute path\r
+ //\r
+ if (StrStr(Path, L":") == NULL) {\r
+ CurDir = EfiShellGetCurDir(NULL);\r
+ ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
+ StrnCatGrow(&Path2, &Path2Size, CurDir, 0);\r
+ if (*Path == L'\\') {\r
+ Path++;\r
+ }\r
+ ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
+ StrnCatGrow(&Path2, &Path2Size, Path, 0);\r
+ } else {\r
+ ASSERT(Path2 == NULL);\r
+ StrnCatGrow(&Path2, NULL, Path, 0);\r
+ }\r
+\r
+ CleanPath (Path2);\r
+\r
+ //\r
+ // do the search\r
+ //\r
+ Status = EfiShellFindFiles(Path2, FileList);\r
+\r
+ FreePool(Path2);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+\r
+ //\r
+ // We had no errors so open all the files (that are not already opened...)\r
+ //\r
+ for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)\r
+ ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link)\r
+ ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)\r
+ ){\r
+ if (ShellFileListItem->Status == 0 && ShellFileListItem->Handle == NULL) {\r
+ ShellFileListItem->Status = EfiShellOpenFileByName (ShellFileListItem->FullName, &ShellFileListItem->Handle, OpenMode);\r
+ }\r
+ }\r
+\r
+ return(EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ This function updated with errata.\r
+\r
+ Gets either a single or list of environment variables.\r
+\r
+ If name is not NULL then this function returns the current value of the specified\r
+ environment variable.\r
+\r
+ If Name is NULL, then a list of all environment variable names is returned. Each is a\r
+ NULL terminated string with a double NULL terminating the list.\r
+\r
+ @param Name A pointer to the environment variable name. If\r
+ Name is NULL, then the function will return all\r
+ of the defined shell environment variables. In\r
+ the case where multiple environment variables are\r
+ being returned, each variable will be terminated by\r
+ a NULL, and the list will be terminated by a double\r
+ NULL.\r
+\r
+ @return !=NULL A pointer to the returned string.\r
+ The returned pointer does not need to be freed by the caller.\r
+\r
+ @retval NULL The environment variable doesn't exist or there are\r
+ no environment variables.\r
+**/\r
+CONST CHAR16 *\r
+EFIAPI\r
+EfiShellGetEnv(\r
+ IN CONST CHAR16 *Name\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *Buffer;\r
+ UINTN Size;\r
+ LIST_ENTRY List;\r
+ ENV_VAR_LIST *Node;\r
+ CHAR16 *CurrentWriteLocation;\r
+\r
+ Size = 0;\r
+ Buffer = NULL;\r
+\r
+ if (Name == NULL) {\r
+ //\r
+ // Get all our environment variables\r
+ //\r
+ InitializeListHead(&List);\r
+ Status = GetEnvironmentVariableList(&List);\r
+ if (EFI_ERROR(Status)){\r
+ return (NULL);\r
+ }\r
+\r
+ //\r
+ // Build the semi-colon delimited list. (2 passes)\r
+ //\r
+ for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List)\r
+ ; !IsNull(&List, &Node->Link)\r
+ ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)\r
+ ){\r
+ ASSERT(Node->Key != NULL);\r
+ Size += StrSize(Node->Key);\r
+ }\r
+\r
+ Size += 2*sizeof(CHAR16);\r
+\r
+ Buffer = AllocateZeroPool(Size);\r
+ CurrentWriteLocation = (CHAR16*)Buffer;\r
+\r
+ for ( Node = (ENV_VAR_LIST*)GetFirstNode(&List)\r
+ ; !IsNull(&List, &Node->Link)\r
+ ; Node = (ENV_VAR_LIST*)GetNextNode(&List, &Node->Link)\r
+ ){\r
+ ASSERT(Node->Key != NULL);\r
+ StrCpy(CurrentWriteLocation, Node->Key);\r
+ CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1;\r
+ }\r
+\r
+ //\r
+ // Free the list...\r
+ //\r
+ FreeEnvironmentVariableList(&List);\r
+ } else {\r
+ //\r
+ // We are doing a specific environment variable\r
+ //\r
+\r
+ //\r
+ // get the size we need for this EnvVariable\r
+ //\r
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE(Name, &Size, Buffer);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // Allocate the space and recall the get function\r
+ //\r
+ Buffer = AllocateZeroPool(Size);\r
+ ASSERT(Buffer != NULL);\r
+ Status = SHELL_GET_ENVIRONMENT_VARIABLE(Name, &Size, Buffer);\r
+ }\r
+ //\r
+ // we didnt get it (might not exist)\r
+ // free the memory if we allocated any and return NULL\r
+ //\r
+ if (EFI_ERROR(Status)) {\r
+ if (Buffer != NULL) {\r
+ FreePool(Buffer);\r
+ }\r
+ return (NULL);\r
+ }\r
+ }\r
+\r
+ //\r
+ // return the buffer\r
+ //\r
+ return (AddBufferToFreeList(Buffer));\r
+}\r
+\r
+/**\r
+ Internal variable setting function. Allows for setting of the read only variables.\r
+\r
+ @param Name Points to the NULL-terminated environment variable name.\r
+ @param Value Points to the NULL-terminated environment variable value. If the value is an\r
+ empty string then the environment variable is deleted.\r
+ @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).\r
+\r
+ @retval EFI_SUCCESS The environment variable was successfully updated.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InternalEfiShellSetEnv(\r
+ IN CONST CHAR16 *Name,\r
+ IN CONST CHAR16 *Value,\r
+ IN BOOLEAN Volatile\r
+ )\r
+{\r
+ if (Value == NULL || StrLen(Value) == 0) {\r
+ return (SHELL_DELETE_ENVIRONMENT_VARIABLE(Name));\r
+ } else {\r
+ SHELL_DELETE_ENVIRONMENT_VARIABLE(Name);\r
+ if (Volatile) {\r
+ return (SHELL_SET_ENVIRONMENT_VARIABLE_V(Name, StrSize(Value), Value));\r
+ } else {\r
+ return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(Name, StrSize(Value), Value));\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Sets the environment variable.\r
+\r
+ This function changes the current value of the specified environment variable. If the\r
+ environment variable exists and the Value is an empty string, then the environment\r
+ variable is deleted. If the environment variable exists and the Value is not an empty\r
+ string, then the value of the environment variable is changed. If the environment\r
+ variable does not exist and the Value is an empty string, there is no action. If the\r
+ environment variable does not exist and the Value is a non-empty string, then the\r
+ environment variable is created and assigned the specified value.\r
+\r
+ For a description of volatile and non-volatile environment variables, see UEFI Shell\r
+ 2.0 specification section 3.6.1.\r
+\r
+ @param Name Points to the NULL-terminated environment variable name.\r
+ @param Value Points to the NULL-terminated environment variable value. If the value is an\r
+ empty string then the environment variable is deleted.\r
+ @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).\r
+\r
+ @retval EFI_SUCCESS The environment variable was successfully updated.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellSetEnv(\r
+ IN CONST CHAR16 *Name,\r
+ IN CONST CHAR16 *Value,\r
+ IN BOOLEAN Volatile\r
+ )\r
+{\r
+ if (Name == NULL || *Name == CHAR_NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ //\r
+ // Make sure we dont 'set' a predefined read only variable\r
+ //\r
+ if (gUnicodeCollation->StriColl(\r
+ gUnicodeCollation,\r
+ (CHAR16*)Name,\r
+ L"cwd") == 0\r
+ ||gUnicodeCollation->StriColl(\r
+ gUnicodeCollation,\r
+ (CHAR16*)Name,\r
+ L"Lasterror") == 0\r
+ ||gUnicodeCollation->StriColl(\r
+ gUnicodeCollation,\r
+ (CHAR16*)Name,\r
+ L"profiles") == 0\r
+ ||gUnicodeCollation->StriColl(\r
+ gUnicodeCollation,\r
+ (CHAR16*)Name,\r
+ L"uefishellsupport") == 0\r
+ ||gUnicodeCollation->StriColl(\r
+ gUnicodeCollation,\r
+ (CHAR16*)Name,\r
+ L"uefishellversion") == 0\r
+ ||gUnicodeCollation->StriColl(\r
+ gUnicodeCollation,\r
+ (CHAR16*)Name,\r
+ L"uefiversion") == 0\r
+ ){\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ return (InternalEfiShellSetEnv(Name, Value, Volatile));\r
+}\r
+\r
+/**\r
+ Returns the current directory on the specified device.\r
+\r
+ If FileSystemMapping is NULL, it returns the current working directory. If the\r
+ FileSystemMapping is not NULL, it returns the current directory associated with the\r
+ FileSystemMapping. In both cases, the returned name includes the file system\r
+ mapping (i.e. fs0:\current-dir).\r
+\r
+ @param FileSystemMapping A pointer to the file system mapping. If NULL,\r
+ then the current working directory is returned.\r
+\r
+ @retval !=NULL The current directory.\r
+ @retval NULL Current directory does not exist.\r
+**/\r
+CONST CHAR16 *\r
+EFIAPI\r
+EfiShellGetCurDir(\r
+ IN CONST CHAR16 *FileSystemMapping OPTIONAL\r
+ )\r
+{\r
+ CHAR16 *PathToReturn;\r
+ UINTN Size;\r
+ SHELL_MAP_LIST *MapListItem;\r
+ if (!IsListEmpty(&gShellMapList.Link)) {\r
+ //\r
+ // if parameter is NULL, use current\r
+ //\r
+ if (FileSystemMapping == NULL) {\r
+ return (EfiShellGetEnv(L"cwd"));\r
+ } else {\r
+ Size = 0;\r
+ PathToReturn = NULL;\r
+ MapListItem = ShellCommandFindMapItem(FileSystemMapping);\r
+ if (MapListItem != NULL) {\r
+ ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL));\r
+ PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->MapName, 0);\r
+ PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->CurrentDirectoryPath, 0);\r
+ }\r
+ }\r
+ return (AddBufferToFreeList(PathToReturn));\r
+ } else {\r
+ return (NULL);\r
+ }\r
+}\r
+\r
+/**\r
+ Changes the current directory on the specified device.\r
+\r
+ If the FileSystem is NULL, and the directory Dir does not contain a file system's\r
+ mapped name, this function changes the current working directory.\r
+\r
+ If the FileSystem is NULL and the directory Dir contains a mapped name, then the\r
+ current file system and the current directory on that file system are changed.\r
+\r
+ If FileSystem is NULL, and Dir is not NULL, then this changes the current working file\r
+ system.\r
+\r
+ If FileSystem is not NULL and Dir is not NULL, then this function changes the current\r
+ directory on the specified file system.\r
+\r
+ If the current working directory or the current working file system is changed then the\r
+ %cwd% environment variable will be updated\r
+\r
+ @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working\r
+ directory is changed.\r
+ @param Dir Points to the NULL-terminated directory on the device specified by FileSystem.\r
+\r
+ @retval EFI_SUCCESS The operation was sucessful\r
+ @retval EFI_NOT_FOUND The file system could not be found\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellSetCurDir(\r
+ IN CONST CHAR16 *FileSystem OPTIONAL,\r
+ IN CONST CHAR16 *Dir\r
+ )\r
+{\r
+ CHAR16 *MapName;\r
+ SHELL_MAP_LIST *MapListItem;\r
+ UINTN Size;\r
+ EFI_STATUS Status;\r
+ CHAR16 *TempString;\r
+ CHAR16 *DirectoryName;\r
+ UINTN TempLen;\r
+\r
+ Size = 0;\r
+ MapName = NULL;\r
+ MapListItem = NULL;\r
+ TempString = NULL;\r
+ DirectoryName = NULL;\r
+\r
+ if (FileSystem == NULL && Dir == NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ if (IsListEmpty(&gShellMapList.Link)){\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+\r
+ DirectoryName = StrnCatGrow(&DirectoryName, NULL, Dir, 0);\r
+ ASSERT(DirectoryName != NULL);\r
+\r
+ CleanPath(DirectoryName);\r
+\r
+ if (FileSystem == NULL) {\r
+ //\r
+ // determine the file system mapping to use\r
+ //\r
+ if (StrStr(DirectoryName, L":") != NULL) {\r
+ ASSERT(MapName == NULL);\r
+ MapName = StrnCatGrow(&MapName, NULL, DirectoryName, (StrStr(DirectoryName, L":")-DirectoryName+1));\r
+ }\r
+ //\r
+ // find the file system mapping's entry in the list\r
+ // or use current\r
+ //\r
+ if (MapName != NULL) {\r
+ MapListItem = ShellCommandFindMapItem(MapName);\r
+\r
+ //\r
+ // make that the current file system mapping\r
+ //\r
+ if (MapListItem != NULL) {\r
+ gShellCurDir = MapListItem;\r
+ }\r
+ } else {\r
+ MapListItem = gShellCurDir;\r
+ }\r
+\r
+ if (MapListItem == NULL) {\r
+ return (EFI_NOT_FOUND);\r
+ }\r
+\r
+ //\r
+ // now update the MapListItem's current directory\r
+ //\r
+ if (MapListItem->CurrentDirectoryPath != NULL && DirectoryName[StrLen(DirectoryName) - 1] != L':') {\r
+ FreePool(MapListItem->CurrentDirectoryPath);\r
+ MapListItem->CurrentDirectoryPath = NULL;\r
+ }\r
+ if (MapName != NULL) {\r
+ TempLen = StrLen(MapName);\r
+ if (TempLen != StrLen(DirectoryName)) {\r
+ ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
+ MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName+StrLen(MapName), 0);\r
+ }\r
+ } else {\r
+ ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
+ MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
+ }\r
+ if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {\r
+ ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
+ MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
+ }\r
+ } else {\r
+ //\r
+ // cant have a mapping in the directory...\r
+ //\r
+ if (StrStr(DirectoryName, L":") != NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+ //\r
+ // FileSystem != NULL\r
+ //\r
+ MapListItem = ShellCommandFindMapItem(FileSystem);\r
+ if (MapListItem == NULL) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+// gShellCurDir = MapListItem;\r
+ if (DirectoryName != NULL) {\r
+ //\r
+ // change current dir on that file system\r
+ //\r
+\r
+ if (MapListItem->CurrentDirectoryPath != NULL) {\r
+ FreePool(MapListItem->CurrentDirectoryPath);\r
+ DEBUG_CODE(MapListItem->CurrentDirectoryPath = NULL;);\r
+ }\r
+// ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
+// MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0);\r
+ ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
+ MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
+ ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
+ MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
+ if (MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] != L'\\') {\r
+ ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
+ MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // if updated the current directory then update the environment variable\r
+ //\r
+ if (MapListItem == gShellCurDir) {\r
+ Size = 0;\r
+ ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
+ StrnCatGrow(&TempString, &Size, MapListItem->MapName, 0);\r
+ ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
+ StrnCatGrow(&TempString, &Size, MapListItem->CurrentDirectoryPath, 0);\r
+ Status = InternalEfiShellSetEnv(L"cwd", TempString, TRUE);\r
+ FreePool(TempString);\r
+ return (Status);\r
+ }\r
+ return(EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ Return help information about a specific command.\r
+\r
+ This function returns the help information for the specified command. The help text\r
+ can be internal to the shell or can be from a UEFI Shell manual page.\r
+\r
+ If Sections is specified, then each section name listed will be compared in a casesensitive\r
+ manner, to the section names described in Appendix B. If the section exists,\r
+ it will be appended to the returned help text. If the section does not exist, no\r
+ information will be returned. If Sections is NULL, then all help text information\r
+ available will be returned.\r
+\r
+ @param Command Points to the NULL-terminated UEFI Shell command name.\r
+ @param Sections Points to the NULL-terminated comma-delimited\r
+ section names to return. If NULL, then all\r
+ sections will be returned.\r
+ @param HelpText On return, points to a callee-allocated buffer\r
+ containing all specified help text.\r
+\r
+ @retval EFI_SUCCESS The help text was returned.\r
+ @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the\r
+ returned help text.\r
+ @retval EFI_INVALID_PARAMETER HelpText is NULL\r
+ @retval EFI_NOT_FOUND There is no help text available for Command.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellGetHelpText(\r
+ IN CONST CHAR16 *Command,\r
+ IN CONST CHAR16 *Sections OPTIONAL,\r
+ OUT CHAR16 **HelpText\r
+ )\r
+{\r
+ CONST CHAR16 *ManFileName;\r
+\r
+ ASSERT(HelpText != NULL);\r
+\r
+ ManFileName = ShellCommandGetManFileNameHandler(Command);\r
+\r
+ if (ManFileName != NULL) {\r
+ return (ProcessManFile(ManFileName, Command, Sections, NULL, HelpText));\r
+ } else {\r
+ return (ProcessManFile(Command, Command, Sections, NULL, HelpText));\r
+ }\r
+}\r
+\r
+/**\r
+ Gets the enable status of the page break output mode.\r
+\r
+ User can use this function to determine current page break mode.\r
+\r
+ @retval TRUE The page break output mode is enabled.\r
+ @retval FALSE The page break output mode is disabled.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+EfiShellGetPageBreak(\r
+ VOID\r
+ )\r
+{\r
+ return(ShellInfoObject.PageBreakEnabled);\r
+}\r
+\r
+/**\r
+ Judges whether the active shell is the root shell.\r
+\r
+ This function makes the user to know that whether the active Shell is the root shell.\r
+\r
+ @retval TRUE The active Shell is the root Shell.\r
+ @retval FALSE The active Shell is NOT the root Shell.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+EfiShellIsRootShell(\r
+ VOID\r
+ )\r
+{\r
+ return(ShellInfoObject.RootShellInstance);\r
+}\r
+\r
+/**\r
+ function to return a semi-colon delimeted list of all alias' in the current shell\r
+\r
+ up to caller to free the memory.\r
+\r
+ @retval NULL No alias' were found\r
+ @retval NULL An error ocurred getting alias'\r
+ @return !NULL a list of all alias'\r
+**/\r
+CHAR16 *\r
+EFIAPI\r
+InternalEfiShellGetListAlias(\r
+ )\r
+{\r
+ UINT64 MaxStorSize;\r
+ UINT64 RemStorSize;\r
+ UINT64 MaxVarSize;\r
+ EFI_STATUS Status;\r
+ EFI_GUID Guid;\r
+ CHAR16 *VariableName;\r
+ UINTN NameSize;\r
+ CHAR16 *RetVal;\r
+ UINTN RetSize;\r
+ CHAR16 *Alias;\r
+\r
+ Status = gRT->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS, &MaxStorSize, &RemStorSize, &MaxVarSize);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ VariableName = AllocateZeroPool((UINTN)MaxVarSize);\r
+ RetSize = 0;\r
+ RetVal = NULL;\r
+\r
+ VariableName[0] = CHAR_NULL;\r
+\r
+ while (TRUE) {\r
+ NameSize = (UINTN)MaxVarSize;\r
+ Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
+ if (Status == EFI_NOT_FOUND){\r
+ break;\r
+ }\r
+ ASSERT_EFI_ERROR(Status);\r
+ if (EFI_ERROR(Status)) {\r
+ break;\r
+ }\r
+ if (CompareGuid(&Guid, &gShellAliasGuid)){\r
+ Alias = GetVariable(VariableName, &gShellAliasGuid);\r
+ ASSERT((RetVal == NULL && RetSize == 0) || (RetVal != NULL));\r
+ RetVal = StrnCatGrow(&RetVal, &RetSize, VariableName, 0);\r
+ RetVal = StrnCatGrow(&RetVal, &RetSize, L";", 0);\r
+ } // compare guid\r
+ } // while\r
+ FreePool(VariableName);\r
+\r
+ return (RetVal);\r
+}\r
+\r
+/**\r
+ This function returns the command associated with a alias or a list of all\r
+ alias'.\r
+\r
+ @param[in] Alias Points to the NULL-terminated shell alias.\r
+ If this parameter is NULL, then all\r
+ aliases will be returned in ReturnedData.\r
+ @param[out] Volatile upon return of a single command if TRUE indicates\r
+ this is stored in a volatile fashion. FALSE otherwise.\r
+\r
+ @return If Alias is not NULL, it will return a pointer to\r
+ the NULL-terminated command for that alias.\r
+ If Alias is NULL, ReturnedData points to a ';'\r
+ delimited list of alias (e.g.\r
+ ReturnedData = "dir;del;copy;mfp") that is NULL-terminated.\r
+ @retval NULL an error ocurred\r
+ @retval NULL Alias was not a valid Alias\r
+**/\r
+CONST CHAR16 *\r
+EFIAPI\r
+EfiShellGetAlias(\r
+ IN CONST CHAR16 *Alias,\r
+ OUT BOOLEAN *Volatile OPTIONAL\r
+ )\r
+{\r
+ CHAR16 *RetVal;\r
+ UINTN RetSize;\r
+ UINT32 Attribs;\r
+ EFI_STATUS Status;\r
+\r
+ if (Alias != NULL) {\r
+ if (Volatile == NULL) {\r
+ return (AddBufferToFreeList(GetVariable((CHAR16*)Alias, &gShellAliasGuid)));\r
+ }\r
+ RetSize = 0;\r
+ RetVal = NULL;\r
+ Status = gRT->GetVariable((CHAR16*)Alias, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ RetVal = AllocateZeroPool(RetSize);\r
+ Status = gRT->GetVariable((CHAR16*)Alias, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
+ }\r
+ if (EFI_ERROR(Status)) {\r
+ if (RetVal != NULL) {\r
+ FreePool(RetVal);\r
+ }\r
+ return (NULL);\r
+ }\r
+ if ((EFI_VARIABLE_NON_VOLATILE & Attribs) == EFI_VARIABLE_NON_VOLATILE) {\r
+ *Volatile = FALSE;\r
+ } else {\r
+ *Volatile = TRUE;\r
+ }\r
+\r
+ return (AddBufferToFreeList(RetVal));\r
+ }\r
+ return (AddBufferToFreeList(InternalEfiShellGetListAlias()));\r
+}\r
+\r
+/**\r
+ Changes a shell command alias.\r
+\r
+ This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.\r
+\r
+ this function does not check for built in alias'.\r
+\r
+ @param[in] Command Points to the NULL-terminated shell command or existing alias.\r
+ @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and\r
+ Command refers to an alias, that alias will be deleted.\r
+ @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the\r
+ Alias being set will be stored in a non-volatile fashion.\r
+\r
+ @retval EFI_SUCCESS Alias created or deleted successfully.\r
+ @retval EFI_NOT_FOUND the Alias intended to be deleted was not found\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InternalSetAlias(\r
+ IN CONST CHAR16 *Command,\r
+ IN CONST CHAR16 *Alias,\r
+ IN BOOLEAN Volatile\r
+ )\r
+{\r
+ //\r
+ // We must be trying to remove one if Alias is NULL\r
+ //\r
+ if (Alias == NULL) {\r
+ //\r
+ // remove an alias (but passed in COMMAND parameter)\r
+ //\r
+ return (gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL));\r
+ } else {\r
+ //\r
+ // Add and replace are the same\r
+ //\r
+\r
+ // We dont check the error return on purpose since the variable may not exist.\r
+ gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL);\r
+\r
+ return (gRT->SetVariable((CHAR16*)Alias, &gShellAliasGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS|(Volatile?0:EFI_VARIABLE_NON_VOLATILE), StrSize(Command), (VOID*)Command));\r
+ }\r
+}\r
+\r
+/**\r
+ Changes a shell command alias.\r
+\r
+ This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.\r
+\r
+\r
+ @param[in] Command Points to the NULL-terminated shell command or existing alias.\r
+ @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and\r
+ Command refers to an alias, that alias will be deleted.\r
+ @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If\r
+ FALSE and the alias already exists, then the existing alias is unchanged and\r
+ EFI_ACCESS_DENIED is returned.\r
+ @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the\r
+ Alias being set will be stored in a non-volatile fashion.\r
+\r
+ @retval EFI_SUCCESS Alias created or deleted successfully.\r
+ @retval EFI_NOT_FOUND the Alias intended to be deleted was not found\r
+ @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to\r
+ FALSE.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiShellSetAlias(\r
+ IN CONST CHAR16 *Command,\r
+ IN CONST CHAR16 *Alias,\r
+ IN BOOLEAN Replace,\r
+ IN BOOLEAN Volatile\r
+ )\r
+{\r
+ //\r
+ // cant set over a built in alias\r
+ //\r
+ if (ShellCommandIsOnAliasList(Alias==NULL?Command:Alias)) {\r
+ return (EFI_ACCESS_DENIED);\r
+ }\r
+ if (Command == NULL || *Command == CHAR_NULL || StrLen(Command) == 0) {\r
+ return (EFI_INVALID_PARAMETER);\r
+ }\r
+\r
+ if (EfiShellGetAlias(Command, NULL) != NULL && !Replace) {\r
+ return (EFI_ACCESS_DENIED);\r
+ }\r
+\r
+ return (InternalSetAlias(Command, Alias, Volatile));\r
+}\r
+\r
+// Pure FILE_HANDLE operations are passed to FileHandleLib\r
+// these functions are indicated by the *\r
+EFI_SHELL_PROTOCOL mShellProtocol = {\r
+ EfiShellExecute,\r
+ EfiShellGetEnv,\r
+ EfiShellSetEnv,\r
+ EfiShellGetAlias,\r
+ EfiShellSetAlias,\r
+ EfiShellGetHelpText,\r
+ EfiShellGetDevicePathFromMap,\r
+ EfiShellGetMapFromDevicePath,\r
+ EfiShellGetDevicePathFromFilePath,\r
+ EfiShellGetFilePathFromDevicePath,\r
+ EfiShellSetMap,\r
+ EfiShellGetCurDir,\r
+ EfiShellSetCurDir,\r
+ EfiShellOpenFileList,\r
+ EfiShellFreeFileList,\r
+ EfiShellRemoveDupInFileList,\r
+ EfiShellBatchIsActive,\r
+ EfiShellIsRootShell,\r
+ EfiShellEnablePageBreak,\r
+ EfiShellDisablePageBreak,\r
+ EfiShellGetPageBreak,\r
+ EfiShellGetDeviceName,\r
+ (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo, //*\r
+ (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo, //*\r
+ EfiShellOpenFileByName,\r
+ EfiShellClose,\r
+ EfiShellCreateFile,\r
+ (EFI_SHELL_READ_FILE)FileHandleRead, //*\r
+ (EFI_SHELL_WRITE_FILE)FileHandleWrite, //*\r
+ (EFI_SHELL_DELETE_FILE)FileHandleDelete, //*\r
+ EfiShellDeleteFileByName,\r
+ (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition, //*\r
+ (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition, //*\r
+ (EFI_SHELL_FLUSH_FILE)FileHandleFlush, //*\r
+ EfiShellFindFiles,\r
+ EfiShellFindFilesInDir,\r
+ (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize, //*\r
+ EfiShellOpenRoot,\r
+ EfiShellOpenRootByHandle,\r
+ NULL,\r
+ SHELL_MAJOR_VERSION,\r
+ SHELL_MINOR_VERSION\r
+};\r
+\r
+/**\r
+ Function to create and install on the current handle.\r
+\r
+ Will overwrite any existing ShellProtocols in the system to be sure that\r
+ the current shell is in control.\r
+\r
+ This must be removed via calling CleanUpShellProtocol().\r
+\r
+ @param[in,out] NewShell The pointer to the pointer to the structure \r
+ to install.\r
+\r
+ @retval EFI_SUCCESS The operation was successful.\r
+ @return An error from LocateHandle, CreateEvent, or other core function.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CreatePopulateInstallShellProtocol (\r
+ IN OUT EFI_SHELL_PROTOCOL **NewShell\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ EFI_HANDLE *Buffer;\r
+ UINTN HandleCounter;\r
+ SHELL_PROTOCOL_HANDLE_LIST *OldProtocolNode;\r
+\r
+ BufferSize = 0;\r
+ Buffer = NULL;\r
+ OldProtocolNode = NULL;\r
+ InitializeListHead(&ShellInfoObject.OldShellList.Link);\r
+\r
+ ASSERT(NewShell != NULL);\r
+\r
+ //\r
+ // Initialize EfiShellProtocol object...\r
+ //\r
+ *NewShell = &mShellProtocol;\r
+ Status = gBS->CreateEvent(0,\r
+ 0,\r
+ NULL,\r
+ NULL,\r
+ &mShellProtocol.ExecutionBreak);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ //\r
+ // Get the size of the buffer we need.\r
+ //\r
+ Status = gBS->LocateHandle(ByProtocol,\r
+ &gEfiShellProtocolGuid,\r
+ NULL,\r
+ &BufferSize,\r
+ Buffer);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // Allocate and recall with buffer of correct size\r
+ //\r
+ Buffer = AllocateZeroPool(BufferSize);\r
+ ASSERT(Buffer != NULL);\r
+ Status = gBS->LocateHandle(ByProtocol,\r
+ &gEfiShellProtocolGuid,\r
+ NULL,\r
+ &BufferSize,\r
+ Buffer);\r
+ ASSERT_EFI_ERROR(Status);\r
+ //\r
+ // now overwrite each of them, but save the info to restore when we end.\r
+ //\r
+ for (HandleCounter = 0 ; HandleCounter < (BufferSize/sizeof(EFI_HANDLE)) ; HandleCounter++) {\r
+ OldProtocolNode = AllocateZeroPool(sizeof(SHELL_PROTOCOL_HANDLE_LIST));\r
+ ASSERT(OldProtocolNode != NULL);\r
+ Status = gBS->OpenProtocol(Buffer[HandleCounter],\r
+ &gEfiShellProtocolGuid,\r
+ (VOID **) &(OldProtocolNode->Interface),\r
+ gImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // reinstall over the old one...\r
+ //\r
+ OldProtocolNode->Handle = Buffer[HandleCounter];\r
+ Status = gBS->ReinstallProtocolInterface(\r
+ OldProtocolNode->Handle,\r
+ &gEfiShellProtocolGuid,\r
+ OldProtocolNode->Interface,\r
+ (VOID*)(*NewShell));\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // we reinstalled sucessfully. log this so we can reverse it later.\r
+ //\r
+\r
+ //\r
+ // add to the list for subsequent...\r
+ //\r
+ InsertTailList(&ShellInfoObject.OldShellList.Link, &OldProtocolNode->Link);\r
+ }\r
+ }\r
+ }\r
+ FreePool(Buffer);\r
+ } else if (Status == EFI_NOT_FOUND) {\r
+ ASSERT(IsListEmpty(&ShellInfoObject.OldShellList.Link));\r
+ //\r
+ // no one else published yet. just publish it ourselves.\r
+ //\r
+ Status = gBS->InstallProtocolInterface (\r
+ &gImageHandle,\r
+ &gEfiShellProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ (VOID*)(*NewShell));\r
+ }\r
+\r
+ if (PcdGetBool(PcdShellSupportOldProtocols)){\r
+ ///@todo support ShellEnvironment2\r
+ ///@todo do we need to support ShellEnvironment (not ShellEnvironment2) also?\r
+ }\r
+\r
+ return (Status);\r
+}\r
+\r
+/**\r
+ Opposite of CreatePopulateInstallShellProtocol. \r
+\r
+ Free all memory and restore the system to the state it was in before calling\r
+ CreatePopulateInstallShellProtocol.\r
+\r
+ @param[in,out] NewShell The pointer to the new shell protocol structure.\r
+\r
+ @retval EFI_SUCCESS The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CleanUpShellProtocol (\r
+ IN OUT EFI_SHELL_PROTOCOL *NewShell\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SHELL_PROTOCOL_HANDLE_LIST *Node2;\r
+\r
+ //\r
+ // if we need to restore old protocols...\r
+ //\r
+ if (!IsListEmpty(&ShellInfoObject.OldShellList.Link)) {\r
+ for (Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link)\r
+ ; !IsListEmpty (&ShellInfoObject.OldShellList.Link)\r
+ ; Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link)\r
+ ){\r
+ RemoveEntryList(&Node2->Link);\r
+ Status = gBS->ReinstallProtocolInterface(Node2->Handle,\r
+ &gEfiShellProtocolGuid,\r
+ NewShell,\r
+ Node2->Interface);\r
+ ASSERT_EFI_ERROR(Status);\r
+ FreePool(Node2);\r
+ }\r
+ } else {\r
+ //\r
+ // no need to restore\r
+ //\r
+ Status = gBS->UninstallProtocolInterface(gImageHandle,\r
+ &gEfiShellProtocolGuid,\r
+ NewShell);\r
+ ASSERT_EFI_ERROR(Status);\r
+ }\r
+ Status = gBS->CloseEvent(NewShell->ExecutionBreak);\r
+\r
+ return (Status);\r
+}\r
+\r
+\r