summaryrefslogtreecommitdiff
path: root/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
diff options
context:
space:
mode:
Diffstat (limited to 'ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c')
-rw-r--r--ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c1782
1 files changed, 891 insertions, 891 deletions
diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
index d93facc6f5..5fe9663454 100644
--- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
+++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
@@ -1,891 +1,891 @@
-/** @file
- Main file for mv shell level 2 function.
-
- (C) Copyright 2013-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"
-
-/**
- function to determine if a move is between file systems.
-
- @param FullName [in] The name of the file to move.
- @param Cwd [in] The current working directory
- @param DestPath [in] The target location to move to
-
- @retval TRUE The move is across file system.
- @retval FALSE The move is within a file system.
-**/
-BOOLEAN
-IsBetweenFileSystem (
- IN CONST CHAR16 *FullName,
- IN CONST CHAR16 *Cwd,
- IN CONST CHAR16 *DestPath
- )
-{
- CHAR16 *Test;
- CHAR16 *Test1;
- UINTN Result;
-
- Test = StrStr (FullName, L":");
- if ((Test == NULL) && (Cwd != NULL)) {
- Test = StrStr (Cwd, L":");
- }
-
- Test1 = StrStr (DestPath, L":");
- if ((Test1 == NULL) && (Cwd != NULL)) {
- Test1 = StrStr (Cwd, L":");
- }
-
- if ((Test1 != NULL) && (Test != NULL)) {
- *Test = CHAR_NULL;
- *Test1 = CHAR_NULL;
- Result = StringNoCaseCompare (&FullName, &DestPath);
- *Test = L':';
- *Test1 = L':';
- if (Result != 0) {
- return (TRUE);
- }
- }
-
- return (FALSE);
-}
-
-/**
- function to determine if SrcPath is valid to mv.
-
- if SrcPath equal CWD then it's invalid.
- if SrcPath is the parent path of CWD then it's invalid.
- is SrcPath is NULL return FALSE.
-
- if CwdPath is NULL then ASSERT()
-
- @param SrcPath [in] The source path.
- @param CwdPath [in] The current working directory.
-
- @retval TRUE The source path is valid.
- @retval FALSE The source path is invalid.
-**/
-BOOLEAN
-IsSoucePathValid (
- IN CONST CHAR16 *SrcPath,
- IN CONST CHAR16 *CwdPath
- )
-{
- CHAR16 *SrcPathBuffer;
- CHAR16 *CwdPathBuffer;
- BOOLEAN Ret;
-
- ASSERT (CwdPath != NULL);
- if (SrcPath == NULL) {
- return FALSE;
- }
-
- Ret = TRUE;
-
- SrcPathBuffer = AllocateCopyPool (StrSize (SrcPath), SrcPath);
- if (SrcPathBuffer == NULL) {
- return FALSE;
- }
-
- CwdPathBuffer = AllocateCopyPool (StrSize (CwdPath), CwdPath);
- if (CwdPathBuffer == NULL) {
- FreePool (SrcPathBuffer);
- return FALSE;
- }
-
- gUnicodeCollation->StrUpr (gUnicodeCollation, SrcPathBuffer);
- gUnicodeCollation->StrUpr (gUnicodeCollation, CwdPathBuffer);
-
- if (SrcPathBuffer[StrLen (SrcPathBuffer) -1] == L'\\') {
- SrcPathBuffer[StrLen (SrcPathBuffer) - 1] = CHAR_NULL;
- }
-
- if (CwdPathBuffer[StrLen (CwdPathBuffer) - 1] == L'\\') {
- CwdPathBuffer[StrLen (CwdPathBuffer) - 1] = CHAR_NULL;
- }
-
- if ((StrCmp (CwdPathBuffer, SrcPathBuffer) == 0) ||
- ((StrStr (CwdPathBuffer, SrcPathBuffer) == CwdPathBuffer) &&
- (CwdPathBuffer[StrLen (SrcPathBuffer)] == L'\\'))
- )
- {
- Ret = FALSE;
- }
-
- FreePool (SrcPathBuffer);
- FreePool (CwdPathBuffer);
-
- return Ret;
-}
-
-/**
- Function to validate that moving a specific file (FileName) to a specific
- location (DestPath) is valid.
-
- This function will verify that the destination is not a subdirectory of
- FullName, that the Current working Directory is not being moved, and that
- the directory is not read only.
-
- if the move is invalid this function will report the error to StdOut.
-
- @param SourcePath [in] The name of the file to move.
- @param Cwd [in] The current working directory
- @param DestPath [in] The target location to move to
- @param Attribute [in] The Attribute of the file
- @param DestAttr [in] The Attribute of the destination
- @param FileStatus [in] The Status of the file when opened
-
- @retval TRUE The move is valid
- @retval FALSE The move is not
-**/
-BOOLEAN
-IsValidMove (
- IN CONST CHAR16 *SourcePath,
- IN CONST CHAR16 *Cwd,
- IN CONST CHAR16 *DestPath,
- IN CONST UINT64 Attribute,
- IN CONST UINT64 DestAttr,
- IN CONST EFI_STATUS FileStatus
- )
-{
- CHAR16 *DestPathCopy;
- CHAR16 *DestPathWalker;
-
- if ((Cwd != NULL) && ((Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)) {
- if (!IsSoucePathValid (SourcePath, Cwd)) {
- //
- // Invalid move
- //
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle);
- return FALSE;
- }
- }
-
- //
- // invalid to move read only or move to a read only destination
- //
- if ( ((Attribute & EFI_FILE_READ_ONLY) != 0)
- || (FileStatus == EFI_WRITE_PROTECTED)
- || ((DestAttr & EFI_FILE_READ_ONLY) != 0)
- )
- {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle, SourcePath);
- return (FALSE);
- }
-
- DestPathCopy = AllocateCopyPool (StrSize (DestPath), DestPath);
- if (DestPathCopy == NULL) {
- return (FALSE);
- }
-
- for (DestPathWalker = DestPathCopy; *DestPathWalker == L'\\'; DestPathWalker++) {
- }
-
- while (DestPathWalker != NULL && DestPathWalker[StrLen (DestPathWalker)-1] == L'\\') {
- DestPathWalker[StrLen (DestPathWalker)-1] = CHAR_NULL;
- }
-
- ASSERT (DestPathWalker != NULL);
- ASSERT (SourcePath != NULL);
-
- //
- // If they're the same, or if source is "above" dest on file path tree
- //
- if ((StringNoCaseCompare (&DestPathWalker, &SourcePath) == 0) ||
- ((StrStr (DestPathWalker, SourcePath) == DestPathWalker) &&
- (DestPathWalker[StrLen (SourcePath)] == '\\')
- )
- )
- {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);
- FreePool (DestPathCopy);
- return (FALSE);
- }
-
- FreePool (DestPathCopy);
-
- return (TRUE);
-}
-
-/**
- Function to take a destination path that might contain wildcards and verify
- that there is only a single possible target (IE we cant have wildcards that
- have 2 possible destination).
-
- if the result is successful the caller must free *DestPathPointer.
-
- @param[in] DestParameter The original path to the destination.
- @param[in, out] DestPathPointer A pointer to the callee allocated final path.
- @param[in] Cwd A pointer to the current working directory.
- @param[in] SingleSource TRUE to have only one source file.
- @param[in, out] DestAttr A pointer to the destination information attribute.
-
- @retval SHELL_INVALID_PARAMETER The DestParameter could not be resolved to a location.
- @retval SHELL_INVALID_PARAMETER The DestParameter could be resolved to more than 1 location.
- @retval SHELL_INVALID_PARAMETER Cwd is required and is NULL.
- @retval SHELL_SUCCESS The operation was successful.
-**/
-SHELL_STATUS
-GetDestinationLocation (
- IN CONST CHAR16 *DestParameter,
- IN OUT CHAR16 **DestPathPointer,
- IN CONST CHAR16 *Cwd,
- IN CONST BOOLEAN SingleSource,
- IN OUT UINT64 *DestAttr
- )
-{
- EFI_SHELL_FILE_INFO *DestList;
- EFI_SHELL_FILE_INFO *Node;
- CHAR16 *DestPath;
- UINTN NewSize;
- UINTN CurrentSize;
-
- DestList = NULL;
- DestPath = NULL;
-
- ASSERT (DestAttr != NULL);
-
- if (StrStr (DestParameter, L"\\") == DestParameter) {
- if (Cwd == NULL) {
- return SHELL_INVALID_PARAMETER;
- }
-
- DestPath = AllocateZeroPool (StrSize (Cwd));
- if (DestPath == NULL) {
- return (SHELL_OUT_OF_RESOURCES);
- }
-
- StrCpyS (DestPath, StrSize (Cwd) / sizeof (CHAR16), Cwd);
- while (PathRemoveLastItem (DestPath)) {
- }
-
- //
- // Append DestParameter beyond '\' which may be present
- //
- CurrentSize = StrSize (DestPath);
- StrnCatGrow (&DestPath, &CurrentSize, &DestParameter[1], 0);
-
- *DestPathPointer = DestPath;
- return (SHELL_SUCCESS);
- }
-
- //
- // get the destination path
- //
- ShellOpenFileMetaArg ((CHAR16 *)DestParameter, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);
- if ((DestList == NULL) || IsListEmpty (&DestList->Link)) {
- //
- // Not existing... must be renaming
- //
- if (StrStr (DestParameter, L":") == NULL) {
- if (Cwd == NULL) {
- ShellCloseFileMetaArg (&DestList);
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
- return (SHELL_INVALID_PARAMETER);
- }
-
- NewSize = StrSize (Cwd);
- NewSize += StrSize (DestParameter);
- DestPath = AllocateZeroPool (NewSize);
- if (DestPath == NULL) {
- ShellCloseFileMetaArg (&DestList);
- return (SHELL_OUT_OF_RESOURCES);
- }
-
- StrCpyS (DestPath, NewSize / sizeof (CHAR16), Cwd);
- if ((DestPath[StrLen (DestPath)-1] != L'\\') && (DestParameter[0] != L'\\')) {
- StrCatS (DestPath, NewSize / sizeof (CHAR16), L"\\");
- } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (DestParameter[0] == L'\\')) {
- ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
- }
-
- StrCatS (DestPath, NewSize / sizeof (CHAR16), DestParameter);
- } else {
- ASSERT (DestPath == NULL);
- DestPath = StrnCatGrow (&DestPath, NULL, DestParameter, 0);
- if (DestPath == NULL) {
- ShellCloseFileMetaArg (&DestList);
- return (SHELL_OUT_OF_RESOURCES);
- }
- }
- } else {
- Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&DestList->Link);
- *DestAttr = Node->Info->Attribute;
- //
- // Make sure there is only 1 node in the list.
- //
- if (!IsNodeAtEnd (&DestList->Link, &Node->Link)) {
- ShellCloseFileMetaArg (&DestList);
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);
- return (SHELL_INVALID_PARAMETER);
- }
-
- //
- // If we are a directory or a single file, then one node is fine.
- //
- if ((ShellIsDirectory (Node->FullName) == EFI_SUCCESS) || SingleSource) {
- DestPath = AllocateZeroPool (StrSize (Node->FullName)+sizeof (CHAR16));
- if (DestPath == NULL) {
- ShellCloseFileMetaArg (&DestList);
- return (SHELL_OUT_OF_RESOURCES);
- }
-
- StrCpyS (DestPath, (StrSize (Node->FullName)+sizeof (CHAR16)) / sizeof (CHAR16), Node->FullName);
- StrCatS (DestPath, (StrSize (Node->FullName)+sizeof (CHAR16)) / sizeof (CHAR16), L"\\");
- } else {
- //
- // cant move multiple files onto a single file.
- //
- ShellCloseFileMetaArg (&DestList);
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);
- return (SHELL_INVALID_PARAMETER);
- }
- }
-
- *DestPathPointer = DestPath;
- ShellCloseFileMetaArg (&DestList);
-
- return (SHELL_SUCCESS);
-}
-
-/**
- Function to do a move across file systems.
-
- @param[in] Node A pointer to the file to be removed.
- @param[in] DestPath A pointer to the destination file path.
- @param[out] Resp A pointer to response from question. Pass back on looped calling
-
- @retval SHELL_SUCCESS The source file was moved to the destination.
-**/
-EFI_STATUS
-MoveBetweenFileSystems (
- IN EFI_SHELL_FILE_INFO *Node,
- IN CONST CHAR16 *DestPath,
- OUT VOID **Resp
- )
-{
- SHELL_STATUS ShellStatus;
-
- //
- // First we copy the file
- //
- ShellStatus = CopySingleFile (Node->FullName, DestPath, Resp, TRUE, L"mv");
-
- //
- // Check our result
- //
- if (ShellStatus == SHELL_SUCCESS) {
- //
- // The copy was successful. delete the source file.
- //
- CascadeDelete (Node, TRUE);
- Node->Handle = NULL;
- } else if (ShellStatus == SHELL_ABORTED) {
- return EFI_ABORTED;
- } else if (ShellStatus == SHELL_ACCESS_DENIED) {
- return EFI_ACCESS_DENIED;
- } else if (ShellStatus == SHELL_VOLUME_FULL) {
- return EFI_VOLUME_FULL;
- } else {
- return EFI_UNSUPPORTED;
- }
-
- return (EFI_SUCCESS);
-}
-
-/**
- Function to take the destination path and target file name to generate the full destination path.
-
- @param[in] DestPath A pointer to the destination file path string.
- @param[out] FullDestPath A pointer to the full destination path string.
- @param[in] FileName Name string of the targe file.
-
- @retval SHELL_SUCCESS the files were all moved.
- @retval SHELL_INVALID_PARAMETER a parameter was invalid
- @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
-**/
-EFI_STATUS
-CreateFullDestPath (
- IN CONST CHAR16 **DestPath,
- OUT CHAR16 **FullDestPath,
- IN CONST CHAR16 *FileName
- )
-{
- UINTN Size;
-
- if ((FullDestPath == NULL) || (FileName == NULL) || (DestPath == NULL) || (*DestPath == NULL)) {
- return (EFI_INVALID_PARAMETER);
- }
-
- Size = StrSize (*DestPath) + StrSize (FileName);
-
- *FullDestPath = AllocateZeroPool (Size);
- if (*FullDestPath == NULL) {
- return (EFI_OUT_OF_RESOURCES);
- }
-
- StrCpyS (*FullDestPath, Size / sizeof (CHAR16), *DestPath);
- if (((*FullDestPath)[StrLen (*FullDestPath)-1] != L'\\') && (FileName[0] != L'\\')) {
- StrCatS (*FullDestPath, Size / sizeof (CHAR16), L"\\");
- }
-
- StrCatS (*FullDestPath, Size / sizeof (CHAR16), FileName);
-
- return (EFI_SUCCESS);
-}
-
-/**
- Function to do a move within a file system.
-
- @param[in] Node A pointer to the file to be removed.
- @param[in] DestPath A pointer to the destination file path.
- @param[out] Resp A pointer to response from question. Pass back on looped calling.
-
- @retval SHELL_SUCCESS The source file was moved to the destination.
- @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
-**/
-EFI_STATUS
-MoveWithinFileSystems (
- IN EFI_SHELL_FILE_INFO *Node,
- IN CHAR16 *DestPath,
- OUT VOID **Resp
- )
-{
- EFI_FILE_INFO *NewFileInfo;
- CHAR16 *TempLocation;
- UINTN NewSize;
- UINTN Length;
- EFI_STATUS Status;
-
- //
- // Chop off map info from DestPath
- //
- if ((TempLocation = StrStr (DestPath, L":")) != NULL) {
- CopyMem (DestPath, TempLocation+1, StrSize (TempLocation+1));
- }
-
- //
- // construct the new file info block
- //
- NewSize = StrSize (DestPath);
- NewSize += StrSize (Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof (CHAR16);
- NewFileInfo = AllocateZeroPool (NewSize);
- if (NewFileInfo == NULL) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);
- Status = EFI_OUT_OF_RESOURCES;
- } else {
- CopyMem (NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO);
- if (DestPath[0] != L'\\') {
- StrCpyS (NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16), L"\\");
- StrCatS (NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16), DestPath);
- } else {
- StrCpyS (NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16), DestPath);
- }
-
- Length = StrLen (NewFileInfo->FileName);
- if (Length > 0) {
- Length--;
- }
-
- if (NewFileInfo->FileName[Length] == L'\\') {
- if (Node->FileName[0] == L'\\') {
- //
- // Don't allow for double slashes. Eliminate one of them.
- //
- NewFileInfo->FileName[Length] = CHAR_NULL;
- }
-
- StrCatS (NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16), Node->FileName);
- }
-
- NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize (NewFileInfo->FileName);
-
- //
- // Perform the move operation
- //
- Status = ShellSetFileInfo (Node->Handle, NewFileInfo);
-
- //
- // Free the info object we used...
- //
- FreePool (NewFileInfo);
- }
-
- return (Status);
-}
-
-/**
- function to take a list of files to move and a destination location and do
- the verification and moving of those files to that location. This function
- will report any errors to the user and continue to move the rest of the files.
-
- @param[in] FileList A LIST_ENTRY* based list of files to move
- @param[out] Resp pointer to response from question. Pass back on looped calling
- @param[in] DestParameter the originally specified destination location
-
- @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
-ValidateAndMoveFiles (
- IN EFI_SHELL_FILE_INFO *FileList,
- OUT VOID **Resp,
- IN CONST CHAR16 *DestParameter
- )
-{
- EFI_STATUS Status;
- CHAR16 *HiiOutput;
- CHAR16 *HiiResultOk;
- CHAR16 *DestPath;
- CHAR16 *FullDestPath;
- CONST CHAR16 *Cwd;
- CHAR16 *FullCwd;
- SHELL_STATUS ShellStatus;
- EFI_SHELL_FILE_INFO *Node;
- VOID *Response;
- UINT64 Attr;
- CHAR16 *CleanFilePathStr;
-
- ASSERT (FileList != NULL);
- ASSERT (DestParameter != NULL);
-
- DestPath = NULL;
- FullDestPath = NULL;
- Cwd = ShellGetCurrentDir (NULL);
- Response = *Resp;
- Attr = 0;
- CleanFilePathStr = NULL;
- FullCwd = NULL;
-
- if (Cwd != NULL) {
- FullCwd = AllocateZeroPool (StrSize (Cwd) + sizeof (CHAR16));
- if (FullCwd == NULL) {
- return SHELL_OUT_OF_RESOURCES;
- } else {
- StrCpyS (FullCwd, StrSize (Cwd)/sizeof (CHAR16)+1, Cwd);
- StrCatS (FullCwd, StrSize (Cwd)/sizeof (CHAR16)+1, L"\\");
- }
- }
-
- Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr);
- if (EFI_ERROR (Status)) {
- SHELL_FREE_NON_NULL (FullCwd);
- if (Status == EFI_OUT_OF_RESOURCES) {
- return SHELL_OUT_OF_RESOURCES;
- } else {
- return SHELL_INVALID_PARAMETER;
- }
- }
-
- ASSERT (CleanFilePathStr != NULL);
-
- //
- // Get and validate the destination location
- //
- ShellStatus = GetDestinationLocation (CleanFilePathStr, &DestPath, FullCwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr);
- FreePool (CleanFilePathStr);
-
- if (ShellStatus != SHELL_SUCCESS) {
- SHELL_FREE_NON_NULL (FullCwd);
- return (ShellStatus);
- }
-
- DestPath = PathCleanUpDirectories (DestPath);
- if (DestPath == NULL) {
- FreePool (FullCwd);
- return (SHELL_OUT_OF_RESOURCES);
- }
-
- HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);
- HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
- if ((HiiOutput == NULL) || (HiiResultOk == NULL)) {
- SHELL_FREE_NON_NULL (DestPath);
- SHELL_FREE_NON_NULL (HiiOutput);
- SHELL_FREE_NON_NULL (HiiResultOk);
- SHELL_FREE_NON_NULL (FullCwd);
- return (SHELL_OUT_OF_RESOURCES);
- }
-
- //
- // Go through the list of files and directories to move...
- //
- 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;
- }
-
- //
- // These should never be NULL
- //
- ASSERT (Node->FileName != NULL);
- ASSERT (Node->FullName != NULL);
- ASSERT (Node->Info != NULL);
-
- //
- // skip the directory traversing stuff...
- //
- if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
- continue;
- }
-
- SHELL_FREE_NON_NULL (FullDestPath);
- FullDestPath = NULL;
- if (ShellIsDirectory (DestPath) == EFI_SUCCESS) {
- CreateFullDestPath ((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName);
- }
-
- //
- // Validate that the move is valid
- //
- if (!IsValidMove (Node->FullName, FullCwd, (FullDestPath != NULL) ? FullDestPath : DestPath, Node->Info->Attribute, Attr, Node->Status)) {
- ShellStatus = SHELL_INVALID_PARAMETER;
- continue;
- }
-
- ShellPrintEx (-1, -1, HiiOutput, Node->FullName, FullDestPath != NULL ? FullDestPath : DestPath);
-
- //
- // See if destination exists
- //
- if (!EFI_ERROR (ShellFileExists ((FullDestPath != NULL) ? FullDestPath : DestPath))) {
- if (Response == NULL) {
- ShellPromptForResponseHii (ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
- }
-
- if (Response == NULL) {
- return SHELL_ABORTED;
- }
-
- switch (*(SHELL_PROMPT_RESPONSE *)Response) {
- case ShellPromptResponseNo:
- FreePool (Response);
- Response = NULL;
- continue;
- case ShellPromptResponseCancel:
- *Resp = Response;
- //
- // indicate to stop everything
- //
- SHELL_FREE_NON_NULL (FullCwd);
- return (SHELL_ABORTED);
- case ShellPromptResponseAll:
- *Resp = Response;
- break;
- case ShellPromptResponseYes:
- FreePool (Response);
- Response = NULL;
- break;
- default:
- FreePool (Response);
- SHELL_FREE_NON_NULL (FullCwd);
- return SHELL_ABORTED;
- }
-
- Status = ShellDeleteFileByName (FullDestPath != NULL ? FullDestPath : DestPath);
- }
-
- if (IsBetweenFileSystem (Node->FullName, FullCwd, DestPath)) {
- while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen (DestPath) - 1] == L'\\') {
- DestPath[StrLen (DestPath) - 1] = CHAR_NULL;
- }
-
- Status = MoveBetweenFileSystems (Node, FullDestPath != NULL ? FullDestPath : DestPath, &Response);
- } else {
- Status = MoveWithinFileSystems (Node, DestPath, &Response);
- //
- // Display error status
- //
- if (EFI_ERROR (Status)) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"mv", Status);
- }
- }
-
- //
- // Check our result
- //
- if (EFI_ERROR (Status)) {
- ShellStatus = SHELL_INVALID_PARAMETER;
- if (Status == EFI_SECURITY_VIOLATION) {
- ShellStatus = SHELL_SECURITY_VIOLATION;
- } else if (Status == EFI_WRITE_PROTECTED) {
- ShellStatus = SHELL_WRITE_PROTECTED;
- } else if (Status == EFI_OUT_OF_RESOURCES) {
- ShellStatus = SHELL_OUT_OF_RESOURCES;
- } else if (Status == EFI_DEVICE_ERROR) {
- ShellStatus = SHELL_DEVICE_ERROR;
- } else if (Status == EFI_ACCESS_DENIED) {
- ShellStatus = SHELL_ACCESS_DENIED;
- }
- } else {
- ShellPrintEx (-1, -1, L"%s", HiiResultOk);
- }
- } // main for loop
-
- SHELL_FREE_NON_NULL (FullDestPath);
- SHELL_FREE_NON_NULL (DestPath);
- SHELL_FREE_NON_NULL (HiiOutput);
- SHELL_FREE_NON_NULL (HiiResultOk);
- SHELL_FREE_NON_NULL (FullCwd);
- return (ShellStatus);
-}
-
-/**
- Function for 'mv' 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
-ShellCommandRunMv (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
- LIST_ENTRY *Package;
- CHAR16 *ProblemParam;
- CHAR16 *Cwd;
- UINTN CwdSize;
- SHELL_STATUS ShellStatus;
- UINTN ParamCount;
- UINTN LoopCounter;
- EFI_SHELL_FILE_INFO *FileList;
- VOID *Response;
-
- ProblemParam = NULL;
- ShellStatus = SHELL_SUCCESS;
- ParamCount = 0;
- FileList = NULL;
- Response = NULL;
-
- //
- // initialize the shell lib (we must be in non-auto-init...)
- //
- Status = ShellInitialize ();
- ASSERT_EFI_ERROR (Status);
-
- //
- // parse the command line
- //
- Status = ShellCommandLineParse (EmptyParamList, &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"mv", ProblemParam);
- FreePool (ProblemParam);
- ShellStatus = SHELL_INVALID_PARAMETER;
- } else {
- ASSERT (FALSE);
- }
- } else {
- //
- // check for "-?"
- //
- if (ShellCommandLineGetFlag (Package, L"-?")) {
- ASSERT (FALSE);
- }
-
- switch (ParamCount = ShellCommandLineGetCount (Package)) {
- case 0:
- case 1:
- //
- // we have insufficient parameters
- //
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mv");
- ShellStatus = SHELL_INVALID_PARAMETER;
- break;
- case 2:
- //
- // must have valid CWD for single parameter...
- //
- if (ShellGetCurrentDir (NULL) == NULL) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"mv");
- 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"mv", ShellCommandLineGetRawValue (Package, 1));
- ShellStatus = SHELL_NOT_FOUND;
- } else {
- //
- // ValidateAndMoveFiles will report errors to the screen itself
- //
- CwdSize = StrSize (ShellGetCurrentDir (NULL)) + sizeof (CHAR16);
- Cwd = AllocateZeroPool (CwdSize);
- if (Cwd == NULL) {
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"mv");
- ShellStatus = SHELL_OUT_OF_RESOURCES;
- } else {
- StrCpyS (Cwd, CwdSize / sizeof (CHAR16), ShellGetCurrentDir (NULL));
- StrCatS (Cwd, CwdSize / sizeof (CHAR16), L"\\");
- ShellStatus = ValidateAndMoveFiles (FileList, &Response, Cwd);
- FreePool (Cwd);
- }
- }
- }
-
- break;
- default:
- /// @todo make sure this works with error half way through and continues...
- for (ParamCount--, LoopCounter = 1; LoopCounter < ParamCount; LoopCounter++) {
- if (ShellGetExecutionBreakFlag ()) {
- break;
- }
-
- Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, LoopCounter), 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"mv", ShellCommandLineGetRawValue (Package, LoopCounter));
- ShellStatus = SHELL_NOT_FOUND;
- } else {
- //
- // ValidateAndMoveFiles will report errors to the screen itself
- // Only change ShellStatus if it's successful
- //
- if (ShellStatus == SHELL_SUCCESS) {
- ShellStatus = ValidateAndMoveFiles (FileList, &Response, ShellCommandLineGetRawValue (Package, ParamCount));
- } else {
- ValidateAndMoveFiles (FileList, &Response, ShellCommandLineGetRawValue (Package, ParamCount));
- }
- }
-
- if ((FileList != NULL) && !IsListEmpty (&FileList->Link)) {
- Status = ShellCloseFileMetaArg (&FileList);
- if (EFI_ERROR (Status) && (ShellStatus == SHELL_SUCCESS)) {
- ShellStatus = SHELL_ACCESS_DENIED;
- ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue (Package, 1), ShellStatus|MAX_BIT);
- }
- }
- }
-
- break;
- } // switch on parameter count
-
- if (FileList != NULL) {
- ShellCloseFileMetaArg (&FileList);
- }
-
- //
- // free the command line package
- //
- ShellCommandLineFreeVarList (Package);
- }
-
- SHELL_FREE_NON_NULL (Response);
-
- if (ShellGetExecutionBreakFlag ()) {
- return (SHELL_ABORTED);
- }
-
- return (ShellStatus);
-}
+/** @file
+ Main file for mv shell level 2 function.
+
+ (C) Copyright 2013-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"
+
+/**
+ function to determine if a move is between file systems.
+
+ @param FullName [in] The name of the file to move.
+ @param Cwd [in] The current working directory
+ @param DestPath [in] The target location to move to
+
+ @retval TRUE The move is across file system.
+ @retval FALSE The move is within a file system.
+**/
+BOOLEAN
+IsBetweenFileSystem (
+ IN CONST CHAR16 *FullName,
+ IN CONST CHAR16 *Cwd,
+ IN CONST CHAR16 *DestPath
+ )
+{
+ CHAR16 *Test;
+ CHAR16 *Test1;
+ UINTN Result;
+
+ Test = StrStr (FullName, L":");
+ if ((Test == NULL) && (Cwd != NULL)) {
+ Test = StrStr (Cwd, L":");
+ }
+
+ Test1 = StrStr (DestPath, L":");
+ if ((Test1 == NULL) && (Cwd != NULL)) {
+ Test1 = StrStr (Cwd, L":");
+ }
+
+ if ((Test1 != NULL) && (Test != NULL)) {
+ *Test = CHAR_NULL;
+ *Test1 = CHAR_NULL;
+ Result = StringNoCaseCompare (&FullName, &DestPath);
+ *Test = L':';
+ *Test1 = L':';
+ if (Result != 0) {
+ return (TRUE);
+ }
+ }
+
+ return (FALSE);
+}
+
+/**
+ function to determine if SrcPath is valid to mv.
+
+ if SrcPath equal CWD then it's invalid.
+ if SrcPath is the parent path of CWD then it's invalid.
+ is SrcPath is NULL return FALSE.
+
+ if CwdPath is NULL then ASSERT()
+
+ @param SrcPath [in] The source path.
+ @param CwdPath [in] The current working directory.
+
+ @retval TRUE The source path is valid.
+ @retval FALSE The source path is invalid.
+**/
+BOOLEAN
+IsSoucePathValid (
+ IN CONST CHAR16 *SrcPath,
+ IN CONST CHAR16 *CwdPath
+ )
+{
+ CHAR16 *SrcPathBuffer;
+ CHAR16 *CwdPathBuffer;
+ BOOLEAN Ret;
+
+ ASSERT (CwdPath != NULL);
+ if (SrcPath == NULL) {
+ return FALSE;
+ }
+
+ Ret = TRUE;
+
+ SrcPathBuffer = AllocateCopyPool (StrSize (SrcPath), SrcPath);
+ if (SrcPathBuffer == NULL) {
+ return FALSE;
+ }
+
+ CwdPathBuffer = AllocateCopyPool (StrSize (CwdPath), CwdPath);
+ if (CwdPathBuffer == NULL) {
+ FreePool (SrcPathBuffer);
+ return FALSE;
+ }
+
+ gUnicodeCollation->StrUpr (gUnicodeCollation, SrcPathBuffer);
+ gUnicodeCollation->StrUpr (gUnicodeCollation, CwdPathBuffer);
+
+ if (SrcPathBuffer[StrLen (SrcPathBuffer) -1] == L'\\') {
+ SrcPathBuffer[StrLen (SrcPathBuffer) - 1] = CHAR_NULL;
+ }
+
+ if (CwdPathBuffer[StrLen (CwdPathBuffer) - 1] == L'\\') {
+ CwdPathBuffer[StrLen (CwdPathBuffer) - 1] = CHAR_NULL;
+ }
+
+ if ((StrCmp (CwdPathBuffer, SrcPathBuffer) == 0) ||
+ ((StrStr (CwdPathBuffer, SrcPathBuffer) == CwdPathBuffer) &&
+ (CwdPathBuffer[StrLen (SrcPathBuffer)] == L'\\'))
+ )
+ {
+ Ret = FALSE;
+ }
+
+ FreePool (SrcPathBuffer);
+ FreePool (CwdPathBuffer);
+
+ return Ret;
+}
+
+/**
+ Function to validate that moving a specific file (FileName) to a specific
+ location (DestPath) is valid.
+
+ This function will verify that the destination is not a subdirectory of
+ FullName, that the Current working Directory is not being moved, and that
+ the directory is not read only.
+
+ if the move is invalid this function will report the error to StdOut.
+
+ @param SourcePath [in] The name of the file to move.
+ @param Cwd [in] The current working directory
+ @param DestPath [in] The target location to move to
+ @param Attribute [in] The Attribute of the file
+ @param DestAttr [in] The Attribute of the destination
+ @param FileStatus [in] The Status of the file when opened
+
+ @retval TRUE The move is valid
+ @retval FALSE The move is not
+**/
+BOOLEAN
+IsValidMove (
+ IN CONST CHAR16 *SourcePath,
+ IN CONST CHAR16 *Cwd,
+ IN CONST CHAR16 *DestPath,
+ IN CONST UINT64 Attribute,
+ IN CONST UINT64 DestAttr,
+ IN CONST EFI_STATUS FileStatus
+ )
+{
+ CHAR16 *DestPathCopy;
+ CHAR16 *DestPathWalker;
+
+ if ((Cwd != NULL) && ((Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)) {
+ if (!IsSoucePathValid (SourcePath, Cwd)) {
+ //
+ // Invalid move
+ //
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle);
+ return FALSE;
+ }
+ }
+
+ //
+ // invalid to move read only or move to a read only destination
+ //
+ if ( ((Attribute & EFI_FILE_READ_ONLY) != 0)
+ || (FileStatus == EFI_WRITE_PROTECTED)
+ || ((DestAttr & EFI_FILE_READ_ONLY) != 0)
+ )
+ {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle, SourcePath);
+ return (FALSE);
+ }
+
+ DestPathCopy = AllocateCopyPool (StrSize (DestPath), DestPath);
+ if (DestPathCopy == NULL) {
+ return (FALSE);
+ }
+
+ for (DestPathWalker = DestPathCopy; *DestPathWalker == L'\\'; DestPathWalker++) {
+ }
+
+ while (DestPathWalker != NULL && DestPathWalker[StrLen (DestPathWalker)-1] == L'\\') {
+ DestPathWalker[StrLen (DestPathWalker)-1] = CHAR_NULL;
+ }
+
+ ASSERT (DestPathWalker != NULL);
+ ASSERT (SourcePath != NULL);
+
+ //
+ // If they're the same, or if source is "above" dest on file path tree
+ //
+ if ((StringNoCaseCompare (&DestPathWalker, &SourcePath) == 0) ||
+ ((StrStr (DestPathWalker, SourcePath) == DestPathWalker) &&
+ (DestPathWalker[StrLen (SourcePath)] == '\\')
+ )
+ )
+ {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);
+ FreePool (DestPathCopy);
+ return (FALSE);
+ }
+
+ FreePool (DestPathCopy);
+
+ return (TRUE);
+}
+
+/**
+ Function to take a destination path that might contain wildcards and verify
+ that there is only a single possible target (IE we cant have wildcards that
+ have 2 possible destination).
+
+ if the result is successful the caller must free *DestPathPointer.
+
+ @param[in] DestParameter The original path to the destination.
+ @param[in, out] DestPathPointer A pointer to the callee allocated final path.
+ @param[in] Cwd A pointer to the current working directory.
+ @param[in] SingleSource TRUE to have only one source file.
+ @param[in, out] DestAttr A pointer to the destination information attribute.
+
+ @retval SHELL_INVALID_PARAMETER The DestParameter could not be resolved to a location.
+ @retval SHELL_INVALID_PARAMETER The DestParameter could be resolved to more than 1 location.
+ @retval SHELL_INVALID_PARAMETER Cwd is required and is NULL.
+ @retval SHELL_SUCCESS The operation was successful.
+**/
+SHELL_STATUS
+GetDestinationLocation (
+ IN CONST CHAR16 *DestParameter,
+ IN OUT CHAR16 **DestPathPointer,
+ IN CONST CHAR16 *Cwd,
+ IN CONST BOOLEAN SingleSource,
+ IN OUT UINT64 *DestAttr
+ )
+{
+ EFI_SHELL_FILE_INFO *DestList;
+ EFI_SHELL_FILE_INFO *Node;
+ CHAR16 *DestPath;
+ UINTN NewSize;
+ UINTN CurrentSize;
+
+ DestList = NULL;
+ DestPath = NULL;
+
+ ASSERT (DestAttr != NULL);
+
+ if (StrStr (DestParameter, L"\\") == DestParameter) {
+ if (Cwd == NULL) {
+ return SHELL_INVALID_PARAMETER;
+ }
+
+ DestPath = AllocateZeroPool (StrSize (Cwd));
+ if (DestPath == NULL) {
+ return (SHELL_OUT_OF_RESOURCES);
+ }
+
+ StrCpyS (DestPath, StrSize (Cwd) / sizeof (CHAR16), Cwd);
+ while (PathRemoveLastItem (DestPath)) {
+ }
+
+ //
+ // Append DestParameter beyond '\' which may be present
+ //
+ CurrentSize = StrSize (DestPath);
+ StrnCatGrow (&DestPath, &CurrentSize, &DestParameter[1], 0);
+
+ *DestPathPointer = DestPath;
+ return (SHELL_SUCCESS);
+ }
+
+ //
+ // get the destination path
+ //
+ ShellOpenFileMetaArg ((CHAR16 *)DestParameter, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);
+ if ((DestList == NULL) || IsListEmpty (&DestList->Link)) {
+ //
+ // Not existing... must be renaming
+ //
+ if (StrStr (DestParameter, L":") == NULL) {
+ if (Cwd == NULL) {
+ ShellCloseFileMetaArg (&DestList);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
+ return (SHELL_INVALID_PARAMETER);
+ }
+
+ NewSize = StrSize (Cwd);
+ NewSize += StrSize (DestParameter);
+ DestPath = AllocateZeroPool (NewSize);
+ if (DestPath == NULL) {
+ ShellCloseFileMetaArg (&DestList);
+ return (SHELL_OUT_OF_RESOURCES);
+ }
+
+ StrCpyS (DestPath, NewSize / sizeof (CHAR16), Cwd);
+ if ((DestPath[StrLen (DestPath)-1] != L'\\') && (DestParameter[0] != L'\\')) {
+ StrCatS (DestPath, NewSize / sizeof (CHAR16), L"\\");
+ } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (DestParameter[0] == L'\\')) {
+ ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
+ }
+
+ StrCatS (DestPath, NewSize / sizeof (CHAR16), DestParameter);
+ } else {
+ ASSERT (DestPath == NULL);
+ DestPath = StrnCatGrow (&DestPath, NULL, DestParameter, 0);
+ if (DestPath == NULL) {
+ ShellCloseFileMetaArg (&DestList);
+ return (SHELL_OUT_OF_RESOURCES);
+ }
+ }
+ } else {
+ Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&DestList->Link);
+ *DestAttr = Node->Info->Attribute;
+ //
+ // Make sure there is only 1 node in the list.
+ //
+ if (!IsNodeAtEnd (&DestList->Link, &Node->Link)) {
+ ShellCloseFileMetaArg (&DestList);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);
+ return (SHELL_INVALID_PARAMETER);
+ }
+
+ //
+ // If we are a directory or a single file, then one node is fine.
+ //
+ if ((ShellIsDirectory (Node->FullName) == EFI_SUCCESS) || SingleSource) {
+ DestPath = AllocateZeroPool (StrSize (Node->FullName)+sizeof (CHAR16));
+ if (DestPath == NULL) {
+ ShellCloseFileMetaArg (&DestList);
+ return (SHELL_OUT_OF_RESOURCES);
+ }
+
+ StrCpyS (DestPath, (StrSize (Node->FullName)+sizeof (CHAR16)) / sizeof (CHAR16), Node->FullName);
+ StrCatS (DestPath, (StrSize (Node->FullName)+sizeof (CHAR16)) / sizeof (CHAR16), L"\\");
+ } else {
+ //
+ // cant move multiple files onto a single file.
+ //
+ ShellCloseFileMetaArg (&DestList);
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);
+ return (SHELL_INVALID_PARAMETER);
+ }
+ }
+
+ *DestPathPointer = DestPath;
+ ShellCloseFileMetaArg (&DestList);
+
+ return (SHELL_SUCCESS);
+}
+
+/**
+ Function to do a move across file systems.
+
+ @param[in] Node A pointer to the file to be removed.
+ @param[in] DestPath A pointer to the destination file path.
+ @param[out] Resp A pointer to response from question. Pass back on looped calling
+
+ @retval SHELL_SUCCESS The source file was moved to the destination.
+**/
+EFI_STATUS
+MoveBetweenFileSystems (
+ IN EFI_SHELL_FILE_INFO *Node,
+ IN CONST CHAR16 *DestPath,
+ OUT VOID **Resp
+ )
+{
+ SHELL_STATUS ShellStatus;
+
+ //
+ // First we copy the file
+ //
+ ShellStatus = CopySingleFile (Node->FullName, DestPath, Resp, TRUE, L"mv");
+
+ //
+ // Check our result
+ //
+ if (ShellStatus == SHELL_SUCCESS) {
+ //
+ // The copy was successful. delete the source file.
+ //
+ CascadeDelete (Node, TRUE);
+ Node->Handle = NULL;
+ } else if (ShellStatus == SHELL_ABORTED) {
+ return EFI_ABORTED;
+ } else if (ShellStatus == SHELL_ACCESS_DENIED) {
+ return EFI_ACCESS_DENIED;
+ } else if (ShellStatus == SHELL_VOLUME_FULL) {
+ return EFI_VOLUME_FULL;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ return (EFI_SUCCESS);
+}
+
+/**
+ Function to take the destination path and target file name to generate the full destination path.
+
+ @param[in] DestPath A pointer to the destination file path string.
+ @param[out] FullDestPath A pointer to the full destination path string.
+ @param[in] FileName Name string of the targe file.
+
+ @retval SHELL_SUCCESS the files were all moved.
+ @retval SHELL_INVALID_PARAMETER a parameter was invalid
+ @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
+**/
+EFI_STATUS
+CreateFullDestPath (
+ IN CONST CHAR16 **DestPath,
+ OUT CHAR16 **FullDestPath,
+ IN CONST CHAR16 *FileName
+ )
+{
+ UINTN Size;
+
+ if ((FullDestPath == NULL) || (FileName == NULL) || (DestPath == NULL) || (*DestPath == NULL)) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ Size = StrSize (*DestPath) + StrSize (FileName);
+
+ *FullDestPath = AllocateZeroPool (Size);
+ if (*FullDestPath == NULL) {
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ StrCpyS (*FullDestPath, Size / sizeof (CHAR16), *DestPath);
+ if (((*FullDestPath)[StrLen (*FullDestPath)-1] != L'\\') && (FileName[0] != L'\\')) {
+ StrCatS (*FullDestPath, Size / sizeof (CHAR16), L"\\");
+ }
+
+ StrCatS (*FullDestPath, Size / sizeof (CHAR16), FileName);
+
+ return (EFI_SUCCESS);
+}
+
+/**
+ Function to do a move within a file system.
+
+ @param[in] Node A pointer to the file to be removed.
+ @param[in] DestPath A pointer to the destination file path.
+ @param[out] Resp A pointer to response from question. Pass back on looped calling.
+
+ @retval SHELL_SUCCESS The source file was moved to the destination.
+ @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
+**/
+EFI_STATUS
+MoveWithinFileSystems (
+ IN EFI_SHELL_FILE_INFO *Node,
+ IN CHAR16 *DestPath,
+ OUT VOID **Resp
+ )
+{
+ EFI_FILE_INFO *NewFileInfo;
+ CHAR16 *TempLocation;
+ UINTN NewSize;
+ UINTN Length;
+ EFI_STATUS Status;
+
+ //
+ // Chop off map info from DestPath
+ //
+ if ((TempLocation = StrStr (DestPath, L":")) != NULL) {
+ CopyMem (DestPath, TempLocation+1, StrSize (TempLocation+1));
+ }
+
+ //
+ // construct the new file info block
+ //
+ NewSize = StrSize (DestPath);
+ NewSize += StrSize (Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof (CHAR16);
+ NewFileInfo = AllocateZeroPool (NewSize);
+ if (NewFileInfo == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ CopyMem (NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO);
+ if (DestPath[0] != L'\\') {
+ StrCpyS (NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16), L"\\");
+ StrCatS (NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16), DestPath);
+ } else {
+ StrCpyS (NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16), DestPath);
+ }
+
+ Length = StrLen (NewFileInfo->FileName);
+ if (Length > 0) {
+ Length--;
+ }
+
+ if (NewFileInfo->FileName[Length] == L'\\') {
+ if (Node->FileName[0] == L'\\') {
+ //
+ // Don't allow for double slashes. Eliminate one of them.
+ //
+ NewFileInfo->FileName[Length] = CHAR_NULL;
+ }
+
+ StrCatS (NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof (CHAR16), Node->FileName);
+ }
+
+ NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize (NewFileInfo->FileName);
+
+ //
+ // Perform the move operation
+ //
+ Status = ShellSetFileInfo (Node->Handle, NewFileInfo);
+
+ //
+ // Free the info object we used...
+ //
+ FreePool (NewFileInfo);
+ }
+
+ return (Status);
+}
+
+/**
+ function to take a list of files to move and a destination location and do
+ the verification and moving of those files to that location. This function
+ will report any errors to the user and continue to move the rest of the files.
+
+ @param[in] FileList A LIST_ENTRY* based list of files to move
+ @param[out] Resp pointer to response from question. Pass back on looped calling
+ @param[in] DestParameter the originally specified destination location
+
+ @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
+ValidateAndMoveFiles (
+ IN EFI_SHELL_FILE_INFO *FileList,
+ OUT VOID **Resp,
+ IN CONST CHAR16 *DestParameter
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *HiiOutput;
+ CHAR16 *HiiResultOk;
+ CHAR16 *DestPath;
+ CHAR16 *FullDestPath;
+ CONST CHAR16 *Cwd;
+ CHAR16 *FullCwd;
+ SHELL_STATUS ShellStatus;
+ EFI_SHELL_FILE_INFO *Node;
+ VOID *Response;
+ UINT64 Attr;
+ CHAR16 *CleanFilePathStr;
+
+ ASSERT (FileList != NULL);
+ ASSERT (DestParameter != NULL);
+
+ DestPath = NULL;
+ FullDestPath = NULL;
+ Cwd = ShellGetCurrentDir (NULL);
+ Response = *Resp;
+ Attr = 0;
+ CleanFilePathStr = NULL;
+ FullCwd = NULL;
+
+ if (Cwd != NULL) {
+ FullCwd = AllocateZeroPool (StrSize (Cwd) + sizeof (CHAR16));
+ if (FullCwd == NULL) {
+ return SHELL_OUT_OF_RESOURCES;
+ } else {
+ StrCpyS (FullCwd, StrSize (Cwd)/sizeof (CHAR16)+1, Cwd);
+ StrCatS (FullCwd, StrSize (Cwd)/sizeof (CHAR16)+1, L"\\");
+ }
+ }
+
+ Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr);
+ if (EFI_ERROR (Status)) {
+ SHELL_FREE_NON_NULL (FullCwd);
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ return SHELL_OUT_OF_RESOURCES;
+ } else {
+ return SHELL_INVALID_PARAMETER;
+ }
+ }
+
+ ASSERT (CleanFilePathStr != NULL);
+
+ //
+ // Get and validate the destination location
+ //
+ ShellStatus = GetDestinationLocation (CleanFilePathStr, &DestPath, FullCwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr);
+ FreePool (CleanFilePathStr);
+
+ if (ShellStatus != SHELL_SUCCESS) {
+ SHELL_FREE_NON_NULL (FullCwd);
+ return (ShellStatus);
+ }
+
+ DestPath = PathCleanUpDirectories (DestPath);
+ if (DestPath == NULL) {
+ FreePool (FullCwd);
+ return (SHELL_OUT_OF_RESOURCES);
+ }
+
+ HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);
+ HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
+ if ((HiiOutput == NULL) || (HiiResultOk == NULL)) {
+ SHELL_FREE_NON_NULL (DestPath);
+ SHELL_FREE_NON_NULL (HiiOutput);
+ SHELL_FREE_NON_NULL (HiiResultOk);
+ SHELL_FREE_NON_NULL (FullCwd);
+ return (SHELL_OUT_OF_RESOURCES);
+ }
+
+ //
+ // Go through the list of files and directories to move...
+ //
+ 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;
+ }
+
+ //
+ // These should never be NULL
+ //
+ ASSERT (Node->FileName != NULL);
+ ASSERT (Node->FullName != NULL);
+ ASSERT (Node->Info != NULL);
+
+ //
+ // skip the directory traversing stuff...
+ //
+ if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
+ continue;
+ }
+
+ SHELL_FREE_NON_NULL (FullDestPath);
+ FullDestPath = NULL;
+ if (ShellIsDirectory (DestPath) == EFI_SUCCESS) {
+ CreateFullDestPath ((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName);
+ }
+
+ //
+ // Validate that the move is valid
+ //
+ if (!IsValidMove (Node->FullName, FullCwd, (FullDestPath != NULL) ? FullDestPath : DestPath, Node->Info->Attribute, Attr, Node->Status)) {
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ continue;
+ }
+
+ ShellPrintEx (-1, -1, HiiOutput, Node->FullName, FullDestPath != NULL ? FullDestPath : DestPath);
+
+ //
+ // See if destination exists
+ //
+ if (!EFI_ERROR (ShellFileExists ((FullDestPath != NULL) ? FullDestPath : DestPath))) {
+ if (Response == NULL) {
+ ShellPromptForResponseHii (ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
+ }
+
+ if (Response == NULL) {
+ return SHELL_ABORTED;
+ }
+
+ switch (*(SHELL_PROMPT_RESPONSE *)Response) {
+ case ShellPromptResponseNo:
+ FreePool (Response);
+ Response = NULL;
+ continue;
+ case ShellPromptResponseCancel:
+ *Resp = Response;
+ //
+ // indicate to stop everything
+ //
+ SHELL_FREE_NON_NULL (FullCwd);
+ return (SHELL_ABORTED);
+ case ShellPromptResponseAll:
+ *Resp = Response;
+ break;
+ case ShellPromptResponseYes:
+ FreePool (Response);
+ Response = NULL;
+ break;
+ default:
+ FreePool (Response);
+ SHELL_FREE_NON_NULL (FullCwd);
+ return SHELL_ABORTED;
+ }
+
+ Status = ShellDeleteFileByName (FullDestPath != NULL ? FullDestPath : DestPath);
+ }
+
+ if (IsBetweenFileSystem (Node->FullName, FullCwd, DestPath)) {
+ while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen (DestPath) - 1] == L'\\') {
+ DestPath[StrLen (DestPath) - 1] = CHAR_NULL;
+ }
+
+ Status = MoveBetweenFileSystems (Node, FullDestPath != NULL ? FullDestPath : DestPath, &Response);
+ } else {
+ Status = MoveWithinFileSystems (Node, DestPath, &Response);
+ //
+ // Display error status
+ //
+ if (EFI_ERROR (Status)) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"mv", Status);
+ }
+ }
+
+ //
+ // Check our result
+ //
+ if (EFI_ERROR (Status)) {
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ if (Status == EFI_SECURITY_VIOLATION) {
+ ShellStatus = SHELL_SECURITY_VIOLATION;
+ } else if (Status == EFI_WRITE_PROTECTED) {
+ ShellStatus = SHELL_WRITE_PROTECTED;
+ } else if (Status == EFI_OUT_OF_RESOURCES) {
+ ShellStatus = SHELL_OUT_OF_RESOURCES;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ ShellStatus = SHELL_DEVICE_ERROR;
+ } else if (Status == EFI_ACCESS_DENIED) {
+ ShellStatus = SHELL_ACCESS_DENIED;
+ }
+ } else {
+ ShellPrintEx (-1, -1, L"%s", HiiResultOk);
+ }
+ } // main for loop
+
+ SHELL_FREE_NON_NULL (FullDestPath);
+ SHELL_FREE_NON_NULL (DestPath);
+ SHELL_FREE_NON_NULL (HiiOutput);
+ SHELL_FREE_NON_NULL (HiiResultOk);
+ SHELL_FREE_NON_NULL (FullCwd);
+ return (ShellStatus);
+}
+
+/**
+ Function for 'mv' 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
+ShellCommandRunMv (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Package;
+ CHAR16 *ProblemParam;
+ CHAR16 *Cwd;
+ UINTN CwdSize;
+ SHELL_STATUS ShellStatus;
+ UINTN ParamCount;
+ UINTN LoopCounter;
+ EFI_SHELL_FILE_INFO *FileList;
+ VOID *Response;
+
+ ProblemParam = NULL;
+ ShellStatus = SHELL_SUCCESS;
+ ParamCount = 0;
+ FileList = NULL;
+ Response = NULL;
+
+ //
+ // initialize the shell lib (we must be in non-auto-init...)
+ //
+ Status = ShellInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // parse the command line
+ //
+ Status = ShellCommandLineParse (EmptyParamList, &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"mv", ProblemParam);
+ FreePool (ProblemParam);
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ } else {
+ ASSERT (FALSE);
+ }
+ } else {
+ //
+ // check for "-?"
+ //
+ if (ShellCommandLineGetFlag (Package, L"-?")) {
+ ASSERT (FALSE);
+ }
+
+ switch (ParamCount = ShellCommandLineGetCount (Package)) {
+ case 0:
+ case 1:
+ //
+ // we have insufficient parameters
+ //
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mv");
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ break;
+ case 2:
+ //
+ // must have valid CWD for single parameter...
+ //
+ if (ShellGetCurrentDir (NULL) == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"mv");
+ 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"mv", ShellCommandLineGetRawValue (Package, 1));
+ ShellStatus = SHELL_NOT_FOUND;
+ } else {
+ //
+ // ValidateAndMoveFiles will report errors to the screen itself
+ //
+ CwdSize = StrSize (ShellGetCurrentDir (NULL)) + sizeof (CHAR16);
+ Cwd = AllocateZeroPool (CwdSize);
+ if (Cwd == NULL) {
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"mv");
+ ShellStatus = SHELL_OUT_OF_RESOURCES;
+ } else {
+ StrCpyS (Cwd, CwdSize / sizeof (CHAR16), ShellGetCurrentDir (NULL));
+ StrCatS (Cwd, CwdSize / sizeof (CHAR16), L"\\");
+ ShellStatus = ValidateAndMoveFiles (FileList, &Response, Cwd);
+ FreePool (Cwd);
+ }
+ }
+ }
+
+ break;
+ default:
+ /// @todo make sure this works with error half way through and continues...
+ for (ParamCount--, LoopCounter = 1; LoopCounter < ParamCount; LoopCounter++) {
+ if (ShellGetExecutionBreakFlag ()) {
+ break;
+ }
+
+ Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, LoopCounter), 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"mv", ShellCommandLineGetRawValue (Package, LoopCounter));
+ ShellStatus = SHELL_NOT_FOUND;
+ } else {
+ //
+ // ValidateAndMoveFiles will report errors to the screen itself
+ // Only change ShellStatus if it's successful
+ //
+ if (ShellStatus == SHELL_SUCCESS) {
+ ShellStatus = ValidateAndMoveFiles (FileList, &Response, ShellCommandLineGetRawValue (Package, ParamCount));
+ } else {
+ ValidateAndMoveFiles (FileList, &Response, ShellCommandLineGetRawValue (Package, ParamCount));
+ }
+ }
+
+ if ((FileList != NULL) && !IsListEmpty (&FileList->Link)) {
+ Status = ShellCloseFileMetaArg (&FileList);
+ if (EFI_ERROR (Status) && (ShellStatus == SHELL_SUCCESS)) {
+ ShellStatus = SHELL_ACCESS_DENIED;
+ ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue (Package, 1), ShellStatus|MAX_BIT);
+ }
+ }
+ }
+
+ break;
+ } // switch on parameter count
+
+ if (FileList != NULL) {
+ ShellCloseFileMetaArg (&FileList);
+ }
+
+ //
+ // free the command line package
+ //
+ ShellCommandLineFreeVarList (Package);
+ }
+
+ SHELL_FREE_NON_NULL (Response);
+
+ if (ShellGetExecutionBreakFlag ()) {
+ return (SHELL_ABORTED);
+ }
+
+ return (ShellStatus);
+}