From 94b17fa1b669e55482efc7a8faec8c95e05d86ec Mon Sep 17 00:00:00 2001 From: jcarsey Date: Thu, 7 May 2009 18:46:18 +0000 Subject: First (Alpha) release of ShellPkg git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@8256 6f19259b-4bc3-4df7-8a09-765794883524 --- ShellPkg/Library/BaseShellLib/BaseShellLib.c | 2099 ++++++++++++++++++++++++ ShellPkg/Library/BaseShellLib/BaseShellLib.inf | 61 + 2 files changed, 2160 insertions(+) create mode 100644 ShellPkg/Library/BaseShellLib/BaseShellLib.c create mode 100644 ShellPkg/Library/BaseShellLib/BaseShellLib.inf (limited to 'ShellPkg/Library') diff --git a/ShellPkg/Library/BaseShellLib/BaseShellLib.c b/ShellPkg/Library/BaseShellLib/BaseShellLib.c new file mode 100644 index 0000000..205974d --- /dev/null +++ b/ShellPkg/Library/BaseShellLib/BaseShellLib.c @@ -0,0 +1,2099 @@ +/** @file + Provides interface to shell functionality for shell commands and applications. + +Copyright (c) 2006 - 2009, 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. + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_FILE_NAME_LEN 522 // (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes) +#define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN) + +EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2; +EFI_SHELL_INTERFACE *mEfiShellInterface; +EFI_SHELL_PROTOCOL *mEfiShellProtocol; +EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol; +EFI_HANDLE mEfiShellEnvironment2Handle; +EFI_LIST_ENTRY *mOldStyleFileList; + +/** + helper function to find ShellEnvironment2 for constructor +**/ +EFI_STATUS +EFIAPI +ShellFindSE2 ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE *Buffer; + UINTN BufferSize; + UINTN HandleIndex; + + BufferSize = 0; + Buffer = NULL; + Status = gBS->OpenProtocol(ImageHandle, + &gEfiShellEnvironment2Guid, + (VOID **)&mEfiShellEnvironment2, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + // + // look for the mEfiShellEnvironment2 protocol at a higher level + // + if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE && + (mEfiShellEnvironment2->MajorVersion > EFI_SHELL_MAJOR_VER || + (mEfiShellEnvironment2->MajorVersion == EFI_SHELL_MAJOR_VER && mEfiShellEnvironment2->MinorVersion >= EFI_SHELL_MINOR_VER)))) { + // + // figure out how big of a buffer we need. + // + Status = gBS->LocateHandle (ByProtocol, + &gEfiShellEnvironment2Guid, + NULL, // ignored for ByProtocol + &BufferSize, + Buffer + ); + ASSERT(Status == EFI_BUFFER_TOO_SMALL); + Buffer = (EFI_HANDLE*)AllocatePool(BufferSize); + ASSERT(Buffer != NULL); + Status = gBS->LocateHandle (ByProtocol, + &gEfiShellEnvironment2Guid, + NULL, // ignored for ByProtocol + &BufferSize, + Buffer + ); + if (!EFI_ERROR (Status)) { + // + // now parse the list of returned handles + // + Status = EFI_NOT_FOUND; + for (HandleIndex = 0; HandleIndex < (BufferSize/sizeof(Buffer[0])); HandleIndex++) { + Status = gBS->OpenProtocol(Buffer[HandleIndex], + &gEfiShellEnvironment2Guid, + (VOID **)&mEfiShellEnvironment2, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE && + (mEfiShellEnvironment2->MajorVersion > EFI_SHELL_MAJOR_VER || + (mEfiShellEnvironment2->MajorVersion == EFI_SHELL_MAJOR_VER && mEfiShellEnvironment2->MinorVersion >= EFI_SHELL_MINOR_VER))) { + mEfiShellEnvironment2Handle = Buffer[HandleIndex]; + Status = EFI_SUCCESS; + break; + } + } + } + } + if (Buffer != NULL) { + FreePool (Buffer); + } + return (Status); +} + +/** + Constructor for the Shell library. + + Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell. + + @param ImageHandle the image handle of the process + @param SystemTable the EFI System Table pointer + + @retval EFI_SUCCESS the initialization was complete sucessfully + @return others an error ocurred during initialization +**/ +EFI_STATUS +EFIAPI +ShellLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + ASSERT(SystemTable != NULL); + ASSERT(gBS != NULL); + + mEfiShellEnvironment2 = NULL; + mEfiShellProtocol = NULL; + mEfiShellParametersProtocol = NULL; + mEfiShellInterface = NULL; + mEfiShellEnvironment2Handle = NULL; + mOldStyleFileList = NULL; + + // + // UEFI 2.0 shell interfaces (used preferentially) + // + Status = gBS->OpenProtocol(ImageHandle, + &gEfiShellProtocolGuid, + (VOID **)&mEfiShellProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status)) { + mEfiShellProtocol = NULL; + } + Status = gBS->OpenProtocol(ImageHandle, + &gEfiShellParametersProtocolGuid, + (VOID **)&mEfiShellParametersProtocol, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status)) { + mEfiShellParametersProtocol = NULL; + } + + if (mEfiShellParametersProtocol == NULL || mEfiShellProtocol == NULL) { + // + // Moved to seperate function due to complexity + // + Status = ShellFindSE2(ImageHandle); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Status: 0x%08x\r\n", Status)); + mEfiShellEnvironment2 = NULL; + } + Status = gBS->OpenProtocol(ImageHandle, + &gEfiShellInterfaceGuid, + (VOID **)&mEfiShellInterface, + ImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status)) { + mEfiShellInterface = NULL; + } + } + // + // only success getting 2 of either the old or new, but no 1/2 and 1/2 + // + if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) || + (mEfiShellProtocol != NULL && mEfiShellParametersProtocol != NULL) ) { + return (EFI_SUCCESS); + } + return (EFI_NOT_FOUND); +} + +/** + Destructory for the library. free any resources. +**/ +EFI_STATUS +EFIAPI +ShellLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + if (mEfiShellEnvironment2 != NULL) { + gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle, + &gEfiShellEnvironment2Guid, + ImageHandle, + NULL); + } + if (mEfiShellInterface != NULL) { + gBS->CloseProtocol(ImageHandle, + &gEfiShellInterfaceGuid, + ImageHandle, + NULL); + } + if (mEfiShellProtocol != NULL) { + gBS->CloseProtocol(ImageHandle, + &gEfiShellProtocolGuid, + ImageHandle, + NULL); + } + if (mEfiShellParametersProtocol != NULL) { + gBS->CloseProtocol(ImageHandle, + &gEfiShellParametersProtocolGuid, + ImageHandle, + NULL); + } + return (EFI_SUCCESS); +} +/** + This function will retrieve the information about the file for the handle + specified and store it in allocated pool memory. + + This function allocates a buffer to store the file’s information. It is the + caller’s responsibility to free the buffer + + @param FileHandle The file handle of the file for which information is + being requested. + + @retval NULL information could not be retrieved. + + @return the information about the file +**/ +EFI_FILE_INFO* +EFIAPI +ShellGetFileInfo ( + IN EFI_FILE_HANDLE FileHandle + ) +{ + EFI_GUID FileInfoGuid; + EFI_FILE_INFO *pFileInfo; + UINTN FileInfoSize; + EFI_STATUS Status; + + // + // ASSERT if FileHandle is NULL + // + ASSERT (FileHandle != NULL); + + // + // Get the required size to allocate + // + FileInfoGuid = gEfiFileInfoGuid; + FileInfoSize = 0; + pFileInfo = NULL; + Status = FileHandle->GetInfo(FileHandle, + &FileInfoGuid, + &FileInfoSize, + pFileInfo); + // + // error is expected. getting size to allocate + // + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + pFileInfo = AllocateZeroPool(FileInfoSize); + ASSERT (pFileInfo != NULL); + // + // now get the information + // + Status = FileHandle->GetInfo(FileHandle, + &FileInfoGuid, + &FileInfoSize, + pFileInfo); + // + // if we got an error free the memory and return NULL + // + if (EFI_ERROR(Status)) { + FreePool(pFileInfo); + return NULL; + } + return (pFileInfo); +} + +/** + This function will set the information about the file for the opened handle + specified. + + @param FileHandle The file handle of the file for which information + is being set + + @param FileInfo The infotmation to set. + + @retval EFI_SUCCESS The information was set. + @retval EFI_UNSUPPORTED The InformationType is not known. + @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 EFI_FILE_HANDLE FileHandle, + IN EFI_FILE_INFO *FileInfo + ) +{ + EFI_GUID FileInfoGuid; + + // + // ASSERT if the FileHandle or FileInfo is NULL + // + ASSERT (FileHandle != NULL); + ASSERT (FileInfo != NULL); + + FileInfoGuid = gEfiFileInfoGuid; + // + // Set the info + // + return (FileHandle->SetInfo(FileHandle, + &FileInfoGuid, + (UINTN)FileInfo->Size, + FileInfo)); +} + + /** + This function will open a file or directory referenced by DevicePath. + + 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 + 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 + 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 EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellOpenFileByDevicePath( + IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, + OUT EFI_HANDLE *DeviceHandle, + OUT EFI_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + CHAR16 *FileName; + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; + EFI_FILE_HANDLE LastHandle; + + // + // ASERT for FileHandle, FilePath, and DeviceHandle being NULL + // + ASSERT(FilePath != NULL); + ASSERT(FileHandle != NULL); + ASSERT(DeviceHandle != NULL); + // + // which shell interface should we use + // + if (mEfiShellProtocol != NULL) { + // + // use UEFI Shell 2.0 method. + // + FileName = mEfiShellProtocol->GetFilePathFromDevicePath(*FilePath); + if (FileName == NULL) { + return (EFI_INVALID_PARAMETER); + } + Status = ShellOpenFileByName(FileName, FileHandle, OpenMode, Attributes); + FreePool(FileName); + return (Status); + } else { + // + // use old shell method. + // + Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, + FilePath, + DeviceHandle); + if (EFI_ERROR (Status)) { + return Status; + } + Status = gBS->OpenProtocol(*DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + &EfiSimpleFileSystemProtocol, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR (Status)) { + return Status; + } + Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, FileHandle); + 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 + // + LastHandle = *FileHandle; + *FileHandle = NULL; + + // + // Try to test opening an existing file + // + Status = LastHandle->Open ( + LastHandle, + FileHandle, + ((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 = LastHandle->Open ( + LastHandle, + FileHandle, + ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, + OpenMode, + Attributes + ); + } + // + // Close the last node + // + LastHandle->Close (LastHandle); + + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // Get the next node + // + *FilePath = NextDevicePathNode (*FilePath); + } + return (EFI_SUCCESS); + } +} + +/** + This function will open a file or directory referenced by filename. + + If return is EFI_SUCCESS, the Filehandle is the opened file’s handle; + otherwise, the Filehandle is NULL. The Attributes is valid only for + EFI_FILE_MODE_CREATE. + + 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. + + @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 + 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 EFI_VOLUME_FULL The volume is full. +**/ +EFI_STATUS +EFIAPI +ShellOpenFileByName( + IN CHAR16 *FileName, + OUT EFI_FILE_HANDLE *FileHandle, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + + // + // ASSERT if FileName is NULL + // + ASSERT(FileName != NULL); + + if (mEfiShellProtocol != NULL) { + // + // Use UEFI Shell 2.0 method + // + return (mEfiShellProtocol->OpenFileByName(FileName, + FileHandle, + OpenMode)); + } + // + // Using EFI Shell version + // this means convert name to path and call that function + // since this will use EFI method again that will open it. + // + ASSERT(mEfiShellEnvironment2 != NULL); + FilePath = mEfiShellEnvironment2->NameToPath (FileName); + if (FileDevicePath != NULL) { + return (ShellOpenFileByDevicePath(&FilePath, + &DeviceHandle, + FileHandle, + OpenMode, + Attributes )); + } + return (EFI_DEVICE_ERROR); +} +/** + This function create a directory + + If return is EFI_SUCCESS, the Filehandle is the opened directory's handle; + 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. + + @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 + 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 EFI_VOLUME_FULL The volume is full. + @sa ShellOpenFileByName +**/ +EFI_STATUS +EFIAPI +ShellCreateDirectory( + IN CHAR16 *DirectoryName, + OUT EFI_FILE_HANDLE *FileHandle + ) +{ + // + // this is a pass thru to the open file function with sepcific open mode and attributes + // + return (ShellOpenFileByName(DirectoryName, + FileHandle, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, + EFI_FILE_DIRECTORY + )); +} + +/** + This function reads information from an opened file. + + If FileHandle is not a directory, the function reads the requested number of + bytes from the file at the file’s current position and returns them in Buffer. + If the read goes beyond the end of the file, the read length is truncated to the + end of the file. The file’s current position is increased by the number of bytes + returned. If FileHandle is a directory, the function reads the directory entry + at the file’s current position and returns the entry in Buffer. If the Buffer + is not large enough to hold the current directory entry, then + EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated. + BufferSize is set to be the size of the buffer needed to read the entry. On + success, the current position is updated to the next directory entry. If there + are no more directory entries, the read returns a zero-length buffer. + EFI_FILE_INFO is the structure returned as the directory entry. + + @param FileHandle the opened file handle + @param BufferSize on input the size of buffer in bytes. on return + 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 + size. + +**/ +EFI_STATUS +EFIAPI +ShellReadFile( + IN EFI_FILE_HANDLE FileHandle, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + // + // ASSERT if FileHandle is NULL + // + ASSERT (FileHandle != NULL); + + // + // Perform the read based on EFI_FILE_PROTOCOL + // + return (FileHandle->Read(FileHandle, BufferSize, Buffer)); +} + + +/** + Write data to a file. + + This function writes the specified number of bytes to the file at the current + file position. The current file position is advanced the actual number of bytes + written, which is returned in BufferSize. Partial writes only occur when there + has been a data error during the write attempt (such as “volume space full”). + The file is automatically grown to hold the data if required. Direct writes to + opened directories are not supported. + + @param FileHandle The opened file for writing + @param BufferSize on input the number of bytes in Buffer. On output + 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. +**/ +EFI_STATUS +EFIAPI +ShellWriteFile( + IN EFI_FILE_HANDLE FileHandle, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + // + // ASSERT if FileHandle is NULL + // + ASSERT (FileHandle != NULL); + // + // Perform the write based on EFI_FILE_PROTOCOL + // + return (FileHandle->Write(FileHandle, BufferSize, Buffer)); +} + +/** + Close an open file handle. + + This function closes a specified file handle. All “dirty” cached file data is + flushed to the device, and the file is closed. In all cases the handle is + closed. + +@param FileHandle the file handle to close. + +@retval EFI_SUCCESS the file handle was closed sucessfully. +**/ +EFI_STATUS +EFIAPI +ShellCloseFile ( + IN EFI_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + // + // ASSERT if FileHandle is NULL + // + ASSERT (FileHandle != NULL); + ASSERT (*FileHandle != NULL); + // + // Perform the Close based on EFI_FILE_PROTOCOL + // + Status = (*FileHandle)->Close(*FileHandle); + *FileHandle = NULL; + return Status; +} + +/** + Delete a file and close the handle + + This function closes and deletes a file. In all cases the file handle is closed. + If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is + returned, but the handle is still closed. + + @param FileHandle the file handle to delete + + @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. +**/ +EFI_STATUS +EFIAPI +ShellDeleteFile ( + IN EFI_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + // + // ASSERT if FileHandle is NULL + // + ASSERT (FileHandle != NULL); + ASSERT (*FileHandle != NULL); + // + // Perform the Delete based on EFI_FILE_PROTOCOL + // + Status = (*FileHandle)->Delete(*FileHandle); + *FileHandle = NULL; + return Status; +} + +/** + Set the current position in a file. + + This function sets the current file position for the handle to the position + supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only + absolute positioning is supported, and seeking past the end of the file is + allowed (a subsequent write would grow the file). Seeking to position + 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file. + If FileHandle is a directory, the only position that may be set is zero. This + has the effect of starting the read process of the directory entries over. + + @param FileHandle The file handle on which the position is being set + @param Position Byte position from begining of file + + @retval EFI_SUCCESS Operation completed sucessfully. + @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on + directories. + @retval INVALID_PARAMETER One of the parameters has an invalid value. +**/ +EFI_STATUS +EFIAPI +ShellSetFilePosition ( + IN EFI_FILE_HANDLE FileHandle, + IN UINT64 Position + ) +{ + // + // ASSERT if FileHandle is NULL + // + ASSERT (FileHandle != NULL); + // + // Perform the SetPosition based on EFI_FILE_PROTOCOL + // + return (FileHandle->SetPosition(FileHandle, Position)); +} + +/** + Gets a file's current position + + This function retrieves the current file position for the file handle. For + directories, the current file position has no meaning outside of the file + system driver and as such the operation is not supported. An error is returned + if FileHandle is a directory. + + @param FileHandle The open file handle on which to get the position. + @param Position Byte position from begining of file. + + @retval EFI_SUCCESS the operation completed sucessfully. + @retval INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED the request is not valid on directories. +**/ +EFI_STATUS +EFIAPI +ShellGetFilePosition ( + IN EFI_FILE_HANDLE FileHandle, + OUT UINT64 *Position + ) +{ + // + // ASSERT if FileHandle is NULL + // + ASSERT (FileHandle != NULL); + // + // Perform the GetPosition based on EFI_FILE_PROTOCOL + // + return (FileHandle->GetPosition(FileHandle, Position)); +} +/** + Flushes data on a file + + This function flushes all modified data associated with a file to a device. + + @param FileHandle The file handle on which to flush data + + @retval EFI_SUCCESS The data was flushed. + @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 file or medium is write protected. + @retval EFI_ACCESS_DENIED The file was opened for read only. +**/ +EFI_STATUS +EFIAPI +ShellFlushFile ( + IN EFI_FILE_HANDLE FileHandle + ) +{ + // + // ASSERT if FileHandle is NULL + // + ASSERT (FileHandle != NULL); + // + // Perform the Flush based on EFI_FILE_PROTOCOL + // + return (FileHandle->Flush(FileHandle)); +} + +/** + function to determine if a given handle is a directory handle + + if DirHandle is NULL then ASSERT() + + open the file information on the DirHandle and verify that the Attribute + includes EFI_FILE_DIRECTORY bit set. + + @param DirHandle Handle to open file + + @retval EFI_SUCCESS DirHandle is a directory + @retval EFI_INVALID_PARAMETER DirHandle did not have EFI_FILE_INFO available + @retval EFI_NOT_FOUND DirHandle is not a directory +**/ +EFI_STATUS +EFIAPI +InternalShellIsDirectory ( + IN EFI_FILE_HANDLE DirHandle + ) +{ + EFI_FILE_INFO *DirInfo; + + // + // ASSERT if DirHandle is NULL + // + ASSERT(DirHandle != NULL); + + // + // get the file information for DirHandle + // + DirInfo = ShellGetFileInfo (DirHandle); + + // + // Parse DirInfo + // + if (DirInfo == NULL) { + // + // We got nothing... + // + return (EFI_INVALID_PARAMETER); + } + if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) { + // + // Attributes say this is not a directory + // + FreePool (DirInfo); + return (EFI_NOT_FOUND); + } + // + // all good... + // + FreePool (DirInfo); + return (EFI_SUCCESS); +} + +/** + Retrieves the first file from a directory + + 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. + + @param DirHandle The file handle of the directory to search + @param Buffer Pointer to buffer for file's information + + @retval EFI_SUCCESS Found the first file. + @retval EFI_NOT_FOUND Cannot find the directory. + @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. + @return Others status of ShellGetFileInfo, ShellSetFilePosition, + or ShellReadFile +**/ +EFI_STATUS +EFIAPI +ShellFindFirstFile ( + IN EFI_FILE_HANDLE DirHandle, + OUT EFI_FILE_INFO *Buffer + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + + // + // ASSERT if DirHandle is NULL + // + ASSERT (DirHandle != NULL); + + // + // verify that DirHandle is a directory + // + Status = InternalShellIsDirectory(DirHandle); + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // reset to the begining of the directory + // + Status = ShellSetFilePosition (DirHandle, 0); + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // Allocate a buffer sized to struct size + enough for the string at the end + // + BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE; + Buffer = AllocateZeroPool(BufferSize); + ASSERT (Buffer != NULL); + + // + // read in the info about the first file + // + Status = ShellReadFile (DirHandle, &BufferSize, Buffer); + ASSERT(Status != EFI_BUFFER_TOO_SMALL); + if (EFI_ERROR(Status)) { + return (Status); + } + return (EFI_SUCCESS); +} +/** + Retrieves the next file in a directory. + + To use this function, caller must call the LibFindFirstFile() 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. + + @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 + + @retval EFI_SUCCESS Found the next file, or reached last file + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. +**/ +EFI_STATUS +EFIAPI +ShellFindNextFile( + IN EFI_FILE_HANDLE DirHandle, + OUT EFI_FILE_INFO *Buffer, + OUT BOOLEAN *NoFile + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + + // + // ASSERTs for DirHandle or Buffer or NoFile poitners being NULL + // + ASSERT (DirHandle != NULL); + ASSERT (Buffer != NULL); + ASSERT (NoFile != NULL); + + // + // verify that DirHandle is a directory + // + Status = InternalShellIsDirectory(DirHandle); + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // This BufferSize MUST stay equal to the originally allocated one in GetFirstFile + // + BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE; + + // + // read in the info about the next file + // + Status = ShellReadFile (DirHandle, &BufferSize, Buffer); + ASSERT(Status != EFI_BUFFER_TOO_SMALL); + if (EFI_ERROR(Status)) { + return (Status); + } + + // + // If we read 0 bytes (but did not have erros) we already read in the last file. + // + if (BufferSize == 0) { + FreePool(Buffer); + *NoFile = TRUE; + } + + return (EFI_SUCCESS); +} +/** + Retrieve the size of a file. + + if FileHandle is NULL then ASSERT() + if Size is NULL then ASSERT() + + This function extracts the file size info from the FileHandle’s EFI_FILE_INFO + data. + + @param FileHandle file handle from which size is retrieved + @param Size pointer to size + + @retval EFI_SUCCESS operation was completed sucessfully + @retval EFI_DEVICE_ERROR cannot access the file +**/ +EFI_STATUS +EFIAPI +ShellGetFileSize ( + IN EFI_FILE_HANDLE FileHandle, + OUT UINT64 *Size + ) +{ + EFI_FILE_INFO *FileInfo; + + // + // ASSERT for FileHandle or Size being NULL + // + ASSERT (FileHandle != NULL); + ASSERT (Size != NULL); + + // + // get the FileInfo structure + // + FileInfo = ShellGetFileInfo(FileHandle); + if (FileInfo == NULL) { + return (EFI_DEVICE_ERROR); + } + + // + // Assign the Size pointer to the correct value + // + *Size = FileInfo->FileSize; + + // + // free the FileInfo memory + // + FreePool(FileInfo); + + return (EFI_SUCCESS); +} +/** + Retrieves the status of the break execution flag + + this function is useful to check whether the application is being asked to halt by the shell. + + @retval TRUE the execution break is enabled + @retval FALSE the execution break is not enabled +**/ +BOOLEAN +EFIAPI +ShellGetExecutionBreakFlag( + VOID + ) +{ + // + // Check for UEFI Shell 2.0 protocols + // + if (mEfiShellProtocol != NULL) { + + // + // We are using UEFI Shell 2.0; see if the event has been triggered + // + if (gBS->CheckEvent(mEfiShellProtocol->ExecutionBreak) != EFI_SUCCESS) { + return (FALSE); + } + return (TRUE); + } + + // + // using EFI Shell; call the function to check + // + ASSERT(mEfiShellEnvironment2 != NULL); + return (mEfiShellEnvironment2->GetExecutionBreak()); +} +/** + return the value of an environment variable + + this function gets the value of the environment variable set by the + ShellSetEnvironmentVariable function + + @param EnvKey The key name of the environment variable. + + @retval NULL the named environment variable does not exist. + @return != NULL pointer to the value of the environment variable +**/ +CONST CHAR16* +EFIAPI +ShellGetEnvironmentVariable ( + IN CHAR16 *EnvKey + ) +{ + // + // Check for UEFI Shell 2.0 protocols + // + if (mEfiShellProtocol != NULL) { + return (mEfiShellProtocol->GetEnv(EnvKey)); + } + + // + // ASSERT that we must have EFI shell + // + ASSERT(mEfiShellEnvironment2 != NULL); + + // + // using EFI Shell + // + return (mEfiShellEnvironment2->GetEnv(EnvKey)); +} +/** + set the value of an environment variable + +This function changes the current value of the specified environment variable. If the +environment variable exists and the Value is an empty string, then the environment +variable is deleted. If the environment variable exists and the Value is not an empty +string, then the value of the environment variable is changed. If the environment +variable does not exist and the Value is an empty string, there is no action. If the +environment variable does not exist and the Value is a non-empty string, then the +environment variable is created and assigned the specified value. + + This is not supported pre-UEFI Shell 2.0. + + @param EnvKey The key name of the environment variable. + @param EnvVal The Value of the environment variable + @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE). + + @retval EFI_SUCCESS the operation was completed sucessfully + @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments +**/ +EFI_STATUS +EFIAPI +ShellSetEnvironmentVariable ( + IN CONST CHAR16 *EnvKey, + IN CONST CHAR16 *EnvVal, + IN BOOLEAN Volatile + ) +{ + // + // Check for UEFI Shell 2.0 protocols + // + if (mEfiShellProtocol != NULL) { + return (mEfiShellProtocol->SetEnv(EnvKey, EnvVal, Volatile)); + } + + // + // This feature does not exist under EFI shell + // + return (EFI_UNSUPPORTED); +} +/** + cause the shell to parse and execute a command line. + + This function creates a nested instance of the shell and executes the specified +command (CommandLine) with the specified environment (Environment). Upon return, +the status code returned by the specified command is placed in StatusCode. +If Environment is NULL, then the current environment is used and all changes made +by the commands executed will be reflected in the current environment. If the +Environment is non-NULL, then the changes made will be discarded. +The CommandLine is executed from the current working directory on the current +device. + +EnvironmentVariables and Status are only supported for UEFI Shell 2.0. +Output is only supported for pre-UEFI Shell 2.0 + + @param ImageHandle Parent image that is starting the operation + @param CommandLine pointer to null terminated command line. + @param Output true to display debug output. false to hide it. + @param EnvironmentVariables optional pointer to array of environment variables + in the form "x=y". if NULL current set is used. + @param Status the status of the run command line. + + @retval EFI_SUCCESS the operation completed sucessfully. Status + contains the status code returned. + @retval EFI_INVALID_PARAMETER a parameter contains an invalid value + @retval EFI_OUT_OF_RESOURCES out of resources + @retval EFI_UNSUPPORTED the operation is not allowed. +**/ +EFI_STATUS +EFIAPI +ShellExecute ( + IN EFI_HANDLE *ParentHandle, + IN CHAR16 *CommandLine OPTIONAL, + IN BOOLEAN Output OPTIONAL, + IN CHAR16 **EnvironmentVariables OPTIONAL, + OUT EFI_STATUS *Status OPTIONAL + ) +{ + // + // Check for UEFI Shell 2.0 protocols + // + if (mEfiShellProtocol != NULL) { + // + // Call UEFI Shell 2.0 version (not using Output parameter) + // + return (mEfiShellProtocol->Execute(ParentHandle, + CommandLine, + EnvironmentVariables, + Status)); + } + // + // ASSERT that we must have EFI shell + // + ASSERT(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 + // + return (mEfiShellEnvironment2->Execute(*ParentHandle, + CommandLine, + Output)); +} +/** + Retreives the current directory path + + If the DeviceName is NULL, it returns the current device’s current directory + name. If the DeviceName is not NULL, it returns the current directory name + on specified drive. + + @param DeviceName the name of the drive to get directory on + + @retval NULL the directory does not exist + @return != NULL the directory +**/ +CONST CHAR16* +EFIAPI +ShellGetCurrentDir ( + IN CHAR16 *DeviceName OPTIONAL + ) +{ + // + // Check for UEFI Shell 2.0 protocols + // + if (mEfiShellProtocol != NULL) { + return (mEfiShellProtocol->GetCurDir(DeviceName)); + } + // + // ASSERT that we must have EFI shell + // + ASSERT(mEfiShellEnvironment2 != NULL); + return (mEfiShellEnvironment2->CurDir(DeviceName)); +} +/** + sets (enabled or disabled) the page break mode + + when page break mode is enabled the screen will stop scrolling + and wait for operator input before scrolling a subsequent screen. + + @param CurrentState TRUE to enable and FALSE to disable +**/ +VOID +EFIAPI +ShellSetPageBreakMode ( + IN BOOLEAN CurrentState + ) +{ + // + // check for enabling + // + if (CurrentState != 0x00) { + // + // check for UEFI Shell 2.0 + // + if (mEfiShellProtocol != NULL) { + // + // Enable with UEFI 2.0 Shell + // + mEfiShellProtocol->EnablePageBreak(); + return; + } else { + // + // ASSERT that must have EFI Shell + // + ASSERT(mEfiShellEnvironment2 != NULL); + // + // Enable with EFI Shell + // + mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF); + return; + } + } else { + // + // check for UEFI Shell 2.0 + // + if (mEfiShellProtocol != NULL) { + // + // Disable with UEFI 2.0 Shell + // + mEfiShellProtocol->DisablePageBreak(); + return; + } else { + // + // ASSERT that must have EFI Shell + // + ASSERT(mEfiShellEnvironment2 != NULL); + // + // Disable with EFI Shell + // + mEfiShellEnvironment2->DisablePageBreak (); + return; + } + } +} + +/// +/// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers. +/// This allows for the struct to be populated. +/// +typedef struct { + EFI_LIST_ENTRY Link; + EFI_STATUS Status; + CHAR16 *FullName; + CHAR16 *FileName; + EFI_FILE_HANDLE Handle; + EFI_FILE_INFO *Info; +} EFI_SHELL_FILE_INFO_NO_CONST; + +/** + Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list. + + if OldStyleFileList is NULL then ASSERT() + + this function will convert a SHELL_FILE_ARG based list into a callee allocated + EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via + the ShellCloseFileMetaArg function. + + @param FileList the EFI shell list type + + @retval the resultant head of the double linked new format list; +**/ +LIST_ENTRY* +EFIAPI +InternalShellConvertFileListType ( + EFI_LIST_ENTRY *FileList + ) +{ + LIST_ENTRY *ListHead; + SHELL_FILE_ARG *OldInfo; + EFI_LIST_ENTRY *Link; + EFI_SHELL_FILE_INFO_NO_CONST *NewInfo; + + // + // ASSERT that FileList is not NULL + // + ASSERT(FileList != NULL); + + // + // Allocate our list head and initialize the list + // + ListHead = AllocateZeroPool(sizeof(EFI_LIST_ENTRY)); + ASSERT (ListHead != NULL); + ListHead = InitializeListHead (ListHead); + + // + // enumerate through each member of the old list and copy + // + for (Link = FileList->Flink; Link != FileList; Link = Link->Flink) { + OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE); + + // + // make sure the old list was valid + // + ASSERT(OldInfo != NULL); + ASSERT(OldInfo->Info != NULL); + ASSERT(OldInfo->FullName != NULL); + ASSERT(OldInfo->FileName != NULL); + + // + // allocate a new EFI_SHELL_FILE_INFO object + // + NewInfo = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO)); + + // + // copy the simple items + // + NewInfo->Handle = OldInfo->Handle; + NewInfo->Status = OldInfo->Status; + + // + // 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); + + // + // make sure all the memory allocations were sucessful + // + ASSERT(NewInfo->FullName != NULL); + ASSERT(NewInfo->FileName != NULL); + ASSERT(NewInfo->Info != NULL); + + // + // 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); + + // + // add that to the list + // + InsertTailList(ListHead, (LIST_ENTRY*)NewInfo); + } + return (ListHead); +} +/** + 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 + 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(). + + This function will fail if called sequentially without freeing the list in the middle. + + @param Arg pointer to path string + @param OpenMode mode to open files with + @param ListHead head of linked list of results + + @retval EFI_SUCCESS the operation was sucessful and the list head + contains the list of opened files + #retval EFI_UNSUPPORTED a previous ShellOpenFileMetaArg must be closed first. + *ListHead is set to NULL. + @return != EFI_SUCCESS the operation failed + + @sa InternalShellConvertFileListType +**/ +EFI_STATUS +EFIAPI +ShellOpenFileMetaArg ( + IN CHAR16 *Arg, + IN UINT64 OpenMode, + IN OUT EFI_SHELL_FILE_INFO **ListHead + ) +{ + EFI_STATUS Status; + LIST_ENTRY *EmptyNode; + + // + // make sure we have no outstanding list + // + if (mOldStyleFileList != NULL) { + *ListHead = NULL; + return (EFI_UNSUPPORTED); + } + + // + // ASSERT that Arg and ListHead are not NULL + // + ASSERT(Arg != NULL); + ASSERT(ListHead != NULL); + + // + // Check for UEFI Shell 2.0 protocols + // + if (mEfiShellProtocol != NULL) { + return (mEfiShellProtocol->OpenFileList(Arg, + OpenMode, + ListHead)); + } + + // + // ASSERT that we must have EFI shell + // + ASSERT(mEfiShellEnvironment2 != NULL); + + // + // allocate memory for old list head + // + mOldStyleFileList = (EFI_LIST_ENTRY*)AllocatePool(sizeof(EFI_LIST_ENTRY)); + ASSERT(mOldStyleFileList != NULL); + + // + // make sure the list head is initialized + // + InitializeListHead((LIST_ENTRY*)mOldStyleFileList); + + // + // Get the EFI Shell list of files + // + Status = mEfiShellEnvironment2->FileMetaArg(Arg, mOldStyleFileList); + if (EFI_ERROR(Status)) { + *ListHead = NULL; + return (Status); + } + + // + // Convert that to equivalent of UEFI Shell 2.0 structure + // + EmptyNode = InternalShellConvertFileListType(mOldStyleFileList); + + // + // remove the empty head of the list + // + *ListHead = (EFI_SHELL_FILE_INFO*)RemoveEntryList(EmptyNode); + FreePool(EmptyNode); + + return (Status); +} +/** + Free the linked list returned from ShellOpenFileMetaArg + + if ListHead is NULL then ASSERT() + + @param ListHead the pointer to free + + @retval EFI_SUCCESS the operation was sucessful +**/ +EFI_STATUS +EFIAPI +ShellCloseFileMetaArg ( + IN OUT EFI_SHELL_FILE_INFO **ListHead + ) +{ + LIST_ENTRY *Node; + + // + // ASSERT that ListHead is not NULL + // + ASSERT(ListHead != NULL); + + // + // Check for UEFI Shell 2.0 protocols + // + if (mEfiShellProtocol != NULL) { + return (mEfiShellProtocol->FreeFileList(ListHead)); + } else { + // + // Free the EFI Shell version that was converted. + // + ASSERT_EFI_ERROR(mEfiShellEnvironment2->FreeFileList(mOldStyleFileList)); + FreePool(mOldStyleFileList); + mOldStyleFileList = NULL; + + // + // Since this is EFI Shell version we need to free our internally made copy + // of the list + // + for (Node = GetFirstNode((LIST_ENTRY*)*ListHead) ; IsListEmpty((LIST_ENTRY*)*ListHead) == FALSE ; Node = GetFirstNode((LIST_ENTRY*)*ListHead)) { + RemoveEntryList(Node); + FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName); + FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FileName); + FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info); + FreePool((EFI_SHELL_FILE_INFO_NO_CONST*)Node); + } + return EFI_SUCCESS; + } +} + +typedef struct { + EFI_LIST_ENTRY List; + CHAR16 *Name; + ParamType Type; + CHAR16 *Value; + UINTN OriginalPosition; +} SHELL_PARAM_PACKAGE; + +/** + Checks the list of valid arguments and returns TRUE if the item was found. If the + return value is TRUE then the type parameter is set also. + + if CheckList is NULL then ASSERT(); + if Name is NULL then ASSERT(); + if Type is NULL then ASSERT(); + + @param Type pointer to type of parameter if it was found + @param Name pointer to Name of parameter found + @param CheckList List to check against + + @retval TRUE the Parameter was found. Type is valid. + @retval FALSE the Parameter was not found. Type is not valid. +**/ +BOOLEAN +EFIAPI +IsCheckList ( + IN CONST CHAR16 *Name, + IN CONST SHELL_PARAM_ITEM *CheckList, + OUT ParamType *Type + ) +{ + SHELL_PARAM_ITEM *TempListItem; + + // + // ASSERT that all 3 pointer parameters aren't NULL + // + ASSERT(CheckList != NULL); + ASSERT(Type != NULL); + ASSERT(Name != NULL); + + // + // Enumerate through the list + // + for (TempListItem = (SHELL_PARAM_ITEM*)CheckList ; TempListItem->Name != NULL ; TempListItem++) { + // + // If the Name matches set the type and return TRUE + // + if (StrCmp(Name, TempListItem->Name) == 0) { + *Type = TempListItem->Type; + return (TRUE); + } + } + return (FALSE); +} +/** + Checks the string for indicators of "flag" status. this is a leading '/' or '-' + + @param Name pointer to Name of parameter found + + @retval TRUE the Parameter is a flag. + @retval FALSE the Parameter not a flag +**/ +BOOLEAN +EFIAPI +IsFlag ( + IN CONST CHAR16 *Name + ) +{ + // + // ASSERT that Name isn't NULL + // + ASSERT(Name != NULL); + + // + // If the Name has a / or - as the first character return TRUE + // + if ((Name[0] == L'/') || (Name[0] == L'-') ) { + return (TRUE); + } + return (FALSE); +} + +/** + Checks the command line arguments passed against the list of valid ones. + + If no initialization is required, then return RETURN_SUCCESS. + + @param CheckList pointer to list of parameters to check + @param CheckPackage pointer to pointer to list checked values + @param ProblemParam optional pointer to pointer to unicode string for + the paramater that caused failure. + @param AutoPageBreak will automatically set PageBreakEnabled for "b" parameter + @param Argc Count of parameters in Argv + @param Argv pointer to array of parameters + + @retval EFI_SUCCESS The operation completed sucessfully. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed + @retval EFI_INVALID_PARAMETER A parameter was invalid + @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was + duplicated. the duplicated command line argument + was returned in ProblemParam if provided. + @retval EFI_NOT_FOUND a argument required a value that was missing. + the invalid command line argument was returned in + ProblemParam if provided. +**/ +EFI_STATUS +EFIAPI +InternalCommandLineParse ( + IN CONST SHELL_PARAM_ITEM *CheckList, + OUT LIST_ENTRY **CheckPackage, + OUT CHAR16 **ProblemParam OPTIONAL, + IN BOOLEAN AutoPageBreak, + IN CONST CHAR16 **Argv, + IN UINTN Argc + ) +{ + UINTN LoopCounter; + UINTN Count; + ParamType CurrentItemType; + SHELL_PARAM_PACKAGE *CurrentItemPackage; + BOOLEAN GetItemValue; + + CurrentItemPackage = NULL; + + // + // ASSERTs + // + ASSERT(CheckList != NULL); + ASSERT(Argv != NULL); + + Count = 0; + GetItemValue = FALSE; + + // + // If there is only 1 item we dont need to do anything + // + if (Argc <= 1) { + *CheckPackage = NULL; + return (EFI_SUCCESS); + } + + // + // initialize the linked list + // + *CheckPackage = (LIST_ENTRY*)AllocateZeroPool(sizeof(LIST_ENTRY)); + InitializeListHead(*CheckPackage); + + // + // loop through each of the arguments + // + for (LoopCounter = 0 ; LoopCounter < Argc ; ++LoopCounter) { + if (Argv[LoopCounter] == NULL) { + // + // do nothing for NULL argv + // + } else if (GetItemValue == TRUE) { + ASSERT(CurrentItemPackage != NULL); + // + // get the item VALUE for the previous flag + // + GetItemValue = FALSE; + CurrentItemPackage->Value = AllocateZeroPool(StrSize(Argv[LoopCounter])); + ASSERT(CurrentItemPackage->Value != NULL); + StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]); + InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage); + } else if (IsFlag(Argv[LoopCounter]) == FALSE) { + // + // add this one as a non-flag + // + CurrentItemPackage = AllocatePool(sizeof(SHELL_PARAM_PACKAGE)); + ASSERT(CurrentItemPackage != NULL); + CurrentItemPackage->Name = NULL; + CurrentItemPackage->Type = TypePosition; + CurrentItemPackage->Value = AllocatePool(StrSize(Argv[LoopCounter])); + ASSERT(CurrentItemPackage->Value != NULL); + StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]); + CurrentItemPackage->OriginalPosition = Count++; + InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage); + } else if (IsCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) == TRUE) { + // + // this is a flag + // + CurrentItemPackage = AllocatePool(sizeof(SHELL_PARAM_PACKAGE)); + ASSERT(CurrentItemPackage != NULL); + CurrentItemPackage->Name = AllocatePool(StrSize(Argv[LoopCounter])); + ASSERT(CurrentItemPackage->Name != NULL); + StrCpy(CurrentItemPackage->Name, Argv[LoopCounter]); + CurrentItemPackage->Type = CurrentItemType; + CurrentItemPackage->OriginalPosition = (UINTN)(-1); + + // + // Does this flag require a value + // + if (CurrentItemPackage->Type == TypeValue) { + // + // trigger the next loop to populate the value of this item + // + GetItemValue = TRUE; + } else { + // + // this item has no value expected; we are done + // + CurrentItemPackage->Value = NULL; + InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage); + } + } else if (ProblemParam) { + // + // this was a non-recognised flag... error! + // + *ProblemParam = (CHAR16*)Argv[LoopCounter]; + ShellCommandLineFreeVarList(*CheckPackage); + *CheckPackage = NULL; + return (EFI_VOLUME_CORRUPTED); + } else { + ShellCommandLineFreeVarList(*CheckPackage); + *CheckPackage = NULL; + return (EFI_VOLUME_CORRUPTED); + } + } + // + // support for AutoPageBreak + // + if (AutoPageBreak && ShellCommandLineGetFlag(*CheckPackage, L"-b")) { + ShellSetPageBreakMode(TRUE); + } + return (EFI_SUCCESS); +} + +/** + Checks the command line arguments passed against the list of valid ones. + Optionally removes NULL values first. + + If no initialization is required, then return RETURN_SUCCESS. + + @param CheckList pointer to list of parameters to check + @param CheckPackage pointer to pointer to list checked values + @param ProblemParam optional pointer to pointer to unicode string for + the paramater that caused failure. + @param AutoPageBreak will automatically set PageBreakEnabled for "b" parameter + + @retval EFI_SUCCESS The operation completed sucessfully. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed + @retval EFI_INVALID_PARAMETER A parameter was invalid + @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was + duplicated. the duplicated command line argument + was returned in ProblemParam if provided. + @retval EFI_DEVICE_ERROR the commands contained 2 opposing arguments. one + of the command line arguments was returned in + ProblemParam if provided. + @retval EFI_NOT_FOUND a argument required a value that was missing. + the invalid command line argument was returned in + ProblemParam if provided. +**/ +EFI_STATUS +EFIAPI +ShellCommandLineParse ( + IN CONST SHELL_PARAM_ITEM *CheckList, + OUT LIST_ENTRY **CheckPackage, + OUT CHAR16 **ProblemParam OPTIONAL, + IN BOOLEAN AutoPageBreak + ) +{ + // + // ASSERT that CheckList and CheckPackage aren't NULL + // + ASSERT(CheckList != NULL); + ASSERT(CheckPackage != NULL); + + // + // Check for UEFI Shell 2.0 protocols + // + if (mEfiShellParametersProtocol != NULL) { + return (InternalCommandLineParse(CheckList, + CheckPackage, + ProblemParam, + AutoPageBreak, + mEfiShellParametersProtocol->Argv, + mEfiShellParametersProtocol->Argc )); + } + + // + // ASSERT That EFI Shell is not required + // + ASSERT (mEfiShellInterface != NULL); + return (InternalCommandLineParse(CheckList, + CheckPackage, + ProblemParam, + AutoPageBreak, + mEfiShellInterface->Argv, + mEfiShellInterface->Argc )); +} + +/** + Frees shell variable list that was returned from ShellCommandLineParse. + + This function will free all the memory that was used for the CheckPackage + list of postprocessed shell arguments. + + this function has no return value. + + if CheckPackage is NULL, then return + + @param CheckPackage the list to de-allocate + **/ +VOID +EFIAPI +ShellCommandLineFreeVarList ( + IN LIST_ENTRY *CheckPackage + ) +{ + LIST_ENTRY *Node; + + // + // check for CheckPackage == NULL + // + if (CheckPackage == NULL) { + return; + } + + // + // for each node in the list + // + for (Node = GetFirstNode(CheckPackage); Node != CheckPackage ; Node = GetFirstNode(CheckPackage)) { + // + // Remove it from the list + // + RemoveEntryList(Node); + + // + // if it has a name free the name + // + if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) { + FreePool(((SHELL_PARAM_PACKAGE*)Node)->Name); + } + + // + // if it has a value free the value + // + if (((SHELL_PARAM_PACKAGE*)Node)->Value != NULL) { + FreePool(((SHELL_PARAM_PACKAGE*)Node)->Value); + } + + // + // free the node structure + // + FreePool((SHELL_PARAM_PACKAGE*)Node); + } + // + // free the list head node + // + FreePool(CheckPackage); +} +/** + Checks for presence of a flag parameter + + flag arguments are in the form of "-" or "/", but do not have a value following the key + + if CheckPackage is NULL then return FALSE. + if KeyString is NULL then ASSERT() + + @param CheckPackage The package of parsed command line arguments + @param KeyString the Key of the command line argument to check for + + @retval TRUE the flag is on the command line + @retval FALSE the flag is not on the command line + **/ +BOOLEAN +EFIAPI +ShellCommandLineGetFlag ( + IN CONST LIST_ENTRY *CheckPackage, + IN CHAR16 *KeyString + ) +{ + LIST_ENTRY *Node; + + // + // ASSERT that both CheckPackage and KeyString aren't NULL + // + ASSERT(KeyString != NULL); + + // + // return FALSE for no package + // + if (CheckPackage == NULL) { + return (FALSE); + } + + // + // enumerate through the list of parametrs + // + for (Node = GetFirstNode(CheckPackage) ; Node != CheckPackage ; Node = GetNextNode(CheckPackage, Node) ) { + // + // If the Name matches, return TRUE (and there may be NULL name) + // + if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) { + if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) { + return (TRUE); + } + } + } + return (FALSE); +} +/** + returns value from command line argument + + value parameters are in the form of "- value" or "/ value" + + if CheckPackage is NULL, then return NULL; + + @param CheckPackage The package of parsed command line arguments + @param KeyString the Key of the command line argument to check for + + @retval NULL the flag is not on the command line + @return !=NULL pointer to unicode string of the value + **/ +CONST CHAR16* +EFIAPI +ShellCommandLineGetValue ( + IN CONST LIST_ENTRY *CheckPackage, + IN CHAR16 *KeyString + ) +{ + LIST_ENTRY *Node; + + // + // check for CheckPackage == NULL + // + if (CheckPackage == NULL) { + return (NULL); + } + + // + // enumerate through the list of parametrs + // + for (Node = GetFirstNode(CheckPackage) ; Node != NULL ; Node = GetNextNode(CheckPackage, Node) ) { + // + // If the Name matches, return the value (name can be NULL) + // + if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) { + if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) { + return (((SHELL_PARAM_PACKAGE*)Node)->Value); + } + } + } + return (NULL); +} +/** + returns raw value from command line argument + + raw value parameters are in the form of "value" in a specific position in the list + + if CheckPackage is NULL, then return NULL; + + @param CheckPackage The package of parsed command line arguments + @param Position the position of the value + + @retval NULL the flag is not on the command line + @return !=NULL pointer to unicode string of the value + **/ +CONST CHAR16* +EFIAPI +ShellCommandLineGetRawValue ( + IN CONST LIST_ENTRY *CheckPackage, + IN UINT32 Position + ) +{ + LIST_ENTRY *Node; + + // + // check for CheckPackage == NULL + // + if (CheckPackage == NULL) { + return (NULL); + } + + // + // enumerate through the list of parametrs + // + for (Node = GetFirstNode(CheckPackage) ; Node != NULL ; Node = GetNextNode(CheckPackage, Node) ) { + // + // If the position matches, return the value + // + if (((SHELL_PARAM_PACKAGE*)Node)->OriginalPosition == Position) { + return (((SHELL_PARAM_PACKAGE*)Node)->Value); + } + } + return (NULL); +} \ No newline at end of file diff --git a/ShellPkg/Library/BaseShellLib/BaseShellLib.inf b/ShellPkg/Library/BaseShellLib/BaseShellLib.inf new file mode 100644 index 0000000..8a2c33b --- /dev/null +++ b/ShellPkg/Library/BaseShellLib/BaseShellLib.inf @@ -0,0 +1,61 @@ +#/** @file +# Provides interface to shell functionality for shell commands and applications. +# +# Copyright (c) 2006 - 2009, 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. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010006 + BASE_NAME = BaseShellLib + FILE_GUID = 449D0F00-2148-4a43-9836-F10B3980ECF5 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = ShellLib|UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = ShellLibConstructor + DESTRUCTOR = ShellLibDestructor + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + BaseShellLib.c + +[Packages] + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + MemoryAllocationLib + DevicePathLib + BaseLib + BaseMemoryLib + DebugLib + +[Protocols] + gEfiSimpleFileSystemProtocolGuid # ALWAYS_CONSUMED + + # shell 2.0 + gEfiShellProtocolGuid # SOMETIMES_CONSUMED + gEfiShellParametersProtocolGuid # SOMETIMES_CONSUMED + + # 'old' shell + gEfiShellEnvironment2Guid # SOMETIMES_CONSUMED + gEfiShellInterfaceGuid # SOMETIMES_CONSUMED + +[Guids] + gEfiFileInfoGuid # ALWAYS_CONSUMED + gEfiShellEnvironment2ExtGuid # ALWAYS_CONSUMED + +[Pcd.common] + -- cgit v1.1