X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ShellPkg%2FLibrary%2FUefiShellLib%2FUefiShellLib.c;h=9f07a58eb23d38a8aa4da36f3abb6f40888f5330;hb=7eb6160d4fdff25ca623a4006e6f93e5e81038bf;hp=06e2386378296df769c07a29ea9234ec752e7728;hpb=02a758cb0b5bc8775d95e0a52acc483f850124a1;p=mirror_edk2.git
diff --git a/ShellPkg/Library/UefiShellLib/UefiShellLib.c b/ShellPkg/Library/UefiShellLib/UefiShellLib.c
index 06e2386378..9f07a58eb2 100644
--- a/ShellPkg/Library/UefiShellLib/UefiShellLib.c
+++ b/ShellPkg/Library/UefiShellLib/UefiShellLib.c
@@ -1,22 +1,16 @@
/** @file
Provides interface to shell functionality for shell commands and applications.
- Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ Copyright 2016-2018 Dell Technologies.
+ Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "UefiShellLib.h"
-#include
#include
-
-#define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)
+#include
//
// globals...
@@ -34,6 +28,126 @@ EFI_SHELL_PROTOCOL *gEfiShellProtocol;
EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol;
EFI_HANDLE mEfiShellEnvironment2Handle;
FILE_HANDLE_FUNCTION_MAP FileFunctionMap;
+EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollationProtocol;
+
+/**
+ Return a clean, fully-qualified version of an input path. If the return value
+ is non-NULL the caller must free the memory when it is no longer needed.
+
+ If asserts are disabled, and if the input parameter is NULL, NULL is returned.
+
+ If there is not enough memory available to create the fully-qualified path or
+ a copy of the input path, NULL is returned.
+
+ If there is no working directory, a clean copy of Path is returned.
+
+ Otherwise, the current file system or working directory (as appropriate) is
+ prepended to Path and the resulting path is cleaned and returned.
+
+ NOTE: If the input path is an empty string, then the current working directory
+ (if it exists) is returned. In other words, an empty input path is treated
+ exactly the same as ".".
+
+ @param[in] Path A pointer to some file or directory path.
+
+ @retval NULL The input path is NULL or out of memory.
+
+ @retval non-NULL A pointer to a clean, fully-qualified version of Path.
+ If there is no working directory, then a pointer to a
+ clean, but not necessarily fully-qualified version of
+ Path. The caller must free this memory when it is no
+ longer needed.
+**/
+CHAR16*
+EFIAPI
+FullyQualifyPath(
+ IN CONST CHAR16 *Path
+ )
+{
+ CONST CHAR16 *WorkingPath;
+ CONST CHAR16 *InputPath;
+ CHAR16 *CharPtr;
+ CHAR16 *InputFileSystem;
+ UINTN FileSystemCharCount;
+ CHAR16 *FullyQualifiedPath;
+ UINTN Size;
+
+ FullyQualifiedPath = NULL;
+
+ ASSERT(Path != NULL);
+ //
+ // Handle erroneous input when asserts are disabled.
+ //
+ if (Path == NULL) {
+ return NULL;
+ }
+ //
+ // In paths that contain ":", like fs0:dir/file.ext and fs2:\fqpath\file.ext,
+ // we have to consider the file system part separately from the "path" part.
+ // If there is a file system in the path, we have to get the current working
+ // directory for that file system. Then we need to use the part of the path
+ // following the ":". If a path does not contain ":", we use it as given.
+ //
+ InputPath = StrStr(Path, L":");
+ if (InputPath != NULL) {
+ InputPath++;
+ FileSystemCharCount = ((UINTN)InputPath - (UINTN)Path + sizeof(CHAR16)) / sizeof(CHAR16);
+ InputFileSystem = AllocateCopyPool(FileSystemCharCount * sizeof(CHAR16), Path);
+ if (InputFileSystem != NULL) {
+ InputFileSystem[FileSystemCharCount - 1] = CHAR_NULL;
+ }
+ WorkingPath = ShellGetCurrentDir(InputFileSystem);
+ SHELL_FREE_NON_NULL(InputFileSystem);
+ } else {
+ InputPath = Path;
+ WorkingPath = ShellGetEnvironmentVariable(L"cwd");
+ }
+
+ if (WorkingPath == NULL) {
+ //
+ // With no working directory, all we can do is copy and clean the input path.
+ //
+ FullyQualifiedPath = AllocateCopyPool(StrSize(Path), Path);
+ } else {
+ //
+ // Allocate space for both strings plus one more character.
+ //
+ Size = StrSize(WorkingPath) + StrSize(InputPath);
+ FullyQualifiedPath = AllocateZeroPool(Size);
+ if (FullyQualifiedPath == NULL) {
+ //
+ // Try to copy and clean just the input. No harm if not enough memory.
+ //
+ FullyQualifiedPath = AllocateCopyPool(StrSize(Path), Path);
+ } else {
+ if (*InputPath == L'\\' || *InputPath == L'/') {
+ //
+ // Absolute path: start with the current working directory, then
+ // truncate the new path after the file system part.
+ //
+ StrCpyS(FullyQualifiedPath, Size/sizeof(CHAR16), WorkingPath);
+ CharPtr = StrStr(FullyQualifiedPath, L":");
+ if (CharPtr != NULL) {
+ *(CharPtr + 1) = CHAR_NULL;
+ }
+ } else {
+ //
+ // Relative path: start with the working directory and append "\".
+ //
+ StrCpyS(FullyQualifiedPath, Size/sizeof(CHAR16), WorkingPath);
+ StrCatS(FullyQualifiedPath, Size/sizeof(CHAR16), L"\\");
+ }
+ //
+ // Now append the absolute or relative path.
+ //
+ StrCatS(FullyQualifiedPath, Size/sizeof(CHAR16), InputPath);
+ }
+ }
+
+ PathCleanUpDirectories(FullyQualifiedPath);
+
+ return FullyQualifiedPath;
+}
/**
Check if a Unicode character is a hexadecimal character.
@@ -84,9 +198,10 @@ ShellIsDecimalDigitCharacter (
Helper function to find ShellEnvironment2 for constructor.
@param[in] ImageHandle A copy of the calling image's handle.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
**/
EFI_STATUS
-EFIAPI
ShellFindSE2 (
IN EFI_HANDLE ImageHandle
)
@@ -123,7 +238,9 @@ ShellFindSE2 (
//
if (Status == EFI_BUFFER_TOO_SMALL) {
Buffer = (EFI_HANDLE*)AllocateZeroPool(BufferSize);
- ASSERT(Buffer != NULL);
+ if (Buffer == NULL) {
+ return (EFI_OUT_OF_RESOURCES);
+ }
Status = gBS->LocateHandle (ByProtocol,
&gEfiShellEnvironment2Guid,
NULL, // ignored for ByProtocol
@@ -159,7 +276,7 @@ ShellFindSE2 (
}
/**
- Function to do most of the work of the constructor. Allows for calling
+ Function to do most of the work of the constructor. Allows for calling
multiple times without complete re-initialization.
@param[in] ImageHandle A copy of the ImageHandle.
@@ -168,7 +285,6 @@ ShellFindSE2 (
@retval EFI_SUCCESS The operationw as successful.
**/
EFI_STATUS
-EFIAPI
ShellLibConstructorWorker (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
@@ -176,43 +292,48 @@ ShellLibConstructorWorker (
{
EFI_STATUS Status;
- //
- // UEFI 2.0 shell interfaces (used preferentially)
- //
- Status = gBS->OpenProtocol(
- ImageHandle,
- &gEfiShellProtocolGuid,
- (VOID **)&gEfiShellProtocol,
- ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR(Status)) {
+ if (gEfiShellProtocol == NULL) {
//
- // Search for the shell protocol
+ // UEFI 2.0 shell interfaces (used preferentially)
//
- Status = gBS->LocateProtocol(
+ Status = gBS->OpenProtocol (
+ ImageHandle,
&gEfiShellProtocolGuid,
+ (VOID **)&gEfiShellProtocol,
+ ImageHandle,
NULL,
- (VOID **)&gEfiShellProtocol
- );
- if (EFI_ERROR(Status)) {
- gEfiShellProtocol = NULL;
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Search for the shell protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiShellProtocolGuid,
+ NULL,
+ (VOID **)&gEfiShellProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ gEfiShellProtocol = NULL;
+ }
}
}
- Status = gBS->OpenProtocol(
- ImageHandle,
- &gEfiShellParametersProtocolGuid,
- (VOID **)&gEfiShellParametersProtocol,
- ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR(Status)) {
- gEfiShellParametersProtocol = NULL;
+
+ if (gEfiShellParametersProtocol == NULL) {
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID **)&gEfiShellParametersProtocol,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ gEfiShellParametersProtocol = NULL;
+ }
}
- if (gEfiShellParametersProtocol == NULL || gEfiShellProtocol == NULL) {
+ if (gEfiShellProtocol == NULL) {
//
// Moved to seperate function due to complexity
//
@@ -235,10 +356,14 @@ ShellLibConstructorWorker (
}
//
- // only success getting 2 of either the old or new, but no 1/2 and 1/2
+ // Getting either EDK Shell's ShellEnvironment2 and ShellInterface protocol
+ // or UEFI Shell's Shell protocol.
+ // When ShellLib is linked to a driver producing DynamicCommand protocol,
+ // ShellParameters protocol is set by DynamicCommand.Handler().
//
- if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) ||
- (gEfiShellProtocol != NULL && gEfiShellParametersProtocol != NULL) ) {
+ if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) ||
+ (gEfiShellProtocol != NULL)
+ ) {
if (gEfiShellProtocol != NULL) {
FileFunctionMap.GetFileInfo = gEfiShellProtocol->GetFileInfo;
FileFunctionMap.SetFileInfo = gEfiShellProtocol->SetFileInfo;
@@ -289,6 +414,7 @@ ShellLibConstructor (
gEfiShellParametersProtocol = NULL;
mEfiShellInterface = NULL;
mEfiShellEnvironment2Handle = NULL;
+ mUnicodeCollationProtocol = NULL;
//
// verify that auto initialize is not set false
@@ -316,35 +442,45 @@ ShellLibDestructor (
IN EFI_SYSTEM_TABLE *SystemTable
)
{
+ EFI_STATUS Status;
+
if (mEfiShellEnvironment2 != NULL) {
- gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,
+ Status = gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,
&gEfiShellEnvironment2Guid,
ImageHandle,
NULL);
- mEfiShellEnvironment2 = NULL;
+ if (!EFI_ERROR (Status)) {
+ mEfiShellEnvironment2 = NULL;
+ mEfiShellEnvironment2Handle = NULL;
+ }
}
if (mEfiShellInterface != NULL) {
- gBS->CloseProtocol(ImageHandle,
+ Status = gBS->CloseProtocol(ImageHandle,
&gEfiShellInterfaceGuid,
ImageHandle,
NULL);
- mEfiShellInterface = NULL;
+ if (!EFI_ERROR (Status)) {
+ mEfiShellInterface = NULL;
+ }
}
if (gEfiShellProtocol != NULL) {
- gBS->CloseProtocol(ImageHandle,
+ Status = gBS->CloseProtocol(ImageHandle,
&gEfiShellProtocolGuid,
ImageHandle,
NULL);
- gEfiShellProtocol = NULL;
+ if (!EFI_ERROR (Status)) {
+ gEfiShellProtocol = NULL;
+ }
}
if (gEfiShellParametersProtocol != NULL) {
- gBS->CloseProtocol(ImageHandle,
+ Status = gBS->CloseProtocol(ImageHandle,
&gEfiShellParametersProtocolGuid,
ImageHandle,
NULL);
- gEfiShellParametersProtocol = NULL;
+ if (!EFI_ERROR (Status)) {
+ gEfiShellParametersProtocol = NULL;
+ }
}
- mEfiShellEnvironment2Handle = NULL;
return (EFI_SUCCESS);
}
@@ -365,8 +501,11 @@ ShellLibDestructor (
EFI_STATUS
EFIAPI
ShellInitialize (
+ VOID
)
{
+ EFI_STATUS Status;
+
//
// if auto initialize is not false then skip
//
@@ -377,7 +516,8 @@ ShellInitialize (
//
// deinit the current stuff
//
- ASSERT_EFI_ERROR(ShellLibDestructor(gImageHandle, gST));
+ Status = ShellLibDestructor (gImageHandle, gST);
+ ASSERT_EFI_ERROR (Status);
//
// init the new stuff
@@ -417,20 +557,20 @@ ShellGetFileInfo (
@param[in] FileInfo The information to set.
- @retval EFI_SUCCESS The information was set.
+ @retval EFI_SUCCESS The information was set.
@retval EFI_INVALID_PARAMETER A parameter was out of range or invalid.
@retval EFI_UNSUPPORTED The FileHandle does not support FileInfo.
- @retval EFI_NO_MEDIA The device has no medium.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
@retval EFI_ACCESS_DENIED The file was opened read only.
@retval EFI_VOLUME_FULL The volume is full.
**/
EFI_STATUS
EFIAPI
ShellSetFileInfo (
- IN SHELL_FILE_HANDLE FileHandle,
+ IN SHELL_FILE_HANDLE FileHandle,
IN EFI_FILE_INFO *FileInfo
)
{
@@ -443,47 +583,43 @@ ShellSetFileInfo (
This function opens a file with the open mode according to the file path. The
Attributes is valid only for EFI_FILE_MODE_CREATE.
- @param FilePath on input the device path to the file. On output
+ @param FilePath on input the device path to the file. On output
the remaining device path.
- @param DeviceHandle pointer to the system device handle.
- @param FileHandle pointer to the file handle.
- @param OpenMode the mode to open the file with.
- @param Attributes the file's file attributes.
-
- @retval EFI_SUCCESS The information was set.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_UNSUPPORTED Could not open the file path.
- @retval EFI_NOT_FOUND The specified file could not be found on the
+ @param FileHandle pointer to the file handle.
+ @param OpenMode the mode to open the file with.
+ @param Attributes the file's file attributes.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Could not open the file path.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
device or the file system could not be found on
the device.
- @retval EFI_NO_MEDIA The device has no medium.
- @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
medium is no longer supported.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The file or medium is write protected.
- @retval EFI_ACCESS_DENIED The file was opened read only.
- @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
file.
- @retval EFI_VOLUME_FULL The volume is full.
+ @retval EFI_VOLUME_FULL The volume is full.
**/
EFI_STATUS
EFIAPI
ShellOpenFileByDevicePath(
- IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
- OUT EFI_HANDLE *DeviceHandle,
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
OUT SHELL_FILE_HANDLE *FileHandle,
- IN UINT64 OpenMode,
- IN UINT64 Attributes
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
)
{
CHAR16 *FileName;
EFI_STATUS Status;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
- EFI_FILE_PROTOCOL *Handle1;
- EFI_FILE_PROTOCOL *Handle2;
+ EFI_FILE_PROTOCOL *File;
- if (FilePath == NULL || FileHandle == NULL || DeviceHandle == NULL) {
+ if (FilePath == NULL || FileHandle == NULL) {
return (EFI_INVALID_PARAMETER);
}
@@ -507,88 +643,15 @@ ShellOpenFileByDevicePath(
//
// use old shell method.
//
- Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid,
- FilePath,
- DeviceHandle);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = gBS->OpenProtocol(*DeviceHandle,
- &gEfiSimpleFileSystemProtocolGuid,
- (VOID**)&EfiSimpleFileSystemProtocol,
- gImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
+ Status = EfiOpenFileByDevicePath (FilePath, &File, OpenMode, Attributes);
if (EFI_ERROR (Status)) {
- FileHandle = NULL;
return Status;
}
- //
- // go down directories one node at a time.
- //
- while (!IsDevicePathEnd (*FilePath)) {
- //
- // For file system access each node should be a file path component
- //
- if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
- DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
- ) {
- FileHandle = NULL;
- return (EFI_INVALID_PARAMETER);
- }
- //
- // Open this file path node
- //
- Handle2 = Handle1;
- Handle1 = NULL;
-
- //
- // Try to test opening an existing file
- //
- Status = Handle2->Open (
- Handle2,
- &Handle1,
- ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
- OpenMode &~EFI_FILE_MODE_CREATE,
- 0
- );
-
- //
- // see if the error was that it needs to be created
- //
- if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
- Status = Handle2->Open (
- Handle2,
- &Handle1,
- ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
- OpenMode,
- Attributes
- );
- }
- //
- // Close the last node
- //
- Handle2->Close (Handle2);
-
- if (EFI_ERROR(Status)) {
- return (Status);
- }
-
- //
- // Get the next node
- //
- *FilePath = NextDevicePathNode (*FilePath);
- }
-
//
// This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
//
- *FileHandle = (VOID*)Handle1;
+ *FileHandle = (VOID*)File;
return (EFI_SUCCESS);
}
@@ -601,41 +664,42 @@ ShellOpenFileByDevicePath(
if FileName is NULL then ASSERT()
- @param FileName pointer to file name
- @param FileHandle pointer to the file handle.
- @param OpenMode the mode to open the file with.
- @param Attributes the file's file attributes.
+ @param FileName pointer to file name
+ @param FileHandle pointer to the file handle.
+ @param OpenMode the mode to open the file with.
+ @param Attributes the file's file attributes.
- @retval EFI_SUCCESS The information was set.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_UNSUPPORTED Could not open the file path.
- @retval EFI_NOT_FOUND The specified file could not be found on the
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Could not open the file path.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
device or the file system could not be found
on the device.
- @retval EFI_NO_MEDIA The device has no medium.
- @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
medium is no longer supported.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The file or medium is write protected.
- @retval EFI_ACCESS_DENIED The file was opened read only.
- @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
file.
- @retval EFI_VOLUME_FULL The volume is full.
+ @retval EFI_VOLUME_FULL The volume is full.
**/
EFI_STATUS
EFIAPI
ShellOpenFileByName(
- IN CONST CHAR16 *FileName,
+ IN CONST CHAR16 *FileName,
OUT SHELL_FILE_HANDLE *FileHandle,
IN UINT64 OpenMode,
- IN UINT64 Attributes
+ IN UINT64 Attributes
)
{
- EFI_HANDLE DeviceHandle;
EFI_DEVICE_PATH_PROTOCOL *FilePath;
EFI_STATUS Status;
EFI_FILE_INFO *FileInfo;
+ CHAR16 *FileNameCopy;
+ EFI_STATUS Status2;
//
// ASSERT if FileName is NULL
@@ -647,21 +711,61 @@ ShellOpenFileByName(
}
if (gEfiShellProtocol != NULL) {
- if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE && (Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
- return ShellCreateDirectory(FileName, FileHandle);
+ if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE) {
+
+ //
+ // Create only a directory
+ //
+ if ((Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
+ return ShellCreateDirectory(FileName, FileHandle);
+ }
+
+ //
+ // Create the directory to create the file in
+ //
+ FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);
+ if (FileNameCopy == NULL) {
+ return (EFI_OUT_OF_RESOURCES);
+ }
+ PathCleanUpDirectories (FileNameCopy);
+ if (PathRemoveLastItem (FileNameCopy)) {
+ if (!EFI_ERROR(ShellCreateDirectory (FileNameCopy, FileHandle))) {
+ ShellCloseFile (FileHandle);
+ }
+ }
+ SHELL_FREE_NON_NULL (FileNameCopy);
}
+
//
- // Use UEFI Shell 2.0 method
+ // Use UEFI Shell 2.0 method to create the file
//
Status = gEfiShellProtocol->OpenFileByName(FileName,
FileHandle,
OpenMode);
- if (StrCmp(FileName, L"NUL") != 0 && !EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (mUnicodeCollationProtocol == NULL) {
+ Status = gBS->LocateProtocol (&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&mUnicodeCollationProtocol);
+ if (EFI_ERROR (Status)) {
+ gEfiShellProtocol->CloseFile (*FileHandle);
+ return Status;
+ }
+ }
+
+ if ((mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16*)FileName, L"NUL") != 0) &&
+ (mUnicodeCollationProtocol->StriColl (mUnicodeCollationProtocol, (CHAR16*)FileName, L"NULL") != 0) &&
+ !EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){
FileInfo = FileFunctionMap.GetFileInfo(*FileHandle);
ASSERT(FileInfo != NULL);
FileInfo->Attribute = Attributes;
- Status = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo);
+ Status2 = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo);
FreePool(FileInfo);
+ if (EFI_ERROR (Status2)) {
+ gEfiShellProtocol->CloseFile(*FileHandle);
+ }
+ Status = Status2;
}
return (Status);
}
@@ -674,7 +778,6 @@ ShellOpenFileByName(
FilePath = mEfiShellEnvironment2->NameToPath ((CHAR16*)FileName);
if (FilePath != NULL) {
return (ShellOpenFileByDevicePath(&FilePath,
- &DeviceHandle,
FileHandle,
OpenMode,
Attributes));
@@ -688,25 +791,25 @@ ShellOpenFileByName(
otherwise, the Filehandle is NULL. If the directory already existed, this
function opens the existing directory.
- @param DirectoryName pointer to directory name
- @param FileHandle pointer to the file handle.
+ @param DirectoryName pointer to directory name
+ @param FileHandle pointer to the file handle.
- @retval EFI_SUCCESS The information was set.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_UNSUPPORTED Could not open the file path.
- @retval EFI_NOT_FOUND The specified file could not be found on the
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Could not open the file path.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
device or the file system could not be found
on the device.
- @retval EFI_NO_MEDIA The device has no medium.
- @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
medium is no longer supported.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The file or medium is write protected.
- @retval EFI_ACCESS_DENIED The file was opened read only.
- @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
file.
- @retval EFI_VOLUME_FULL The volume is full.
+ @retval EFI_VOLUME_FULL The volume is full.
@sa ShellOpenFileByName
**/
EFI_STATUS
@@ -754,11 +857,11 @@ ShellCreateDirectory(
the number of bytes written.
@param Buffer the buffer to put read data into.
- @retval EFI_SUCCESS Data was read.
- @retval EFI_NO_MEDIA The device has no media.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
+ @retval EFI_SUCCESS Data was read.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
size.
**/
@@ -789,14 +892,14 @@ ShellReadFile(
the number of bytes written.
@param Buffer the buffer containing data to write is stored.
- @retval EFI_SUCCESS Data was written.
- @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
- @retval EFI_NO_MEDIA The device has no media.
- @retval EFI_DEVICE_ERROR The device reported an error.
- @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
- @retval EFI_WRITE_PROTECTED The device is write-protected.
- @retval EFI_ACCESS_DENIED The file was open for read only.
- @retval EFI_VOLUME_FULL The volume is full.
+ @retval EFI_SUCCESS Data was written.
+ @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
+ @retval EFI_NO_MEDIA The device has no media.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The device is write-protected.
+ @retval EFI_ACCESS_DENIED The file was open for read only.
+ @retval EFI_VOLUME_FULL The volume is full.
**/
EFI_STATUS
EFIAPI
@@ -841,12 +944,12 @@ ShellCloseFile (
@retval EFI_SUCCESS the file was closed sucessfully
@retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
deleted
- @retval INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval INVALID_PARAMETER One of the parameters has an invalid value.
**/
EFI_STATUS
EFIAPI
ShellDeleteFile (
- IN SHELL_FILE_HANDLE *FileHandle
+ IN SHELL_FILE_HANDLE *FileHandle
)
{
return (FileFunctionMap.DeleteFile(*FileHandle));
@@ -874,8 +977,8 @@ ShellDeleteFile (
EFI_STATUS
EFIAPI
ShellSetFilePosition (
- IN SHELL_FILE_HANDLE FileHandle,
- IN UINT64 Position
+ IN SHELL_FILE_HANDLE FileHandle,
+ IN UINT64 Position
)
{
return (FileFunctionMap.SetFilePosition(FileHandle, Position));
@@ -928,15 +1031,19 @@ ShellFlushFile (
return (FileFunctionMap.FlushFile(FileHandle));
}
-/**
- Retrieves the first file from a directory
+/** Retrieve first entry from a directory.
+
+ This function takes an open directory handle and gets information from the
+ first entry in the directory. A buffer is allocated to contain
+ the information and a pointer to the buffer is returned in *Buffer. The
+ caller can use ShellFindNextFile() to get subsequent directory entries.
- This function opens a directory and gets the first file's info in the
- directory. Caller can use ShellFindNextFile() to get other files. When
- complete the caller is responsible for calling FreePool() on Buffer.
+ The buffer will be freed by ShellFindNextFile() when the last directory
+ entry is read. Otherwise, the caller must free the buffer, using FreePool,
+ when finished with it.
- @param DirHandle The file handle of the directory to search
- @param Buffer Pointer to buffer for file's information
+ @param[in] DirHandle The file handle of the directory to search.
+ @param[out] Buffer The pointer to the buffer for the file's information.
@retval EFI_SUCCESS Found the first file.
@retval EFI_NOT_FOUND Cannot find the directory.
@@ -958,19 +1065,18 @@ ShellFindFirstFile (
//
return (FileHandleFindFirstFile(DirHandle, Buffer));
}
-/**
- Retrieves the next file in a directory.
+/** Retrieve next entries from a directory.
- To use this function, caller must call the ShellFindFirstFile() to get the
- first file, and then use this function get other files. This function can be
- called for several times to get each file's information in the directory. If
- the call of ShellFindNextFile() got the last file in the directory, the next
- call of this function has no file to get. *NoFile will be set to TRUE and the
- Buffer memory will be automatically freed.
+ To use this function, the caller must first call the ShellFindFirstFile()
+ function to get the first directory entry. Subsequent directory entries are
+ retrieved by using the ShellFindNextFile() function. This function can
+ be called several times to get each entry from the directory. If the call of
+ ShellFindNextFile() retrieved the last directory entry, the next call of
+ this function will set *NoFile to TRUE and free the buffer.
- @param DirHandle the file handle of the directory
- @param Buffer pointer to buffer for file's information
- @param NoFile pointer to boolean when last file is found
+ @param[in] DirHandle The file handle of the directory.
+ @param[out] Buffer The pointer to buffer for file's information.
+ @param[out] NoFile The pointer to boolean when last file is found.
@retval EFI_SUCCESS Found the next file, or reached last file
@retval EFI_NO_MEDIA The device has no media.
@@ -1137,7 +1243,7 @@ ShellSetEnvironmentVariable (
The CommandLine is executed from the current working directory on the current
device.
- The EnvironmentVariables and Status parameters are ignored in a pre-UEFI Shell 2.0
+ The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0
environment. The values pointed to by the parameters will be unchanged by the
ShellExecute() function. The Output parameter has no effect in a
UEFI Shell 2.0 environment.
@@ -1165,6 +1271,7 @@ ShellExecute (
OUT EFI_STATUS *Status OPTIONAL
)
{
+ EFI_STATUS CmdStatus;
//
// Check for UEFI Shell 2.0 protocols
//
@@ -1183,16 +1290,47 @@ ShellExecute (
//
if (mEfiShellEnvironment2 != NULL) {
//
- // Call EFI Shell version (not using EnvironmentVariables or Status parameters)
- // Due to oddity in the EFI shell we want to dereference the ParentHandle here
+ // Call EFI Shell version.
//
- return (mEfiShellEnvironment2->Execute(*ParentHandle,
+ // Due to an unfixable bug in the EdkShell implementation, we must
+ // dereference "ParentHandle" here:
+ //
+ // 1. The EFI shell installs the EFI_SHELL_ENVIRONMENT2 protocol,
+ // identified by gEfiShellEnvironment2Guid.
+ // 2. The Execute() member function takes "ParentImageHandle" as first
+ // parameter, with type (EFI_HANDLE*).
+ // 3. In the EdkShell implementation, SEnvExecute() implements the
+ // Execute() member function. It passes "ParentImageHandle" correctly to
+ // SEnvDoExecute().
+ // 4. SEnvDoExecute() takes the (EFI_HANDLE*), and passes it directly --
+ // without de-referencing -- to the HandleProtocol() boot service.
+ // 5. But HandleProtocol() takes an EFI_HANDLE.
+ //
+ // Therefore we must
+ // - de-reference "ParentHandle" here, to mask the bug in
+ // SEnvDoExecute(), and
+ // - pass the resultant EFI_HANDLE as an (EFI_HANDLE*).
+ //
+ CmdStatus = (mEfiShellEnvironment2->Execute((EFI_HANDLE *)*ParentHandle,
CommandLine,
Output));
+ //
+ // No Status output parameter so just use the returned status
+ //
+ if (Status != NULL) {
+ *Status = CmdStatus;
+ }
+ //
+ // If there was an error, we can't tell if it was from the command or from
+ // the Execute() function, so we'll just assume the shell ran successfully
+ // and the error came from the command.
+ //
+ return EFI_SUCCESS;
}
return (EFI_UNSUPPORTED);
}
+
/**
Retreives the current directory path
@@ -1200,6 +1338,8 @@ ShellExecute (
name. If the DeviceName is not NULL, it returns the current directory name
on specified drive.
+ Note that the current directory string should exclude the tailing backslash character.
+
@param DeviceName the name of the drive to get directory on
@retval NULL the directory does not exist
@@ -1319,7 +1459,6 @@ typedef struct {
@retval the resultant head of the double linked new format list;
**/
LIST_ENTRY*
-EFIAPI
InternalShellConvertFileListType (
IN LIST_ENTRY *FileList,
IN OUT LIST_ENTRY *ListHead
@@ -1360,8 +1499,9 @@ InternalShellConvertFileListType (
// allocate a new EFI_SHELL_FILE_INFO object
//
NewInfo = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
- ASSERT(NewInfo != NULL);
if (NewInfo == NULL) {
+ ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));
+ ListHead = NULL;
break;
}
@@ -1377,23 +1517,29 @@ InternalShellConvertFileListType (
//
// allocate new space to copy strings and structure
//
- NewInfo->FullName = AllocateZeroPool(StrSize(OldInfo->FullName));
- NewInfo->FileName = AllocateZeroPool(StrSize(OldInfo->FileName));
- NewInfo->Info = AllocateZeroPool((UINTN)OldInfo->Info->Size);
+ NewInfo->FullName = AllocateCopyPool(StrSize(OldInfo->FullName), OldInfo->FullName);
+ NewInfo->FileName = AllocateCopyPool(StrSize(OldInfo->FileName), OldInfo->FileName);
+ NewInfo->Info = AllocateCopyPool((UINTN)OldInfo->Info->Size, OldInfo->Info);
//
// make sure all the memory allocations were sucessful
//
- ASSERT(NewInfo->FullName != NULL);
- ASSERT(NewInfo->FileName != NULL);
- ASSERT(NewInfo->Info != NULL);
+ if (NULL == NewInfo->FullName || NewInfo->FileName == NULL || NewInfo->Info == NULL) {
+ //
+ // Free the partially allocated new node
+ //
+ SHELL_FREE_NON_NULL(NewInfo->FullName);
+ SHELL_FREE_NON_NULL(NewInfo->FileName);
+ SHELL_FREE_NON_NULL(NewInfo->Info);
+ SHELL_FREE_NON_NULL(NewInfo);
- //
- // Copt the strings and structure
- //
- StrCpy(NewInfo->FullName, OldInfo->FullName);
- StrCpy(NewInfo->FileName, OldInfo->FileName);
- gBS->CopyMem (NewInfo->Info, OldInfo->Info, (UINTN)OldInfo->Info->Size);
+ //
+ // Free the previously converted stuff
+ //
+ ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));
+ ListHead = NULL;
+ break;
+ }
//
// add that to the list
@@ -1406,8 +1552,8 @@ InternalShellConvertFileListType (
Opens a group of files based on a path.
This function uses the Arg to open all the matching files. Each matched
- file has a SHELL_FILE_ARG structure to record the file information. These
- structures are placed on the list ListHead. Users can get the SHELL_FILE_ARG
+ file has a SHELL_FILE_INFO structure to record the file information. These
+ structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO
structures from ListHead to access each file. This function supports wildcards
and will process '?' and '*' as such. the list must be freed with a call to
ShellCloseFileMetaArg().
@@ -1435,6 +1581,7 @@ ShellOpenFileMetaArg (
{
EFI_STATUS Status;
LIST_ENTRY mOldStyleFileList;
+ CHAR16 *CleanFilePathStr;
//
// ASSERT that Arg and ListHead are not NULL
@@ -1442,6 +1589,13 @@ ShellOpenFileMetaArg (
ASSERT(Arg != NULL);
ASSERT(ListHead != NULL);
+ CleanFilePathStr = NULL;
+
+ Status = InternalShellStripQuotes (Arg, &CleanFilePathStr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
//
// Check for UEFI Shell 2.0 protocols
//
@@ -1449,11 +1603,12 @@ ShellOpenFileMetaArg (
if (*ListHead == NULL) {
*ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
if (*ListHead == NULL) {
+ FreePool(CleanFilePathStr);
return (EFI_OUT_OF_RESOURCES);
}
InitializeListHead(&((*ListHead)->Link));
}
- Status = gEfiShellProtocol->OpenFileList(Arg,
+ Status = gEfiShellProtocol->OpenFileList(CleanFilePathStr,
OpenMode,
ListHead);
if (EFI_ERROR(Status)) {
@@ -1463,9 +1618,11 @@ ShellOpenFileMetaArg (
}
if (*ListHead != NULL && IsListEmpty(&(*ListHead)->Link)) {
FreePool(*ListHead);
+ FreePool(CleanFilePathStr);
*ListHead = NULL;
return (EFI_NOT_FOUND);
}
+ FreePool(CleanFilePathStr);
return (Status);
}
@@ -1481,15 +1638,17 @@ ShellOpenFileMetaArg (
//
// Get the EFI Shell list of files
//
- Status = mEfiShellEnvironment2->FileMetaArg(Arg, &mOldStyleFileList);
+ Status = mEfiShellEnvironment2->FileMetaArg(CleanFilePathStr, &mOldStyleFileList);
if (EFI_ERROR(Status)) {
*ListHead = NULL;
+ FreePool(CleanFilePathStr);
return (Status);
}
if (*ListHead == NULL) {
*ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
if (*ListHead == NULL) {
+ FreePool(CleanFilePathStr);
return (EFI_OUT_OF_RESOURCES);
}
InitializeListHead(&((*ListHead)->Link));
@@ -1510,9 +1669,11 @@ ShellOpenFileMetaArg (
*ListHead = NULL;
Status = EFI_NOT_FOUND;
}
+ FreePool(CleanFilePathStr);
return (Status);
}
+ FreePool(CleanFilePathStr);
return (EFI_UNSUPPORTED);
}
/**
@@ -1557,6 +1718,7 @@ ShellCloseFileMetaArg (
FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info);
FreePool((EFI_SHELL_FILE_INFO_NO_CONST*)Node);
}
+ SHELL_FREE_NON_NULL(*ListHead);
return EFI_SUCCESS;
}
@@ -1609,15 +1771,15 @@ ShellFindFilePath (
Path = ShellGetEnvironmentVariable(L"cwd");
if (Path != NULL) {
- Size = StrSize(Path);
+ Size = StrSize(Path) + sizeof(CHAR16);
Size += StrSize(FileName);
TestPath = AllocateZeroPool(Size);
- ASSERT(TestPath != NULL);
if (TestPath == NULL) {
return (NULL);
}
- StrCpy(TestPath, Path);
- StrCat(TestPath, FileName);
+ StrCpyS(TestPath, Size/sizeof(CHAR16), Path);
+ StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");
+ StrCatS(TestPath, Size/sizeof(CHAR16), FileName);
Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);
if (!EFI_ERROR(Status)){
if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
@@ -1649,12 +1811,12 @@ ShellFindFilePath (
*TempChar = CHAR_NULL;
}
if (TestPath[StrLen(TestPath)-1] != L'\\') {
- StrCat(TestPath, L"\\");
+ StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");
}
if (FileName[0] == L'\\') {
FileName++;
}
- StrCat(TestPath, FileName);
+ StrCatS(TestPath, Size/sizeof(CHAR16), FileName);
if (StrStr(Walker, L";") != NULL) {
Walker = StrStr(Walker, L";") + 1;
} else {
@@ -1719,14 +1881,13 @@ ShellFindFilePathEx (
Size = StrSize(FileName);
Size += StrSize(FileExtension);
TestPath = AllocateZeroPool(Size);
- ASSERT(TestPath != NULL);
if (TestPath == NULL) {
return (NULL);
}
for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension; TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1){
- StrCpy(TestPath, FileName);
+ StrCpyS(TestPath, Size/sizeof(CHAR16), FileName);
if (ExtensionWalker != NULL) {
- StrCat(TestPath, ExtensionWalker);
+ StrCatS(TestPath, Size/sizeof(CHAR16), ExtensionWalker);
}
TempChar = StrStr(TestPath, L";");
if (TempChar != NULL) {
@@ -1767,7 +1928,6 @@ typedef struct {
@retval FALSE the Parameter was not found. Type is not valid.
**/
BOOLEAN
-EFIAPI
InternalIsOnCheckList (
IN CONST CHAR16 *Name,
IN CONST SHELL_PARAM_ITEM *CheckList,
@@ -1802,7 +1962,7 @@ InternalIsOnCheckList (
// If the Type is TypeStart only check the first characters of the passed in param
// If it matches set the type and return TRUE
//
- if (TempListItem->Type == TypeStart) {
+ if (TempListItem->Type == TypeStart) {
if (StrnCmp(Name, TempListItem->Name, StrLen(TempListItem->Name)) == 0) {
*Type = TempListItem->Type;
return (TRUE);
@@ -1830,15 +1990,16 @@ InternalIsOnCheckList (
@param[in] Name pointer to Name of parameter found
@param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.
+ @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
@retval TRUE the Parameter is a flag.
@retval FALSE the Parameter not a flag.
**/
BOOLEAN
-EFIAPI
InternalIsFlag (
IN CONST CHAR16 *Name,
- IN BOOLEAN AlwaysAllowNumbers
+ IN CONST BOOLEAN AlwaysAllowNumbers,
+ IN CONST BOOLEAN TimeNumbers
)
{
//
@@ -1849,7 +2010,7 @@ InternalIsFlag (
//
// If we accept numbers then dont return TRUE. (they will be values)
//
- if (((Name[0] == L'-' || Name[0] == L'+') && ShellIsHexaDecimalDigitCharacter(Name[1])) && AlwaysAllowNumbers) {
+ if (((Name[0] == L'-' || Name[0] == L'+') && InternalShellIsHexOrDecimalNumber(Name+1, FALSE, FALSE, TimeNumbers)) && AlwaysAllowNumbers) {
return (FALSE);
}
@@ -1891,7 +2052,6 @@ InternalIsFlag (
ProblemParam if provided.
**/
EFI_STATUS
-EFIAPI
InternalCommandLineParse (
IN CONST SHELL_PARAM_ITEM *CheckList,
OUT LIST_ENTRY **CheckPackage,
@@ -1909,6 +2069,8 @@ InternalCommandLineParse (
UINTN ValueSize;
UINTN Count;
CONST CHAR16 *TempPointer;
+ UINTN CurrentValueSize;
+ CHAR16 *NewValue;
CurrentItemPackage = NULL;
GetItemValue = 0;
@@ -1934,8 +2096,9 @@ InternalCommandLineParse (
//
*CheckPackage = (LIST_ENTRY*)AllocateZeroPool(sizeof(LIST_ENTRY));
if (*CheckPackage == NULL) {
- return EFI_OUT_OF_RESOURCES;
+ return (EFI_OUT_OF_RESOURCES);
}
+
InitializeListHead(*CheckPackage);
//
@@ -1958,10 +2121,17 @@ InternalCommandLineParse (
// this is a flag
//
CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));
- ASSERT(CurrentItemPackage != NULL);
- CurrentItemPackage->Name = AllocateZeroPool(StrSize(Argv[LoopCounter]));
- ASSERT(CurrentItemPackage->Name != NULL);
- StrCpy(CurrentItemPackage->Name, Argv[LoopCounter]);
+ if (CurrentItemPackage == NULL) {
+ ShellCommandLineFreeVarList(*CheckPackage);
+ *CheckPackage = NULL;
+ return (EFI_OUT_OF_RESOURCES);
+ }
+ CurrentItemPackage->Name = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);
+ if (CurrentItemPackage->Name == NULL) {
+ ShellCommandLineFreeVarList(*CheckPackage);
+ *CheckPackage = NULL;
+ return (EFI_OUT_OF_RESOURCES);
+ }
CurrentItemPackage->Type = CurrentItemType;
CurrentItemPackage->OriginalPosition = (UINTN)(-1);
CurrentItemPackage->Value = NULL;
@@ -1974,6 +2144,7 @@ InternalCommandLineParse (
// possibly trigger the next loop(s) to populate the value of this item
//
case TypeValue:
+ case TypeTimeValue:
GetItemValue = 1;
ValueSize = 0;
break;
@@ -1993,43 +2164,67 @@ InternalCommandLineParse (
ASSERT(GetItemValue == 0);
break;
}
- } else if (GetItemValue != 0 && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers)) {
- ASSERT(CurrentItemPackage != NULL);
+ } else if (GetItemValue != 0 && CurrentItemPackage != NULL && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, (BOOLEAN)(CurrentItemPackage->Type == TypeTimeValue))) {
//
// get the item VALUE for a previous flag
//
- CurrentItemPackage->Value = ReallocatePool(ValueSize, ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16), CurrentItemPackage->Value);
- ASSERT(CurrentItemPackage->Value != NULL);
+ CurrentValueSize = ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16);
+ NewValue = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);
+ if (NewValue == NULL) {
+ SHELL_FREE_NON_NULL (CurrentItemPackage->Value);
+ SHELL_FREE_NON_NULL (CurrentItemPackage);
+ ShellCommandLineFreeVarList (*CheckPackage);
+ *CheckPackage = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CurrentItemPackage->Value = NewValue;
if (ValueSize == 0) {
- StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);
+ StrCpyS( CurrentItemPackage->Value,
+ CurrentValueSize/sizeof(CHAR16),
+ Argv[LoopCounter]
+ );
} else {
- StrCat(CurrentItemPackage->Value, L" ");
- StrCat(CurrentItemPackage->Value, Argv[LoopCounter]);
+ StrCatS( CurrentItemPackage->Value,
+ CurrentValueSize/sizeof(CHAR16),
+ L" "
+ );
+ StrCatS( CurrentItemPackage->Value,
+ CurrentValueSize/sizeof(CHAR16),
+ Argv[LoopCounter]
+ );
}
ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);
+
GetItemValue--;
if (GetItemValue == 0) {
InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
}
- } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers) ){ //|| ProblemParam == NULL) {
+ } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, FALSE)){
//
// add this one as a non-flag
//
TempPointer = Argv[LoopCounter];
- if ((*TempPointer == L'^' && *(TempPointer+1) == L'-')
+ if ((*TempPointer == L'^' && *(TempPointer+1) == L'-')
|| (*TempPointer == L'^' && *(TempPointer+1) == L'/')
|| (*TempPointer == L'^' && *(TempPointer+1) == L'+')
){
TempPointer++;
}
CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));
- ASSERT(CurrentItemPackage != NULL);
+ if (CurrentItemPackage == NULL) {
+ ShellCommandLineFreeVarList(*CheckPackage);
+ *CheckPackage = NULL;
+ return (EFI_OUT_OF_RESOURCES);
+ }
CurrentItemPackage->Name = NULL;
CurrentItemPackage->Type = TypePosition;
- CurrentItemPackage->Value = AllocateZeroPool(StrSize(TempPointer));
- ASSERT(CurrentItemPackage->Value != NULL);
- StrCpy(CurrentItemPackage->Value, TempPointer);
+ CurrentItemPackage->Value = AllocateCopyPool(StrSize(TempPointer), TempPointer);
+ if (CurrentItemPackage->Value == NULL) {
+ ShellCommandLineFreeVarList(*CheckPackage);
+ *CheckPackage = NULL;
+ return (EFI_OUT_OF_RESOURCES);
+ }
CurrentItemPackage->OriginalPosition = Count++;
InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
} else {
@@ -2037,9 +2232,7 @@ InternalCommandLineParse (
// this was a non-recognised flag... error!
//
if (ProblemParam != NULL) {
- *ProblemParam = AllocateZeroPool(StrSize(Argv[LoopCounter]));
- ASSERT(*ProblemParam != NULL);
- StrCpy(*ProblemParam, Argv[LoopCounter]);
+ *ProblemParam = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);
}
ShellCommandLineFreeVarList(*CheckPackage);
*CheckPackage = NULL;
@@ -2213,14 +2406,9 @@ ShellCommandLineGetFlag (
CHAR16 *TempString;
//
- // ASSERT that both CheckPackage and KeyString aren't NULL
+ // return FALSE for no package or KeyString is NULL
//
- ASSERT(KeyString != NULL);
-
- //
- // return FALSE for no package
- //
- if (CheckPackage == NULL) {
+ if (CheckPackage == NULL || KeyString == NULL) {
return (FALSE);
}
@@ -2282,9 +2470,9 @@ ShellCommandLineGetValue (
CHAR16 *TempString;
//
- // check for CheckPackage == NULL
+ // return NULL for no package or KeyString is NULL
//
- if (CheckPackage == NULL) {
+ if (CheckPackage == NULL || KeyString == NULL) {
return (NULL);
}
@@ -2403,7 +2591,7 @@ ShellCommandLineGetCount(
}
/**
- Determins if a parameter is duplicated.
+ Determines if a parameter is duplicated.
If Param is not NULL then it will point to a callee allocated string buffer
with the parameter value if a duplicate is found.
@@ -2504,12 +2692,14 @@ ShellCopySearchAndReplace(
Replace = StrnCatGrow(&Replace, NULL, ReplaceWith, 0);
} else {
Replace = AllocateZeroPool(StrSize(ReplaceWith) + 2*sizeof(CHAR16));
- UnicodeSPrint(Replace, StrSize(ReplaceWith) + 2*sizeof(CHAR16), L"\"%s\"", ReplaceWith);
+ if (Replace != NULL) {
+ UnicodeSPrint(Replace, StrSize(ReplaceWith) + 2*sizeof(CHAR16), L"\"%s\"", ReplaceWith);
+ }
}
if (Replace == NULL) {
return (EFI_OUT_OF_RESOURCES);
}
- NewString = SetMem16(NewString, NewSize, CHAR_NULL);
+ NewString = ZeroMem(NewString, NewSize);
while (*SourceString != CHAR_NULL) {
//
// if we find the FindTarget and either Skip == FALSE or Skip and we
@@ -2524,14 +2714,14 @@ ShellCopySearchAndReplace(
FreePool(Replace);
return (EFI_BUFFER_TOO_SMALL);
}
- StrCat(NewString, Replace);
+ StrCatS(NewString, NewSize/sizeof(CHAR16), Replace);
} else {
Size = StrSize(NewString);
if (Size + sizeof(CHAR16) > NewSize) {
FreePool(Replace);
return (EFI_BUFFER_TOO_SMALL);
}
- StrnCat(NewString, SourceString, 1);
+ StrnCatS(NewString, NewSize/sizeof(CHAR16), SourceString, 1);
SourceString++;
}
}
@@ -2550,7 +2740,6 @@ ShellCopySearchAndReplace(
@retval !EFI_SUCCESS The operation failed.
**/
EFI_STATUS
-EFIAPI
InternalPrintTo (
IN CONST CHAR16 *String
)
@@ -2564,10 +2753,12 @@ InternalPrintTo (
return (gEfiShellProtocol->WriteFile(gEfiShellParametersProtocol->StdOut, &Size, (VOID*)String));
}
if (mEfiShellInterface != NULL) {
+ if (mEfiShellInterface->RedirArgc == 0) {
//
// Divide in half for old shell. Must be string length not size.
- //
- Size /= 2;
+ //
+ Size /=2; // Divide in half only when no redirection.
+ }
return (mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut, &Size, (VOID*)String));
}
ASSERT(FALSE);
@@ -2604,7 +2795,6 @@ InternalPrintTo (
@return EFI_DEVICE_ERROR The console device reported an error.
**/
EFI_STATUS
-EFIAPI
InternalShellPrintWorker(
IN INT32 Col OPTIONAL,
IN INT32 Row OPTIONAL,
@@ -2677,7 +2867,12 @@ InternalShellPrintWorker(
// update the attribute
//
if (ResumeLocation != NULL) {
- if (*(ResumeLocation-1) == L'^') {
+ if ((ResumeLocation != mPostReplaceFormat2) && (*(ResumeLocation-1) == L'^')) {
+ //
+ // Move cursor back 1 position to overwrite the ^
+ //
+ gST->ConOut->SetCursorPosition(gST->ConOut, gST->ConOut->Mode->CursorColumn - 1, gST->ConOut->Mode->CursorRow);
+
//
// Print a simple '%' symbol
//
@@ -2695,10 +2890,10 @@ InternalShellPrintWorker(
gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
break;
case (L'B'):
- gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_BLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
+ gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTBLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
break;
case (L'V'):
- gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
+ gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTGREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
break;
default:
//
@@ -2820,7 +3015,7 @@ ShellPrintHiiEx(
IN INT32 Row OPTIONAL,
IN CONST CHAR8 *Language OPTIONAL,
IN CONST EFI_STRING_ID HiiFormatStringId,
- IN CONST EFI_HANDLE HiiFormatHandle,
+ IN CONST EFI_HII_HANDLE HiiFormatHandle,
...
)
{
@@ -2828,13 +3023,14 @@ ShellPrintHiiEx(
CHAR16 *HiiFormatString;
EFI_STATUS RetVal;
+ RetVal = EFI_DEVICE_ERROR;
+
VA_START (Marker, HiiFormatHandle);
HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, Language);
- ASSERT(HiiFormatString != NULL);
-
- RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker);
-
- SHELL_FREE_NON_NULL(HiiFormatString);
+ if (HiiFormatString != NULL) {
+ RetVal = InternalShellPrintWorker (Col, Row, HiiFormatString, Marker);
+ SHELL_FREE_NON_NULL (HiiFormatString);
+ }
VA_END(Marker);
return (RetVal);
@@ -2845,9 +3041,10 @@ ShellPrintHiiEx(
@param[in] DirName Path to directory to test.
- @retval EFI_SUCCESS The Path represents a directory
- @retval EFI_NOT_FOUND The Path does not represent a directory
- @return other The path failed to open
+ @retval EFI_SUCCESS The Path represents a directory
+ @retval EFI_NOT_FOUND The Path does not represent a directory
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+ @return The path failed to open
**/
EFI_STATUS
EFIAPI
@@ -2872,6 +3069,10 @@ ShellIsDirectory(
//
if (gEfiShellProtocol != NULL) {
TempLocation = StrnCatGrow(&TempLocation, NULL, DirName, 0);
+ if (TempLocation == NULL) {
+ ShellCloseFile(&Handle);
+ return (EFI_OUT_OF_RESOURCES);
+ }
TempLocation2 = StrStr(TempLocation, L":");
if (TempLocation2 != NULL && StrLen(StrStr(TempLocation, L":")) == 2) {
*(TempLocation2+1) = CHAR_NULL;
@@ -2971,9 +3172,35 @@ ShellIsFileInPath(
return (Status);
}
+/**
+ Function return the number converted from a hex representation of a number.
+
+ Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid
+ result. Use ShellConvertStringToUint64 instead.
+
+ @param[in] String String representation of a number.
+
+ @return The unsigned integer result of the conversion.
+ @retval (UINTN)(-1) An error occured.
+**/
+UINTN
+EFIAPI
+ShellHexStrToUintn(
+ IN CONST CHAR16 *String
+ )
+{
+ UINT64 RetVal;
+
+ if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, TRUE, TRUE))) {
+ return ((UINTN)RetVal);
+ }
+
+ return ((UINTN)(-1));
+}
+
/**
Function to determine whether a string is decimal or hex representation of a number
- and return the number converted from the string.
+ and return the number converted from the string. Spaces are always skipped.
@param[in] String String representation of a number
@@ -2991,7 +3218,7 @@ ShellStrToUintn(
Hex = FALSE;
- if (!InternalShellIsHexOrDecimalNumber(String, Hex, TRUE)) {
+ if (!InternalShellIsHexOrDecimalNumber(String, Hex, TRUE, FALSE)) {
Hex = TRUE;
}
@@ -3088,15 +3315,16 @@ StrnCatGrow (
//
if (CurrentSize != NULL) {
NewSize = *CurrentSize;
- while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {
- NewSize += 2 * Count * sizeof(CHAR16);
+ if (NewSize < DestinationStartSize + (Count * sizeof(CHAR16))) {
+ while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {
+ NewSize += 2 * Count * sizeof(CHAR16);
+ }
+ *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);
+ *CurrentSize = NewSize;
}
- *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);
- ASSERT(*Destination != NULL);
- *CurrentSize = NewSize;
} else {
- *Destination = AllocateZeroPool((Count+1)*sizeof(CHAR16));
- ASSERT(*Destination != NULL);
+ NewSize = (Count+1)*sizeof(CHAR16);
+ *Destination = AllocateZeroPool(NewSize);
}
//
@@ -3105,14 +3333,16 @@ StrnCatGrow (
if (*Destination == NULL) {
return (NULL);
}
- return StrnCat(*Destination, Source, Count);
+
+ StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, Count);
+ return *Destination;
}
/**
Prompt the user and return the resultant answer to the requestor.
This function will display the requested question on the shell prompt and then
- wait for an apropriate answer to be input from the console.
+ wait for an appropriate answer to be input from the console.
if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue
or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.
@@ -3154,6 +3384,9 @@ ShellPromptForResponse (
if (Type != ShellPromptResponseTypeFreeform) {
Resp = (SHELL_PROMPT_RESPONSE*)AllocateZeroPool(sizeof(SHELL_PROMPT_RESPONSE));
if (Resp == NULL) {
+ if (Response != NULL) {
+ *Response = NULL;
+ }
return (EFI_OUT_OF_RESOURCES);
}
}
@@ -3168,7 +3401,9 @@ ShellPromptForResponse (
//
gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
if (Key.UnicodeChar == L'Q' || Key.UnicodeChar ==L'q') {
*Resp = ShellPromptResponseQuit;
@@ -3185,9 +3420,15 @@ ShellPromptForResponse (
//
*Resp = ShellPromptResponseMax;
while (*Resp == ShellPromptResponseMax) {
+ if (ShellGetExecutionBreakFlag()) {
+ Status = EFI_ABORTED;
+ break;
+ }
gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
switch (Key.UnicodeChar) {
case L'Y':
@@ -3204,7 +3445,8 @@ ShellPromptForResponse (
break;
}
}
- break; case ShellPromptResponseTypeYesNoAllCancel:
+ break;
+ case ShellPromptResponseTypeYesNoAllCancel:
if (Prompt != NULL) {
ShellPrintEx(-1, -1, L"%s", Prompt);
}
@@ -3213,10 +3455,20 @@ ShellPromptForResponse (
//
*Resp = ShellPromptResponseMax;
while (*Resp == ShellPromptResponseMax) {
+ if (ShellGetExecutionBreakFlag()) {
+ Status = EFI_ABORTED;
+ break;
+ }
gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- ASSERT_EFI_ERROR(Status);
- ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+
+ if (Key.UnicodeChar <= 127 && Key.UnicodeChar >= 32) {
+ ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);
+ }
+
switch (Key.UnicodeChar) {
case L'Y':
case L'y':
@@ -3247,10 +3499,16 @@ ShellPromptForResponse (
//
*Resp = ShellPromptResponseMax;
while (*Resp == ShellPromptResponseMax) {
+ if (ShellGetExecutionBreakFlag()) {
+ Status = EFI_ABORTED;
+ break;
+ }
gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
if (Type == ShellPromptResponseTypeEnterContinue) {
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
*Resp = ShellPromptResponseContinue;
@@ -3274,9 +3532,15 @@ ShellPromptForResponse (
//
*Resp = ShellPromptResponseMax;
while (*Resp == ShellPromptResponseMax) {
+ if (ShellGetExecutionBreakFlag()) {
+ Status = EFI_ABORTED;
+ break;
+ }
gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
switch (Key.UnicodeChar) {
case L'Y':
@@ -3295,9 +3559,15 @@ ShellPromptForResponse (
ShellPrintEx(-1, -1, L"%s", Prompt);
}
while(1) {
+ if (ShellGetExecutionBreakFlag()) {
+ Status = EFI_ABORTED;
+ break;
+ }
gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
- ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
break;
@@ -3308,6 +3578,7 @@ ShellPromptForResponse (
break;
//
// This is the location to add new prompt types.
+ // If your new type loops remember to add ExecutionBreak support.
//
default:
ASSERT(FALSE);
@@ -3318,6 +3589,8 @@ ShellPromptForResponse (
*Response = Resp;
} else if (Buffer != NULL) {
*Response = Buffer;
+ } else {
+ *Response = NULL;
}
} else {
if (Resp != NULL) {
@@ -3354,7 +3627,7 @@ EFIAPI
ShellPromptForResponseHii (
IN SHELL_PROMPT_REQUEST_TYPE Type,
IN CONST EFI_STRING_ID HiiFormatStringId,
- IN CONST EFI_HANDLE HiiFormatHandle,
+ IN CONST EFI_HII_HANDLE HiiFormatHandle,
IN OUT VOID **Response
)
{
@@ -3375,42 +3648,50 @@ ShellPromptForResponseHii (
@param[in] String The string to evaluate.
@param[in] ForceHex TRUE - always assume hex.
@param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
+ @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
@retval TRUE It is all numeric (dec/hex) characters.
@retval FALSE There is a non-numeric character.
**/
BOOLEAN
-EFIAPI
InternalShellIsHexOrDecimalNumber (
IN CONST CHAR16 *String,
IN CONST BOOLEAN ForceHex,
- IN CONST BOOLEAN StopAtSpace
+ IN CONST BOOLEAN StopAtSpace,
+ IN CONST BOOLEAN TimeNumbers
)
{
BOOLEAN Hex;
+ BOOLEAN LeadingZero;
+
+ if (String == NULL) {
+ return FALSE;
+ }
//
// chop off a single negative sign
//
- if (String != NULL && *String == L'-') {
+ if (*String == L'-') {
String++;
}
-
- if (String == NULL) {
- return (FALSE);
+
+ if (*String == CHAR_NULL) {
+ return FALSE;
}
//
// chop leading zeroes
//
- while(String != NULL && *String == L'0'){
+ LeadingZero = FALSE;
+ while(*String == L'0'){
String++;
+ LeadingZero = TRUE;
}
//
// allow '0x' or '0X', but not 'x' or 'X'
//
- if (String != NULL && (*String == L'x' || *String == L'X')) {
- if (*(String-1) != L'0') {
+ if (*String == L'x' || *String == L'X') {
+ if (!LeadingZero) {
//
// we got an x without a preceeding 0
//
@@ -3427,7 +3708,10 @@ InternalShellIsHexOrDecimalNumber (
//
// loop through the remaining characters and use the lib function
//
- for ( ; String != NULL && *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){
+ for ( ; *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){
+ if (TimeNumbers && (String[0] == L':')) {
+ continue;
+ }
if (Hex) {
if (!ShellIsHexaDecimalDigitCharacter(*String)) {
return (FALSE);
@@ -3473,40 +3757,12 @@ ShellFileExists(
return (EFI_SUCCESS);
}
-/**
- Convert a Unicode character to upper case only if
- it maps to a valid small-case ASCII character.
-
- This internal function only deal with Unicode character
- which maps to a valid small-case ASCII character, i.e.
- L'a' to L'z'. For other Unicode character, the input character
- is returned directly.
-
- @param Char The character to convert.
-
- @retval LowerCharacter If the Char is with range L'a' to L'z'.
- @retval Unchanged Otherwise.
-
-**/
-CHAR16
-EFIAPI
-InternalShellCharToUpper (
- IN CHAR16 Char
- )
-{
- if (Char >= L'a' && Char <= L'z') {
- return (CHAR16) (Char - (L'a' - L'A'));
- }
-
- return Char;
-}
-
/**
Convert a Unicode character to numerical value.
This internal function only deal with Unicode character
which maps to a valid hexadecimal ASII character, i.e.
- L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
+ L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
Unicode character, the value returned does not make sense.
@param Char The character to convert.
@@ -3515,7 +3771,6 @@ InternalShellCharToUpper (
**/
UINTN
-EFIAPI
InternalShellHexCharToUintn (
IN CHAR16 Char
)
@@ -3524,13 +3779,13 @@ InternalShellHexCharToUintn (
return Char - L'0';
}
- return (UINTN) (10 + InternalShellCharToUpper (Char) - L'A');
+ return (10 + CharToUpper (Char) - L'A');
}
/**
Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
- This function returns a value of type UINTN by interpreting the contents
+ This function returns a value of type UINT64 by interpreting the contents
of the Unicode string specified by String as a hexadecimal number.
The format of the input Unicode string String is:
@@ -3558,7 +3813,6 @@ InternalShellHexCharToUintn (
@retval EFI_DEVICE_ERROR An overflow occured.
**/
EFI_STATUS
-EFIAPI
InternalShellStrHexToUint64 (
IN CONST CHAR16 *String,
OUT UINT64 *Value,
@@ -3570,9 +3824,9 @@ InternalShellStrHexToUint64 (
if (String == NULL || StrSize(String) == 0 || Value == NULL) {
return (EFI_INVALID_PARAMETER);
}
-
+
//
- // Ignore the pad spaces (space or tab)
+ // Ignore the pad spaces (space or tab)
//
while ((*String == L' ') || (*String == L'\t')) {
String++;
@@ -3585,7 +3839,7 @@ InternalShellStrHexToUint64 (
String++;
}
- if (InternalShellCharToUpper (*String) == L'X') {
+ if (CharToUpper (*String) == L'X') {
if (*(String - 1) != L'0') {
return 0;
}
@@ -3596,18 +3850,18 @@ InternalShellStrHexToUint64 (
}
Result = 0;
-
+
//
- // Skip spaces if requested
+ // there is a space where there should't be
//
- while (StopAtSpace && *String == L' ') {
- String++;
+ if (*String == L' ') {
+ return (EFI_INVALID_PARAMETER);
}
-
+
while (ShellIsHexaDecimalDigitCharacter (*String)) {
//
- // If the Hex Number represented by String overflows according
- // to the range defined by UINTN, then ASSERT().
+ // If the Hex Number represented by String overflows according
+ // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
//
if (!(Result <= (RShiftU64((((UINT64) ~0) - InternalShellHexCharToUintn (*String)), 4)))) {
// if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {
@@ -3619,10 +3873,10 @@ InternalShellStrHexToUint64 (
String++;
//
- // Skip spaces if requested
+ // stop at spaces if requested
//
- while (StopAtSpace && *String == L' ') {
- String++;
+ if (StopAtSpace && *String == L' ') {
+ break;
}
}
@@ -3660,7 +3914,6 @@ InternalShellStrHexToUint64 (
@retval EFI_DEVICE_ERROR An overflow occured.
**/
EFI_STATUS
-EFIAPI
InternalShellStrDecimalToUint64 (
IN CONST CHAR16 *String,
OUT UINT64 *Value,
@@ -3690,17 +3943,20 @@ InternalShellStrDecimalToUint64 (
Result = 0;
//
- // Skip spaces if requested
+ // Stop upon space if requested
+ // (if the whole value was 0)
//
- while (StopAtSpace && *String == L' ') {
- String++;
+ if (StopAtSpace && *String == L' ') {
+ *Value = Result;
+ return (EFI_SUCCESS);
}
+
while (ShellIsDecimalDigitCharacter (*String)) {
//
- // If the number represented by String overflows according
- // to the range defined by UINT64, then ASSERT().
+ // If the number represented by String overflows according
+ // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
//
-
+
if (!(Result <= (DivU64x32((((UINT64) ~0) - (*String - L'0')),10)))) {
return (EFI_DEVICE_ERROR);
}
@@ -3717,7 +3973,7 @@ InternalShellStrDecimalToUint64 (
}
*Value = Result;
-
+
return (EFI_SUCCESS);
}
@@ -3730,7 +3986,7 @@ InternalShellStrDecimalToUint64 (
@param[out] Value Upon a successful return the value of the conversion.
@param[in] ForceHex TRUE - always assume hex.
@param[in] StopAtSpace FALSE to skip spaces.
-
+
@retval EFI_SUCCESS The conversion was successful.
@retval EFI_INVALID_PARAMETER String contained an invalid character.
@retval EFI_NOT_FOUND String was a number, but Value was NULL.
@@ -3751,10 +4007,10 @@ ShellConvertStringToUint64(
Hex = ForceHex;
- if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace)) {
+ if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {
if (!Hex) {
Hex = TRUE;
- if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace)) {
+ if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {
return (EFI_INVALID_PARAMETER);
}
} else {
@@ -3770,9 +4026,9 @@ ShellConvertStringToUint64(
//
// make sure we have something left that is numeric.
//
- if (Walker == NULL || *Walker == CHAR_NULL || !InternalShellIsHexOrDecimalNumber(Walker, Hex, StopAtSpace)) {
+ if (Walker == NULL || *Walker == CHAR_NULL || !InternalShellIsHexOrDecimalNumber(Walker, Hex, StopAtSpace, FALSE)) {
return (EFI_INVALID_PARAMETER);
- }
+ }
//
// do the conversion.
@@ -3831,7 +4087,8 @@ ShellIsHexOrDecimalNumber (
@param[in, out] Ascii Boolean value for indicating whether the file is
Ascii (TRUE) or UCS2 (FALSE).
- @return The line of text from the file.
+ @return The line of text from the file.
+ @retval NULL There was not enough memory available.
@sa ShellFileHandleReadLine
**/
@@ -3852,9 +4109,15 @@ ShellFileHandleReturnLine(
Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
if (Status == EFI_BUFFER_TOO_SMALL) {
RetVal = AllocateZeroPool(Size);
+ if (RetVal == NULL) {
+ return (NULL);
+ }
Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
+
+ }
+ if (Status == EFI_END_OF_FILE && RetVal != NULL && *RetVal != CHAR_NULL) {
+ Status = EFI_SUCCESS;
}
- ASSERT_EFI_ERROR(Status);
if (EFI_ERROR(Status) && (RetVal != NULL)) {
FreePool(RetVal);
RetVal = NULL;
@@ -3868,9 +4131,20 @@ ShellFileHandleReturnLine(
If the position upon start is 0, then the Ascii Boolean will be set. This should be
maintained and not changed for all operations with the same file.
+ NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ
+ IS IN ASCII FORMAT.
+
@param[in] Handle SHELL_FILE_HANDLE to read from.
- @param[in, out] Buffer The pointer to buffer to read into.
- @param[in, out] Size The pointer to number of bytes in Buffer.
+ @param[in, out] Buffer The pointer to buffer to read into. If this function
+ returns EFI_SUCCESS, then on output Buffer will
+ contain a UCS2 string, even if the file being
+ read is ASCII.
+ @param[in, out] Size On input, pointer to number of bytes in Buffer.
+ On output, unchanged unless Buffer is too small
+ to contain the next line of the file. In that
+ case Size is set to the number of bytes needed
+ to hold the next line of the file (as a UCS2
+ string, even if it is an ASCII file).
@param[in] Truncate If the buffer is large enough, this has no effect.
If the buffer is is too small and Truncate is TRUE,
the line will be truncated.
@@ -3882,6 +4156,7 @@ ShellFileHandleReturnLine(
@retval EFI_SUCCESS The operation was successful. The line is stored in
Buffer.
+ @retval EFI_END_OF_FILE There are no more lines in the file.
@retval EFI_INVALID_PARAMETER Handle was NULL.
@retval EFI_INVALID_PARAMETER Size was NULL.
@retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.
@@ -3927,19 +4202,22 @@ ShellFileHandleReadLine(
}
}
+ if (*Ascii) {
+ CharSize = sizeof(CHAR8);
+ } else {
+ CharSize = sizeof(CHAR16);
+ }
for (CountSoFar = 0;;CountSoFar++){
CharBuffer = 0;
- if (*Ascii) {
- CharSize = sizeof(CHAR8);
- } else {
- CharSize = sizeof(CHAR16);
- }
Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
if ( EFI_ERROR(Status)
|| CharSize == 0
|| (CharBuffer == L'\n' && !(*Ascii))
|| (CharBuffer == '\n' && *Ascii)
){
+ if (CharSize == 0) {
+ Status = EFI_END_OF_FILE;
+ }
break;
}
//
@@ -3970,3 +4248,145 @@ ShellFileHandleReadLine(
return (Status);
}
+
+/**
+ Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function.
+
+ @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed.
+ @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
+ @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints
+ the help content only.
+ @retval EFI_DEVICE_ERROR The help data format was incorrect.
+ @retval EFI_NOT_FOUND The help data could not be found.
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+EFIAPI
+ShellPrintHelp (
+ IN CONST CHAR16 *CommandToGetHelpOn,
+ IN CONST CHAR16 *SectionToGetHelpOn,
+ IN BOOLEAN PrintCommandText
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *OutText;
+
+ OutText = NULL;
+
+ //
+ // Get the string to print based
+ //
+ Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);
+
+ //
+ // make sure we got a valid string
+ //
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+ if (OutText == NULL || StrLen(OutText) == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Chop off trailing stuff we dont need
+ //
+ while (OutText[StrLen(OutText)-1] == L'\r' || OutText[StrLen(OutText)-1] == L'\n' || OutText[StrLen(OutText)-1] == L' ') {
+ OutText[StrLen(OutText)-1] = CHAR_NULL;
+ }
+
+ //
+ // Print this out to the console
+ //
+ if (PrintCommandText) {
+ ShellPrintEx(-1, -1, L"%H%-14s%N- %s\r\n", CommandToGetHelpOn, OutText);
+ } else {
+ ShellPrintEx(-1, -1, L"%N%s\r\n", OutText);
+ }
+
+ SHELL_FREE_NON_NULL(OutText);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Function to delete a file by name
+
+ @param[in] FileName Pointer to file name to delete.
+
+ @retval EFI_SUCCESS the file was deleted sucessfully
+ @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
+ deleted
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
+ device or the file system could not be found
+ on the device.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ medium is no longer supported.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ file.
+ @retval other The file failed to open
+**/
+EFI_STATUS
+EFIAPI
+ShellDeleteFileByName(
+ IN CONST CHAR16 *FileName
+ )
+{
+ EFI_STATUS Status;
+ SHELL_FILE_HANDLE FileHandle;
+
+ Status = ShellFileExists(FileName);
+
+ if (Status == EFI_SUCCESS){
+ Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0x0);
+ if (Status == EFI_SUCCESS){
+ Status = ShellDeleteFile(&FileHandle);
+ }
+ }
+
+ return(Status);
+
+}
+
+/**
+ Cleans off all the quotes in the string.
+
+ @param[in] OriginalString pointer to the string to be cleaned.
+ @param[out] CleanString The new string with all quotes removed.
+ Memory allocated in the function and free
+ by caller.
+
+ @retval EFI_SUCCESS The operation was successful.
+**/
+EFI_STATUS
+InternalShellStripQuotes (
+ IN CONST CHAR16 *OriginalString,
+ OUT CHAR16 **CleanString
+ )
+{
+ CHAR16 *Walker;
+
+ if (OriginalString == NULL || CleanString == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);
+ if (*CleanString == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {
+ if (*Walker == L'\"') {
+ CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+