summaryrefslogtreecommitdiff
path: root/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c')
-rw-r--r--ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c1598
1 files changed, 799 insertions, 799 deletions
diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
index c3927ca35b..3dc949b46d 100644
--- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
+++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
@@ -1,799 +1,799 @@
-/** @file
- Main file for cp shell level 2 function.
-
- (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
- Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "UefiShellLevel2CommandsLib.h"
-#include <Guid/FileSystemInfo.h>
-#include <Guid/FileSystemVolumeLabelInfo.h>
-
-/**
- Function to take a list of files to copy and a destination location and do
- the verification and copying of those files to that location. This function
- will report any errors to the user and halt.
-
- @param[in] FileList A LIST_ENTRY* based list of files to move.
- @param[in] DestDir The destination location.
- @param[in] SilentMode TRUE to eliminate screen output.
- @param[in] RecursiveMode TRUE to copy directories.
- @param[in] Resp The response to the overwrite query (if always).
-
- @retval SHELL_SUCCESS the files were all moved.
- @retval SHELL_INVALID_PARAMETER a parameter was invalid
- @retval SHELL_SECURITY_VIOLATION a security violation ocurred
- @retval SHELL_WRITE_PROTECTED the destination was write protected
- @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
-**/
-SHELL_STATUS
-ValidateAndCopyFiles (
- IN CONST EFI_SHELL_FILE_INFO *FileList,
- IN CONST CHAR16 *DestDir,
- IN BOOLEAN SilentMode,
- IN BOOLEAN RecursiveMode,
- IN VOID **Resp
- );
-
-/**
- Function to Copy one file to another location
-
- If the destination exists the user will be prompted and the result put into *resp
-
- @param[in] Source pointer to source file name
- @param[in] Dest pointer to destination file name
- @param[out] Resp pointer to response from question. Pass back on looped calling
- @param[in] SilentMode whether to run in quiet mode or not
- @param[in] CmdName Source command name requesting single file copy
-
- @retval SHELL_SUCCESS The source file was copied to the destination
-**/
-SHELL_STATUS
-CopySingleFile (
- IN CONST CHAR16 *Source,
- IN CONST CHAR16 *Dest,
- OUT VOID **Resp,
- IN BOOLEAN SilentMode,
- IN CONST CHAR16 *CmdName
- )
-{
- VOID *Response;
- UINTN ReadSize;
- SHELL_FILE_HANDLE SourceHandle;
- SHELL_FILE_HANDLE DestHandle;
- EFI_STATUS Status;
- VOID *Buffer;
- CHAR16 *TempName;
- UINTN Size;
- EFI_SHELL_FILE_INFO *List;
- SHELL_STATUS ShellStatus;
- UINT64 SourceFileSize;
- UINT64 DestFileSize;
- EFI_FILE_PROTOCOL *DestVolumeFP;
- EFI_FILE_SYSTEM_INFO *DestVolumeInfo;
- UINTN DestVolumeInfoSize;
-
- ASSERT (Resp != NULL);
-
- SourceHandle = NULL;
- DestHandle = NULL;
- Response = *Resp;
- List = NULL;
- DestVolumeInfo = NULL;
- ShellStatus = SHELL_SUCCESS;
-
- ReadSize = PcdGet32 (PcdShellFileOperationSize);
- // Why bother copying a file to itself
- if (StrCmp (Source, Dest) == 0) {
- return (SHELL_SUCCESS);
- }
-
- //
- // if the destination file existed check response and possibly prompt user
- //
- if (ShellFileExists (Dest) == EFI_SUCCESS) {
- if ((Response == NULL) && !SilentMode) {
- Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
- }
-
- //
- // possibly return based on response
- //
- if (!SilentMode) {
- if (Response == NULL) {
- return SHELL_ABORTED;
- }
-
- switch (*(SHELL_PROMPT_RESPONSE *)Response) {
- case ShellPromptResponseNo:
- //
- // return success here so we dont stop the process
- //
- return (SHELL_SUCCESS);
- case ShellPromptResponseCancel:
- *Resp = Response;
- //
- // indicate to stop everything
- //
- return (SHELL_ABORTED);
- case ShellPromptResponseAll:
- *Resp = Response;
- case ShellPromptResponseYes:
- break;
- default:
- return SHELL_ABORTED;
- }
- }
- }
-
- if (ShellIsDirectory (Source) == EFI_SUCCESS) {
- Status = ShellCreateDirectory (Dest, &DestHandle);
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
- return (SHELL_ACCESS_DENIED);
- }
-
- //
- // Now copy all the files under the directory...
- //
- TempName = NULL;
- Size = 0;
- StrnCatGrow (&TempName, &Size, Source, 0);
- StrnCatGrow (&TempName, &Size, L"\\*", 0);
- if (TempName != NULL) {
- ShellOpenFileMetaArg ((CHAR16 *)TempName, EFI_FILE_MODE_READ, &List);
- *TempName = CHAR_NULL;
- StrnCatGrow (&TempName, &Size, Dest, 0);
- StrnCatGrow (&TempName, &Size, L"\\", 0);
- ShellStatus = ValidateAndCopyFiles (List, TempName, SilentMode, TRUE, Resp);
- ShellCloseFileMetaArg (&List);
- SHELL_FREE_NON_NULL (TempName);
- Size = 0;
- }
- } else {
- Status = ShellDeleteFileByName (Dest);
-
- //
- // open file with create enabled
- //
- Status = ShellOpenFileByName (Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
- return (SHELL_ACCESS_DENIED);
- }
-
- //
- // open source file
- //
- Status = ShellOpenFileByName (Source, &SourceHandle, EFI_FILE_MODE_READ, 0);
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source);
- return (SHELL_ACCESS_DENIED);
- }
-
- //
- // get file size of source file and freespace available on destination volume
- //
- ShellGetFileSize (SourceHandle, &SourceFileSize);
- ShellGetFileSize (DestHandle, &DestFileSize);
-
- //
- // if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space
- //
- if (DestFileSize < SourceFileSize) {
- SourceFileSize -= DestFileSize;
- } else {
- SourceFileSize = 0;
- }
-
- //
- // get the system volume info to check the free space
- //
- DestVolumeFP = ConvertShellHandleToEfiFileProtocol (DestHandle);
- DestVolumeInfo = NULL;
- DestVolumeInfoSize = 0;
- Status = DestVolumeFP->GetInfo (
- DestVolumeFP,
- &gEfiFileSystemInfoGuid,
- &DestVolumeInfoSize,
- DestVolumeInfo
- );
-
- if (Status == EFI_BUFFER_TOO_SMALL) {
- DestVolumeInfo = AllocateZeroPool (DestVolumeInfoSize);
- Status = DestVolumeFP->GetInfo (
- DestVolumeFP,
- &gEfiFileSystemInfoGuid,
- &DestVolumeInfoSize,
- DestVolumeInfo
- );
- }
-
- //
- // check if enough space available on destination drive to complete copy
- //
- if ((DestVolumeInfo != NULL) && (DestVolumeInfo->FreeSpace < SourceFileSize)) {
- //
- // not enough space on destination directory to copy file
- //
- SHELL_FREE_NON_NULL (DestVolumeInfo);
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName);
- return (SHELL_VOLUME_FULL);
- } else {
- //
- // copy data between files
- //
- Buffer = AllocateZeroPool (ReadSize);
- if (Buffer == NULL) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, CmdName);
- return SHELL_OUT_OF_RESOURCES;
- }
-
- while (ReadSize == PcdGet32 (PcdShellFileOperationSize) && !EFI_ERROR (Status)) {
- Status = ShellReadFile (SourceHandle, &ReadSize, Buffer);
- if (!EFI_ERROR (Status)) {
- Status = ShellWriteFile (DestHandle, &ReadSize, Buffer);
- if (EFI_ERROR (Status)) {
- ShellStatus = (SHELL_STATUS)(Status & (~MAX_BIT));
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest);
- break;
- }
- } else {
- ShellStatus = (SHELL_STATUS)(Status & (~MAX_BIT));
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source);
- break;
- }
- }
- }
-
- SHELL_FREE_NON_NULL (DestVolumeInfo);
- }
-
- //
- // close files
- //
- if (DestHandle != NULL) {
- ShellCloseFile (&DestHandle);
- DestHandle = NULL;
- }
-
- if (SourceHandle != NULL) {
- ShellCloseFile (&SourceHandle);
- SourceHandle = NULL;
- }
-
- //
- // return
- //
- return ShellStatus;
-}
-
-/**
- function to take a list of files to copy and a destination location and do
- the verification and copying of those files to that location. This function
- will report any errors to the user and halt.
-
- The key is to have this function called ONLY once. this allows for the parameter
- verification to happen correctly.
-
- @param[in] FileList A LIST_ENTRY* based list of files to move.
- @param[in] DestDir The destination location.
- @param[in] SilentMode TRUE to eliminate screen output.
- @param[in] RecursiveMode TRUE to copy directories.
- @param[in] Resp The response to the overwrite query (if always).
-
- @retval SHELL_SUCCESS the files were all moved.
- @retval SHELL_INVALID_PARAMETER a parameter was invalid
- @retval SHELL_SECURITY_VIOLATION a security violation ocurred
- @retval SHELL_WRITE_PROTECTED the destination was write protected
- @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
-**/
-SHELL_STATUS
-ValidateAndCopyFiles (
- IN CONST EFI_SHELL_FILE_INFO *FileList,
- IN CONST CHAR16 *DestDir,
- IN BOOLEAN SilentMode,
- IN BOOLEAN RecursiveMode,
- IN VOID **Resp
- )
-{
- CHAR16 *HiiOutput;
- CHAR16 *HiiResultOk;
- CONST EFI_SHELL_FILE_INFO *Node;
- SHELL_STATUS ShellStatus;
- EFI_STATUS Status;
- CHAR16 *DestPath;
- VOID *Response;
- UINTN PathSize;
- CONST CHAR16 *Cwd;
- UINTN NewSize;
- CHAR16 *CleanFilePathStr;
-
- if (Resp == NULL) {
- Response = NULL;
- } else {
- Response = *Resp;
- }
-
- DestPath = NULL;
- ShellStatus = SHELL_SUCCESS;
- PathSize = 0;
- Cwd = ShellGetCurrentDir (NULL);
- CleanFilePathStr = NULL;
-
- ASSERT (FileList != NULL);
- ASSERT (DestDir != NULL);
-
- Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr);
- if (EFI_ERROR (Status)) {
- if (Status == EFI_OUT_OF_RESOURCES) {
- return SHELL_OUT_OF_RESOURCES;
- } else {
- return SHELL_INVALID_PARAMETER;
- }
- }
-
- ASSERT (CleanFilePathStr != NULL);
-
- //
- // If we are trying to copy multiple files... make sure we got a directory for the target...
- //
- if (EFI_ERROR (ShellIsDirectory (CleanFilePathStr)) && (FileList->Link.ForwardLink != FileList->Link.BackLink)) {
- //
- // Error for destination not a directory
- //
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
- FreePool (CleanFilePathStr);
- return (SHELL_INVALID_PARAMETER);
- }
-
- for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link)
- ; !IsNull (&FileList->Link, &Node->Link)
- ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &Node->Link)
- )
- {
- //
- // skip the directory traversing stuff...
- //
- if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
- continue;
- }
-
- NewSize = StrSize (CleanFilePathStr);
- NewSize += StrSize (Node->FullName);
- NewSize += (Cwd == NULL) ? 0 : (StrSize (Cwd) + sizeof (CHAR16));
- if (NewSize > PathSize) {
- PathSize = NewSize;
- }
-
- //
- // Make sure got -r if required
- //
- if (!RecursiveMode && !EFI_ERROR (ShellIsDirectory (Node->FullName))) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp");
- FreePool (CleanFilePathStr);
- return (SHELL_INVALID_PARAMETER);
- }
-
- //
- // make sure got dest as dir if needed
- //
- if (!EFI_ERROR (ShellIsDirectory (Node->FullName)) && EFI_ERROR (ShellIsDirectory (CleanFilePathStr))) {
- //
- // Error for destination not a directory
- //
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
- FreePool (CleanFilePathStr);
- return (SHELL_INVALID_PARAMETER);
- }
- }
-
- HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);
- HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
- DestPath = AllocateZeroPool (PathSize);
-
- if ((DestPath == NULL) || (HiiOutput == NULL) || (HiiResultOk == NULL)) {
- SHELL_FREE_NON_NULL (DestPath);
- SHELL_FREE_NON_NULL (HiiOutput);
- SHELL_FREE_NON_NULL (HiiResultOk);
- FreePool (CleanFilePathStr);
- return (SHELL_OUT_OF_RESOURCES);
- }
-
- //
- // Go through the list of files to copy...
- //
- for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link)
- ; !IsNull (&FileList->Link, &Node->Link)
- ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &Node->Link)
- )
- {
- if (ShellGetExecutionBreakFlag ()) {
- break;
- }
-
- ASSERT (Node->FileName != NULL);
- ASSERT (Node->FullName != NULL);
-
- //
- // skip the directory traversing stuff...
- //
- if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
- continue;
- }
-
- if ( (FileList->Link.ForwardLink == FileList->Link.BackLink) // 1 item
- && EFI_ERROR (ShellIsDirectory (CleanFilePathStr)) // not an existing directory
- )
- {
- if (StrStr (CleanFilePathStr, L":") == NULL) {
- //
- // simple copy of a single file
- //
- if (Cwd != NULL) {
- StrCpyS (DestPath, PathSize / sizeof (CHAR16), Cwd);
- StrCatS (DestPath, PathSize / sizeof (CHAR16), L"\\");
- } else {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
- FreePool (CleanFilePathStr);
- return (SHELL_INVALID_PARAMETER);
- }
-
- if ((DestPath[StrLen (DestPath)-1] != L'\\') && (CleanFilePathStr[0] != L'\\')) {
- StrCatS (DestPath, PathSize / sizeof (CHAR16), L"\\");
- } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (CleanFilePathStr[0] == L'\\')) {
- ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
- }
-
- StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
- } else {
- StrCpyS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
- }
- } else {
- //
- // we have multiple files or a directory in the DestDir
- //
-
- //
- // Check for leading slash
- //
- if (CleanFilePathStr[0] == L'\\') {
- //
- // Copy to the root of CWD
- //
- if (Cwd != NULL) {
- StrCpyS (DestPath, PathSize/sizeof (CHAR16), Cwd);
- StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
- } else {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
- FreePool (CleanFilePathStr);
- return (SHELL_INVALID_PARAMETER);
- }
-
- while (PathRemoveLastItem (DestPath)) {
- }
-
- StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr+1);
- StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
- } else if (StrStr (CleanFilePathStr, L":") == NULL) {
- if (Cwd != NULL) {
- StrCpyS (DestPath, PathSize/sizeof (CHAR16), Cwd);
- StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
- } else {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
- FreePool (CleanFilePathStr);
- return (SHELL_INVALID_PARAMETER);
- }
-
- if ((DestPath[StrLen (DestPath)-1] != L'\\') && (CleanFilePathStr[0] != L'\\')) {
- StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
- } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (CleanFilePathStr[0] == L'\\')) {
- ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
- }
-
- StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
- if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] != L'\\') && (Node->FileName[0] != L'\\')) {
- StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
- } else if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] == L'\\') && (Node->FileName[0] == L'\\')) {
- ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
- }
-
- StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
- } else {
- StrCpyS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
- if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] != L'\\') && (Node->FileName[0] != L'\\')) {
- StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
- } else if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] == L'\\') && (Node->FileName[0] == L'\\')) {
- ((CHAR16 *)CleanFilePathStr)[StrLen (CleanFilePathStr)-1] = CHAR_NULL;
- }
-
- StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
- }
- }
-
- //
- // Make sure the path exists
- //
- if (EFI_ERROR (VerifyIntermediateDirectories (DestPath))) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath);
- ShellStatus = SHELL_DEVICE_ERROR;
- break;
- }
-
- if ( !EFI_ERROR (ShellIsDirectory (Node->FullName))
- && !EFI_ERROR (ShellIsDirectory (DestPath))
- && (StrniCmp (Node->FullName, DestPath, StrLen (DestPath)) == 0)
- )
- {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp");
- ShellStatus = SHELL_INVALID_PARAMETER;
- break;
- }
-
- if (StringNoCaseCompare (&Node->FullName, &DestPath) == 0) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
- ShellStatus = SHELL_INVALID_PARAMETER;
- break;
- }
-
- if ( (StrniCmp (Node->FullName, DestPath, StrLen (Node->FullName)) == 0)
- && ((DestPath[StrLen (Node->FullName)] == CHAR_NULL) || (DestPath[StrLen (Node->FullName)] == L'\\'))
- )
- {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
- ShellStatus = SHELL_INVALID_PARAMETER;
- break;
- }
-
- PathCleanUpDirectories (DestPath);
-
- if (!SilentMode) {
- ShellPrintEx (-1, -1, HiiOutput, Node->FullName, DestPath);
- }
-
- //
- // copy single file...
- //
- ShellStatus = CopySingleFile (Node->FullName, DestPath, &Response, SilentMode, L"cp");
- if (ShellStatus != SHELL_SUCCESS) {
- break;
- }
- }
-
- if ((ShellStatus == SHELL_SUCCESS) && (Resp == NULL)) {
- ShellPrintEx (-1, -1, L"%s", HiiResultOk);
- }
-
- SHELL_FREE_NON_NULL (DestPath);
- SHELL_FREE_NON_NULL (HiiOutput);
- SHELL_FREE_NON_NULL (HiiResultOk);
- SHELL_FREE_NON_NULL (CleanFilePathStr);
- if (Resp == NULL) {
- SHELL_FREE_NON_NULL (Response);
- }
-
- return (ShellStatus);
-}
-
-/**
- Validate and if successful copy all the files from the list into
- destination directory.
-
- @param[in] FileList The list of files to copy.
- @param[in] DestDir The directory to copy files to.
- @param[in] SilentMode TRUE to eliminate screen output.
- @param[in] RecursiveMode TRUE to copy directories.
-
- @retval SHELL_INVALID_PARAMETER A parameter was invalid.
- @retval SHELL_SUCCESS The operation was successful.
-**/
-SHELL_STATUS
-ProcessValidateAndCopyFiles (
- IN EFI_SHELL_FILE_INFO *FileList,
- IN CONST CHAR16 *DestDir,
- IN BOOLEAN SilentMode,
- IN BOOLEAN RecursiveMode
- )
-{
- SHELL_STATUS ShellStatus;
- EFI_SHELL_FILE_INFO *List;
- EFI_FILE_INFO *FileInfo;
- CHAR16 *FullName;
-
- List = NULL;
- FullName = NULL;
- FileInfo = NULL;
-
- ShellOpenFileMetaArg ((CHAR16 *)DestDir, EFI_FILE_MODE_READ, &List);
- if ((List != NULL) && (List->Link.ForwardLink != List->Link.BackLink)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir);
- ShellStatus = SHELL_INVALID_PARAMETER;
- ShellCloseFileMetaArg (&List);
- } else if (List != NULL) {
- ASSERT (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
- ASSERT (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
- FileInfo = gEfiShellProtocol->GetFileInfo (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
- ASSERT (FileInfo != NULL);
- StrnCatGrow (&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);
- ShellCloseFileMetaArg (&List);
- if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
- ShellStatus = ValidateAndCopyFiles (FileList, FullName, SilentMode, RecursiveMode, NULL);
- } else {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp");
- ShellStatus = SHELL_ACCESS_DENIED;
- }
- } else {
- ShellCloseFileMetaArg (&List);
- ShellStatus = ValidateAndCopyFiles (FileList, DestDir, SilentMode, RecursiveMode, NULL);
- }
-
- SHELL_FREE_NON_NULL (FileInfo);
- SHELL_FREE_NON_NULL (FullName);
- return (ShellStatus);
-}
-
-STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
- { L"-r", TypeFlag },
- { L"-q", TypeFlag },
- { NULL, TypeMax }
-};
-
-/**
- Function for 'cp' command.
-
- @param[in] ImageHandle Handle to the Image (NULL if Internal).
- @param[in] SystemTable Pointer to the System Table (NULL if Internal).
-**/
-SHELL_STATUS
-EFIAPI
-ShellCommandRunCp (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Package;
- CHAR16 *ProblemParam;
- SHELL_STATUS ShellStatus;
- UINTN ParamCount;
- UINTN LoopCounter;
- EFI_SHELL_FILE_INFO *FileList;
- BOOLEAN SilentMode;
- BOOLEAN RecursiveMode;
- CONST CHAR16 *Cwd;
- CHAR16 *FullCwd;
-
- ProblemParam = NULL;
- ShellStatus = SHELL_SUCCESS;
- ParamCount = 0;
- FileList = NULL;
-
- //
- // initialize the shell lib (we must be in non-auto-init...)
- //
- Status = ShellInitialize ();
- ASSERT_EFI_ERROR (Status);
-
- Status = CommandInit ();
- ASSERT_EFI_ERROR (Status);
-
- //
- // parse the command line
- //
- Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
- if (EFI_ERROR (Status)) {
- if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam);
- FreePool (ProblemParam);
- ShellStatus = SHELL_INVALID_PARAMETER;
- } else {
- ASSERT (FALSE);
- }
- } else {
- //
- // check for "-?"
- //
- if (ShellCommandLineGetFlag (Package, L"-?")) {
- ASSERT (FALSE);
- }
-
- //
- // Initialize SilentMode and RecursiveMode
- //
- if (gEfiShellProtocol->BatchIsActive ()) {
- SilentMode = TRUE;
- } else {
- SilentMode = ShellCommandLineGetFlag (Package, L"-q");
- }
-
- RecursiveMode = ShellCommandLineGetFlag (Package, L"-r");
-
- switch (ParamCount = ShellCommandLineGetCount (Package)) {
- case 0:
- case 1:
- //
- // we have insufficient parameters
- //
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp");
- ShellStatus = SHELL_INVALID_PARAMETER;
- break;
- case 2:
- //
- // must have valid CWD for single parameter...
- //
- Cwd = ShellGetCurrentDir (NULL);
- if (Cwd == NULL) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp");
- ShellStatus = SHELL_INVALID_PARAMETER;
- } else {
- Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
- if ((FileList == NULL) || IsListEmpty (&FileList->Link) || EFI_ERROR (Status)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, 1));
- ShellStatus = SHELL_NOT_FOUND;
- } else {
- FullCwd = AllocateZeroPool (StrSize (Cwd) + sizeof (CHAR16));
- if (FullCwd == NULL) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cp");
- ShellStatus = SHELL_OUT_OF_RESOURCES;
- } else {
- StrCpyS (FullCwd, StrSize (Cwd) / sizeof (CHAR16) + 1, Cwd);
- ShellStatus = ProcessValidateAndCopyFiles (FileList, FullCwd, SilentMode, RecursiveMode);
- FreePool (FullCwd);
- }
- }
- }
-
- break;
- default:
- //
- // Make a big list of all the files...
- //
- for (ParamCount--, LoopCounter = 1; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS; LoopCounter++) {
- if (ShellGetExecutionBreakFlag ()) {
- break;
- }
-
- Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
- if (EFI_ERROR (Status) || (FileList == NULL) || IsListEmpty (&FileList->Link)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, LoopCounter));
- ShellStatus = SHELL_NOT_FOUND;
- }
- }
-
- if (ShellStatus != SHELL_SUCCESS) {
- Status = ShellCloseFileMetaArg (&FileList);
- } else {
- //
- // now copy them all...
- //
- if ((FileList != NULL) && !IsListEmpty (&FileList->Link)) {
- ShellStatus = ProcessValidateAndCopyFiles (FileList, PathCleanUpDirectories ((CHAR16 *)ShellCommandLineGetRawValue (Package, ParamCount)), SilentMode, RecursiveMode);
- Status = ShellCloseFileMetaArg (&FileList);
- if (EFI_ERROR (Status) && (ShellStatus == SHELL_SUCCESS)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, ParamCount), ShellStatus|MAX_BIT);
- ShellStatus = SHELL_ACCESS_DENIED;
- }
- }
- }
-
- break;
- } // switch on parameter count
-
- if (FileList != NULL) {
- ShellCloseFileMetaArg (&FileList);
- }
-
- //
- // free the command line package
- //
- ShellCommandLineFreeVarList (Package);
- }
-
- if (ShellGetExecutionBreakFlag ()) {
- return (SHELL_ABORTED);
- }
-
- return (ShellStatus);
-}
+/** @file
+ Main file for cp shell level 2 function.
+
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "UefiShellLevel2CommandsLib.h"
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+
+/**
+ Function to take a list of files to copy and a destination location and do
+ the verification and copying of those files to that location. This function
+ will report any errors to the user and halt.
+
+ @param[in] FileList A LIST_ENTRY* based list of files to move.
+ @param[in] DestDir The destination location.
+ @param[in] SilentMode TRUE to eliminate screen output.
+ @param[in] RecursiveMode TRUE to copy directories.
+ @param[in] Resp The response to the overwrite query (if always).
+
+ @retval SHELL_SUCCESS the files were all moved.
+ @retval SHELL_INVALID_PARAMETER a parameter was invalid
+ @retval SHELL_SECURITY_VIOLATION a security violation ocurred
+ @retval SHELL_WRITE_PROTECTED the destination was write protected
+ @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
+**/
+SHELL_STATUS
+ValidateAndCopyFiles (
+ IN CONST EFI_SHELL_FILE_INFO *FileList,
+ IN CONST CHAR16 *DestDir,
+ IN BOOLEAN SilentMode,
+ IN BOOLEAN RecursiveMode,
+ IN VOID **Resp
+ );
+
+/**
+ Function to Copy one file to another location
+
+ If the destination exists the user will be prompted and the result put into *resp
+
+ @param[in] Source pointer to source file name
+ @param[in] Dest pointer to destination file name
+ @param[out] Resp pointer to response from question. Pass back on looped calling
+ @param[in] SilentMode whether to run in quiet mode or not
+ @param[in] CmdName Source command name requesting single file copy
+
+ @retval SHELL_SUCCESS The source file was copied to the destination
+**/
+SHELL_STATUS
+CopySingleFile (
+ IN CONST CHAR16 *Source,
+ IN CONST CHAR16 *Dest,
+ OUT VOID **Resp,
+ IN BOOLEAN SilentMode,
+ IN CONST CHAR16 *CmdName
+ )
+{
+ VOID *Response;
+ UINTN ReadSize;
+ SHELL_FILE_HANDLE SourceHandle;
+ SHELL_FILE_HANDLE DestHandle;
+ EFI_STATUS Status;
+ VOID *Buffer;
+ CHAR16 *TempName;
+ UINTN Size;
+ EFI_SHELL_FILE_INFO *List;
+ SHELL_STATUS ShellStatus;
+ UINT64 SourceFileSize;
+ UINT64 DestFileSize;
+ EFI_FILE_PROTOCOL *DestVolumeFP;
+ EFI_FILE_SYSTEM_INFO *DestVolumeInfo;
+ UINTN DestVolumeInfoSize;
+
+ ASSERT (Resp != NULL);
+
+ SourceHandle = NULL;
+ DestHandle = NULL;
+ Response = *Resp;
+ List = NULL;
+ DestVolumeInfo = NULL;
+ ShellStatus = SHELL_SUCCESS;
+
+ ReadSize = PcdGet32 (PcdShellFileOperationSize);
+ // Why bother copying a file to itself
+ if (StrCmp (Source, Dest) == 0) {
+ return (SHELL_SUCCESS);
+ }
+
+ //
+ // if the destination file existed check response and possibly prompt user
+ //
+ if (ShellFileExists (Dest) == EFI_SUCCESS) {
+ if ((Response == NULL) && !SilentMode) {
+ Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
+ }
+
+ //
+ // possibly return based on response
+ //
+ if (!SilentMode) {
+ if (Response == NULL) {
+ return SHELL_ABORTED;
+ }
+
+ switch (*(SHELL_PROMPT_RESPONSE *)Response) {
+ case ShellPromptResponseNo:
+ //
+ // return success here so we dont stop the process
+ //
+ return (SHELL_SUCCESS);
+ case ShellPromptResponseCancel:
+ *Resp = Response;
+ //
+ // indicate to stop everything
+ //
+ return (SHELL_ABORTED);
+ case ShellPromptResponseAll:
+ *Resp = Response;
+ case ShellPromptResponseYes:
+ break;
+ default:
+ return SHELL_ABORTED;
+ }
+ }
+ }
+
+ if (ShellIsDirectory (Source) == EFI_SUCCESS) {
+ Status = ShellCreateDirectory (Dest, &DestHandle);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
+ return (SHELL_ACCESS_DENIED);
+ }
+
+ //
+ // Now copy all the files under the directory...
+ //
+ TempName = NULL;
+ Size = 0;
+ StrnCatGrow (&TempName, &Size, Source, 0);
+ StrnCatGrow (&TempName, &Size, L"\\*", 0);
+ if (TempName != NULL) {
+ ShellOpenFileMetaArg ((CHAR16 *)TempName, EFI_FILE_MODE_READ, &List);
+ *TempName = CHAR_NULL;
+ StrnCatGrow (&TempName, &Size, Dest, 0);
+ StrnCatGrow (&TempName, &Size, L"\\", 0);
+ ShellStatus = ValidateAndCopyFiles (List, TempName, SilentMode, TRUE, Resp);
+ ShellCloseFileMetaArg (&List);
+ SHELL_FREE_NON_NULL (TempName);
+ Size = 0;
+ }
+ } else {
+ Status = ShellDeleteFileByName (Dest);
+
+ //
+ // open file with create enabled
+ //
+ Status = ShellOpenFileByName (Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
+ return (SHELL_ACCESS_DENIED);
+ }
+
+ //
+ // open source file
+ //
+ Status = ShellOpenFileByName (Source, &SourceHandle, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source);
+ return (SHELL_ACCESS_DENIED);
+ }
+
+ //
+ // get file size of source file and freespace available on destination volume
+ //
+ ShellGetFileSize (SourceHandle, &SourceFileSize);
+ ShellGetFileSize (DestHandle, &DestFileSize);
+
+ //
+ // if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space
+ //
+ if (DestFileSize < SourceFileSize) {
+ SourceFileSize -= DestFileSize;
+ } else {
+ SourceFileSize = 0;
+ }
+
+ //
+ // get the system volume info to check the free space
+ //
+ DestVolumeFP = ConvertShellHandleToEfiFileProtocol (DestHandle);
+ DestVolumeInfo = NULL;
+ DestVolumeInfoSize = 0;
+ Status = DestVolumeFP->GetInfo (
+ DestVolumeFP,
+ &gEfiFileSystemInfoGuid,
+ &DestVolumeInfoSize,
+ DestVolumeInfo
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ DestVolumeInfo = AllocateZeroPool (DestVolumeInfoSize);
+ Status = DestVolumeFP->GetInfo (
+ DestVolumeFP,
+ &gEfiFileSystemInfoGuid,
+ &DestVolumeInfoSize,
+ DestVolumeInfo
+ );
+ }
+
+ //
+ // check if enough space available on destination drive to complete copy
+ //
+ if ((DestVolumeInfo != NULL) && (DestVolumeInfo->FreeSpace < SourceFileSize)) {
+ //
+ // not enough space on destination directory to copy file
+ //
+ SHELL_FREE_NON_NULL (DestVolumeInfo);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName);
+ return (SHELL_VOLUME_FULL);
+ } else {
+ //
+ // copy data between files
+ //
+ Buffer = AllocateZeroPool (ReadSize);
+ if (Buffer == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, CmdName);
+ return SHELL_OUT_OF_RESOURCES;
+ }
+
+ while (ReadSize == PcdGet32 (PcdShellFileOperationSize) && !EFI_ERROR (Status)) {
+ Status = ShellReadFile (SourceHandle, &ReadSize, Buffer);
+ if (!EFI_ERROR (Status)) {
+ Status = ShellWriteFile (DestHandle, &ReadSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ ShellStatus = (SHELL_STATUS)(Status & (~MAX_BIT));
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest);
+ break;
+ }
+ } else {
+ ShellStatus = (SHELL_STATUS)(Status & (~MAX_BIT));
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source);
+ break;
+ }
+ }
+ }
+
+ SHELL_FREE_NON_NULL (DestVolumeInfo);
+ }
+
+ //
+ // close files
+ //
+ if (DestHandle != NULL) {
+ ShellCloseFile (&DestHandle);
+ DestHandle = NULL;
+ }
+
+ if (SourceHandle != NULL) {
+ ShellCloseFile (&SourceHandle);
+ SourceHandle = NULL;
+ }
+
+ //
+ // return
+ //
+ return ShellStatus;
+}
+
+/**
+ function to take a list of files to copy and a destination location and do
+ the verification and copying of those files to that location. This function
+ will report any errors to the user and halt.
+
+ The key is to have this function called ONLY once. this allows for the parameter
+ verification to happen correctly.
+
+ @param[in] FileList A LIST_ENTRY* based list of files to move.
+ @param[in] DestDir The destination location.
+ @param[in] SilentMode TRUE to eliminate screen output.
+ @param[in] RecursiveMode TRUE to copy directories.
+ @param[in] Resp The response to the overwrite query (if always).
+
+ @retval SHELL_SUCCESS the files were all moved.
+ @retval SHELL_INVALID_PARAMETER a parameter was invalid
+ @retval SHELL_SECURITY_VIOLATION a security violation ocurred
+ @retval SHELL_WRITE_PROTECTED the destination was write protected
+ @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
+**/
+SHELL_STATUS
+ValidateAndCopyFiles (
+ IN CONST EFI_SHELL_FILE_INFO *FileList,
+ IN CONST CHAR16 *DestDir,
+ IN BOOLEAN SilentMode,
+ IN BOOLEAN RecursiveMode,
+ IN VOID **Resp
+ )
+{
+ CHAR16 *HiiOutput;
+ CHAR16 *HiiResultOk;
+ CONST EFI_SHELL_FILE_INFO *Node;
+ SHELL_STATUS ShellStatus;
+ EFI_STATUS Status;
+ CHAR16 *DestPath;
+ VOID *Response;
+ UINTN PathSize;
+ CONST CHAR16 *Cwd;
+ UINTN NewSize;
+ CHAR16 *CleanFilePathStr;
+
+ if (Resp == NULL) {
+ Response = NULL;
+ } else {
+ Response = *Resp;
+ }
+
+ DestPath = NULL;
+ ShellStatus = SHELL_SUCCESS;
+ PathSize = 0;
+ Cwd = ShellGetCurrentDir (NULL);
+ CleanFilePathStr = NULL;
+
+ ASSERT (FileList != NULL);
+ ASSERT (DestDir != NULL);
+
+ Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ return SHELL_OUT_OF_RESOURCES;
+ } else {
+ return SHELL_INVALID_PARAMETER;
+ }
+ }
+
+ ASSERT (CleanFilePathStr != NULL);
+
+ //
+ // If we are trying to copy multiple files... make sure we got a directory for the target...
+ //
+ if (EFI_ERROR (ShellIsDirectory (CleanFilePathStr)) && (FileList->Link.ForwardLink != FileList->Link.BackLink)) {
+ //
+ // Error for destination not a directory
+ //
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
+ FreePool (CleanFilePathStr);
+ return (SHELL_INVALID_PARAMETER);
+ }
+
+ for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link)
+ ; !IsNull (&FileList->Link, &Node->Link)
+ ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &Node->Link)
+ )
+ {
+ //
+ // skip the directory traversing stuff...
+ //
+ if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
+ continue;
+ }
+
+ NewSize = StrSize (CleanFilePathStr);
+ NewSize += StrSize (Node->FullName);
+ NewSize += (Cwd == NULL) ? 0 : (StrSize (Cwd) + sizeof (CHAR16));
+ if (NewSize > PathSize) {
+ PathSize = NewSize;
+ }
+
+ //
+ // Make sure got -r if required
+ //
+ if (!RecursiveMode && !EFI_ERROR (ShellIsDirectory (Node->FullName))) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp");
+ FreePool (CleanFilePathStr);
+ return (SHELL_INVALID_PARAMETER);
+ }
+
+ //
+ // make sure got dest as dir if needed
+ //
+ if (!EFI_ERROR (ShellIsDirectory (Node->FullName)) && EFI_ERROR (ShellIsDirectory (CleanFilePathStr))) {
+ //
+ // Error for destination not a directory
+ //
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
+ FreePool (CleanFilePathStr);
+ return (SHELL_INVALID_PARAMETER);
+ }
+ }
+
+ HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);
+ HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
+ DestPath = AllocateZeroPool (PathSize);
+
+ if ((DestPath == NULL) || (HiiOutput == NULL) || (HiiResultOk == NULL)) {
+ SHELL_FREE_NON_NULL (DestPath);
+ SHELL_FREE_NON_NULL (HiiOutput);
+ SHELL_FREE_NON_NULL (HiiResultOk);
+ FreePool (CleanFilePathStr);
+ return (SHELL_OUT_OF_RESOURCES);
+ }
+
+ //
+ // Go through the list of files to copy...
+ //
+ for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link)
+ ; !IsNull (&FileList->Link, &Node->Link)
+ ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &Node->Link)
+ )
+ {
+ if (ShellGetExecutionBreakFlag ()) {
+ break;
+ }
+
+ ASSERT (Node->FileName != NULL);
+ ASSERT (Node->FullName != NULL);
+
+ //
+ // skip the directory traversing stuff...
+ //
+ if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
+ continue;
+ }
+
+ if ( (FileList->Link.ForwardLink == FileList->Link.BackLink) // 1 item
+ && EFI_ERROR (ShellIsDirectory (CleanFilePathStr)) // not an existing directory
+ )
+ {
+ if (StrStr (CleanFilePathStr, L":") == NULL) {
+ //
+ // simple copy of a single file
+ //
+ if (Cwd != NULL) {
+ StrCpyS (DestPath, PathSize / sizeof (CHAR16), Cwd);
+ StrCatS (DestPath, PathSize / sizeof (CHAR16), L"\\");
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
+ FreePool (CleanFilePathStr);
+ return (SHELL_INVALID_PARAMETER);
+ }
+
+ if ((DestPath[StrLen (DestPath)-1] != L'\\') && (CleanFilePathStr[0] != L'\\')) {
+ StrCatS (DestPath, PathSize / sizeof (CHAR16), L"\\");
+ } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (CleanFilePathStr[0] == L'\\')) {
+ ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
+ }
+
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
+ } else {
+ StrCpyS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
+ }
+ } else {
+ //
+ // we have multiple files or a directory in the DestDir
+ //
+
+ //
+ // Check for leading slash
+ //
+ if (CleanFilePathStr[0] == L'\\') {
+ //
+ // Copy to the root of CWD
+ //
+ if (Cwd != NULL) {
+ StrCpyS (DestPath, PathSize/sizeof (CHAR16), Cwd);
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
+ FreePool (CleanFilePathStr);
+ return (SHELL_INVALID_PARAMETER);
+ }
+
+ while (PathRemoveLastItem (DestPath)) {
+ }
+
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr+1);
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
+ } else if (StrStr (CleanFilePathStr, L":") == NULL) {
+ if (Cwd != NULL) {
+ StrCpyS (DestPath, PathSize/sizeof (CHAR16), Cwd);
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
+ FreePool (CleanFilePathStr);
+ return (SHELL_INVALID_PARAMETER);
+ }
+
+ if ((DestPath[StrLen (DestPath)-1] != L'\\') && (CleanFilePathStr[0] != L'\\')) {
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
+ } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (CleanFilePathStr[0] == L'\\')) {
+ ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
+ }
+
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
+ if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] != L'\\') && (Node->FileName[0] != L'\\')) {
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
+ } else if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] == L'\\') && (Node->FileName[0] == L'\\')) {
+ ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
+ }
+
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
+ } else {
+ StrCpyS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
+ if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] != L'\\') && (Node->FileName[0] != L'\\')) {
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
+ } else if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] == L'\\') && (Node->FileName[0] == L'\\')) {
+ ((CHAR16 *)CleanFilePathStr)[StrLen (CleanFilePathStr)-1] = CHAR_NULL;
+ }
+
+ StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
+ }
+ }
+
+ //
+ // Make sure the path exists
+ //
+ if (EFI_ERROR (VerifyIntermediateDirectories (DestPath))) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath);
+ ShellStatus = SHELL_DEVICE_ERROR;
+ break;
+ }
+
+ if ( !EFI_ERROR (ShellIsDirectory (Node->FullName))
+ && !EFI_ERROR (ShellIsDirectory (DestPath))
+ && (StrniCmp (Node->FullName, DestPath, StrLen (DestPath)) == 0)
+ )
+ {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp");
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ break;
+ }
+
+ if (StringNoCaseCompare (&Node->FullName, &DestPath) == 0) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ break;
+ }
+
+ if ( (StrniCmp (Node->FullName, DestPath, StrLen (Node->FullName)) == 0)
+ && ((DestPath[StrLen (Node->FullName)] == CHAR_NULL) || (DestPath[StrLen (Node->FullName)] == L'\\'))
+ )
+ {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ break;
+ }
+
+ PathCleanUpDirectories (DestPath);
+
+ if (!SilentMode) {
+ ShellPrintEx (-1, -1, HiiOutput, Node->FullName, DestPath);
+ }
+
+ //
+ // copy single file...
+ //
+ ShellStatus = CopySingleFile (Node->FullName, DestPath, &Response, SilentMode, L"cp");
+ if (ShellStatus != SHELL_SUCCESS) {
+ break;
+ }
+ }
+
+ if ((ShellStatus == SHELL_SUCCESS) && (Resp == NULL)) {
+ ShellPrintEx (-1, -1, L"%s", HiiResultOk);
+ }
+
+ SHELL_FREE_NON_NULL (DestPath);
+ SHELL_FREE_NON_NULL (HiiOutput);
+ SHELL_FREE_NON_NULL (HiiResultOk);
+ SHELL_FREE_NON_NULL (CleanFilePathStr);
+ if (Resp == NULL) {
+ SHELL_FREE_NON_NULL (Response);
+ }
+
+ return (ShellStatus);
+}
+
+/**
+ Validate and if successful copy all the files from the list into
+ destination directory.
+
+ @param[in] FileList The list of files to copy.
+ @param[in] DestDir The directory to copy files to.
+ @param[in] SilentMode TRUE to eliminate screen output.
+ @param[in] RecursiveMode TRUE to copy directories.
+
+ @retval SHELL_INVALID_PARAMETER A parameter was invalid.
+ @retval SHELL_SUCCESS The operation was successful.
+**/
+SHELL_STATUS
+ProcessValidateAndCopyFiles (
+ IN EFI_SHELL_FILE_INFO *FileList,
+ IN CONST CHAR16 *DestDir,
+ IN BOOLEAN SilentMode,
+ IN BOOLEAN RecursiveMode
+ )
+{
+ SHELL_STATUS ShellStatus;
+ EFI_SHELL_FILE_INFO *List;
+ EFI_FILE_INFO *FileInfo;
+ CHAR16 *FullName;
+
+ List = NULL;
+ FullName = NULL;
+ FileInfo = NULL;
+
+ ShellOpenFileMetaArg ((CHAR16 *)DestDir, EFI_FILE_MODE_READ, &List);
+ if ((List != NULL) && (List->Link.ForwardLink != List->Link.BackLink)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir);
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ ShellCloseFileMetaArg (&List);
+ } else if (List != NULL) {
+ ASSERT (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
+ ASSERT (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
+ FileInfo = gEfiShellProtocol->GetFileInfo (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
+ ASSERT (FileInfo != NULL);
+ StrnCatGrow (&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);
+ ShellCloseFileMetaArg (&List);
+ if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
+ ShellStatus = ValidateAndCopyFiles (FileList, FullName, SilentMode, RecursiveMode, NULL);
+ } else {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp");
+ ShellStatus = SHELL_ACCESS_DENIED;
+ }
+ } else {
+ ShellCloseFileMetaArg (&List);
+ ShellStatus = ValidateAndCopyFiles (FileList, DestDir, SilentMode, RecursiveMode, NULL);
+ }
+
+ SHELL_FREE_NON_NULL (FileInfo);
+ SHELL_FREE_NON_NULL (FullName);
+ return (ShellStatus);
+}
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+ { L"-r", TypeFlag },
+ { L"-q", TypeFlag },
+ { NULL, TypeMax }
+};
+
+/**
+ Function for 'cp' command.
+
+ @param[in] ImageHandle Handle to the Image (NULL if Internal).
+ @param[in] SystemTable Pointer to the System Table (NULL if Internal).
+**/
+SHELL_STATUS
+EFIAPI
+ShellCommandRunCp (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Package;
+ CHAR16 *ProblemParam;
+ SHELL_STATUS ShellStatus;
+ UINTN ParamCount;
+ UINTN LoopCounter;
+ EFI_SHELL_FILE_INFO *FileList;
+ BOOLEAN SilentMode;
+ BOOLEAN RecursiveMode;
+ CONST CHAR16 *Cwd;
+ CHAR16 *FullCwd;
+
+ ProblemParam = NULL;
+ ShellStatus = SHELL_SUCCESS;
+ ParamCount = 0;
+ FileList = NULL;
+
+ //
+ // initialize the shell lib (we must be in non-auto-init...)
+ //
+ Status = ShellInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ Status = CommandInit ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // parse the command line
+ //
+ Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
+ if (EFI_ERROR (Status)) {
+ if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam);
+ FreePool (ProblemParam);
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ } else {
+ ASSERT (FALSE);
+ }
+ } else {
+ //
+ // check for "-?"
+ //
+ if (ShellCommandLineGetFlag (Package, L"-?")) {
+ ASSERT (FALSE);
+ }
+
+ //
+ // Initialize SilentMode and RecursiveMode
+ //
+ if (gEfiShellProtocol->BatchIsActive ()) {
+ SilentMode = TRUE;
+ } else {
+ SilentMode = ShellCommandLineGetFlag (Package, L"-q");
+ }
+
+ RecursiveMode = ShellCommandLineGetFlag (Package, L"-r");
+
+ switch (ParamCount = ShellCommandLineGetCount (Package)) {
+ case 0:
+ case 1:
+ //
+ // we have insufficient parameters
+ //
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp");
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ break;
+ case 2:
+ //
+ // must have valid CWD for single parameter...
+ //
+ Cwd = ShellGetCurrentDir (NULL);
+ if (Cwd == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp");
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ } else {
+ Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
+ if ((FileList == NULL) || IsListEmpty (&FileList->Link) || EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, 1));
+ ShellStatus = SHELL_NOT_FOUND;
+ } else {
+ FullCwd = AllocateZeroPool (StrSize (Cwd) + sizeof (CHAR16));
+ if (FullCwd == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cp");
+ ShellStatus = SHELL_OUT_OF_RESOURCES;
+ } else {
+ StrCpyS (FullCwd, StrSize (Cwd) / sizeof (CHAR16) + 1, Cwd);
+ ShellStatus = ProcessValidateAndCopyFiles (FileList, FullCwd, SilentMode, RecursiveMode);
+ FreePool (FullCwd);
+ }
+ }
+ }
+
+ break;
+ default:
+ //
+ // Make a big list of all the files...
+ //
+ for (ParamCount--, LoopCounter = 1; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS; LoopCounter++) {
+ if (ShellGetExecutionBreakFlag ()) {
+ break;
+ }
+
+ Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
+ if (EFI_ERROR (Status) || (FileList == NULL) || IsListEmpty (&FileList->Link)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, LoopCounter));
+ ShellStatus = SHELL_NOT_FOUND;
+ }
+ }
+
+ if (ShellStatus != SHELL_SUCCESS) {
+ Status = ShellCloseFileMetaArg (&FileList);
+ } else {
+ //
+ // now copy them all...
+ //
+ if ((FileList != NULL) && !IsListEmpty (&FileList->Link)) {
+ ShellStatus = ProcessValidateAndCopyFiles (FileList, PathCleanUpDirectories ((CHAR16 *)ShellCommandLineGetRawValue (Package, ParamCount)), SilentMode, RecursiveMode);
+ Status = ShellCloseFileMetaArg (&FileList);
+ if (EFI_ERROR (Status) && (ShellStatus == SHELL_SUCCESS)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, ParamCount), ShellStatus|MAX_BIT);
+ ShellStatus = SHELL_ACCESS_DENIED;
+ }
+ }
+ }
+
+ break;
+ } // switch on parameter count
+
+ if (FileList != NULL) {
+ ShellCloseFileMetaArg (&FileList);
+ }
+
+ //
+ // free the command line package
+ //
+ ShellCommandLineFreeVarList (Package);
+ }
+
+ if (ShellGetExecutionBreakFlag ()) {
+ return (SHELL_ABORTED);
+ }
+
+ return (ShellStatus);
+}