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.c478
1 files changed, 478 insertions, 0 deletions
diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
new file mode 100644
index 0000000000..adb6f99759
--- /dev/null
+++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
@@ -0,0 +1,478 @@
+/** @file
+ Main file for mv shell level 2 function.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UefiShellLevel2CommandsLib.h"
+
+/**
+ 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 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
+ @param Attribute[in] The Attribute of the file
+
+ @retval TRUE The move is valid
+ @retval FALSE The move is not
+**/
+BOOLEAN
+EFIAPI
+IsValidMove(
+ IN CONST CHAR16 *FullName,
+ IN CONST CHAR16 *Cwd,
+ IN CONST CHAR16 *DestPath,
+ IN CONST UINT64 Attribute
+ )
+{
+ CHAR16 *Test;
+ CHAR16 *Test1;
+ CHAR16 *TestWalker;
+ UINTN Result;
+ UINTN TempLen;
+ if (Cwd != NULL && StrCmp(FullName, Cwd) == 0) {
+ //
+ // Invalid move
+ //
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle);
+ return (FALSE);
+ }
+ Test = NULL;
+ Test = StrnCatGrow(&Test, NULL, DestPath, 0);
+ TestWalker = Test;
+ ASSERT(TestWalker != NULL);
+ while(*TestWalker == L'\\') {
+ TestWalker++;
+ }
+ while(TestWalker != NULL && TestWalker[StrLen(TestWalker)-1] == L'\\') {
+ TestWalker[StrLen(TestWalker)-1] = CHAR_NULL;
+ }
+ ASSERT(TestWalker != NULL);
+ ASSERT(FullName != NULL);
+ if (StrStr(FullName, TestWalker) != 0) {
+ TempLen = StrLen(FullName);
+ if (StrStr(FullName, TestWalker) != FullName // not the first items... (could below it)
+ && TempLen <= (StrLen(TestWalker) + 1)
+ && StrStr(FullName+StrLen(TestWalker) + 1, L"\\") == NULL) {
+ //
+ // Invalid move
+ //
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);
+ FreePool(Test);
+ return (FALSE);
+ }
+ }
+ FreePool(Test);
+ if (StrStr(DestPath, FullName) != 0 && StrStr(DestPath, FullName) != DestPath) {
+ //
+ // Invalid move
+ //
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);
+ return (FALSE);
+ }
+ if ((Attribute & EFI_FILE_READ_ONLY) != 0) {
+ //
+ // invalid to move read only
+ //
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle);
+ return (FALSE);
+ }
+ Test = StrStr(FullName, L":");
+ Test1 = StrStr(DestPath, L":");
+ if (Test1 != NULL && Test != NULL) {
+ *Test = CHAR_NULL;
+ *Test1 = CHAR_NULL;
+ Result = StringNoCaseCompare(&FullName, &DestPath);
+ *Test = L':';
+ *Test1 = L':';
+ if (Result != 0) {
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_FS), gShellLevel2HiiHandle);
+ return (FALSE);
+ }
+ }
+ 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 sucessful the caller must free *DestPathPointer.
+
+ @param[in] DestDir The original path to the destination
+ @param[in,out] DestPathPointer a pointer to the callee allocated final path.
+
+ @retval EFI_INVALID_PARAMETR the DestDir could not be resolved to a location
+ @retval EFI_INVALID_PARAMETR the DestDir could be resolved to more than 1 location
+ @retval EFI_SUCCESS the operation was sucessful
+**/
+SHELL_STATUS
+EFIAPI
+GetDestinationLocation(
+ IN CONST CHAR16 *DestDir,
+ IN OUT CHAR16 **DestPathPointer,
+ IN CONST CHAR16 *Cwd
+ )
+{
+ EFI_SHELL_FILE_INFO *DestList;
+ EFI_SHELL_FILE_INFO *Node;
+ EFI_STATUS Status;
+ CHAR16 *DestPath;
+ CHAR16 *TempLocation;
+ UINTN NewSize;
+
+ DestList = NULL;
+ DestPath = NULL;
+ //
+ // get the destination path
+ //
+ Status = ShellOpenFileMetaArg((CHAR16*)DestDir, 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 ((TempLocation = StrStr(DestDir, L":")) == NULL) {
+ NewSize = StrSize(Cwd);
+ NewSize += StrSize(DestDir);
+ DestPath = AllocateZeroPool(NewSize);
+ StrCpy(DestPath, Cwd);
+ if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {
+ StrCat(DestPath, L"\\");
+ } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {
+ ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
+ }
+ StrCat(DestPath, DestDir);
+ } else {
+ ASSERT(DestPath == NULL);
+ DestPath = StrnCatGrow(&DestPath, NULL, DestDir, 0);
+ }
+ } else {
+ Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link);
+ //
+ // 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, DestDir);
+ return (SHELL_INVALID_PARAMETER);
+ }
+ if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS) {
+ DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16));
+ StrCpy(DestPath, Node->FullName);
+ StrCat(DestPath, L"\\");
+ } else {
+ //
+ // cant move onto another file.
+ //
+ ShellCloseFileMetaArg(&DestList);
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, DestDir);
+ return (SHELL_INVALID_PARAMETER);
+ }
+ }
+
+ *DestPathPointer = DestPath;
+ ShellCloseFileMetaArg(&DestList);
+
+ return (SHELL_SUCCESS);
+}
+
+/**
+ 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[in] DestDir the 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
+EFIAPI
+ValidateAndMoveFiles(
+ IN CONST EFI_SHELL_FILE_INFO *FileList,
+ IN CONST CHAR16 *DestDir
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *HiiOutput;
+ CHAR16 *HiiResultOk;
+ CHAR16 *DestPath;
+ CONST CHAR16 *Cwd;
+ SHELL_STATUS ShellStatus;
+ CONST EFI_SHELL_FILE_INFO *Node;
+ EFI_FILE_INFO *NewFileInfo;
+ CHAR16 *TempLocation;
+ UINTN NewSize;
+
+ ASSERT(FileList != NULL);
+ ASSERT(DestDir != NULL);
+
+ DestPath = NULL;
+ Cwd = ShellGetCurrentDir(NULL);
+
+ //
+ // Get and validate the destination location
+ //
+ ShellStatus = GetDestinationLocation(DestDir, &DestPath, Cwd);
+ if (ShellStatus != SHELL_SUCCESS) {
+ return (ShellStatus);
+ }
+
+ HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);
+ HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
+ ASSERT (DestPath != NULL);
+ ASSERT (HiiResultOk != NULL);
+ ASSERT (HiiOutput != NULL);
+// ASSERT (Cwd != NULL);
+
+ //
+ // 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;
+ }
+ 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;
+ }
+
+ //
+ // Validate that the move is valid
+ //
+ if (!IsValidMove(Node->FullName, Cwd, DestPath, Node->Info->Attribute)) {
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ continue;
+ }
+
+ //
+ // 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) + sizeof(EFI_FILE_INFO) + sizeof(CHAR16);
+ NewFileInfo = AllocateZeroPool(NewSize);
+ ASSERT(NewFileInfo != NULL);
+ CopyMem(NewFileInfo, Node->Info, sizeof(EFI_FILE_INFO));
+ if (DestPath[0] != L'\\') {
+ StrCpy(NewFileInfo->FileName, L"\\");
+ StrCat(NewFileInfo->FileName, DestPath);
+ } else {
+ StrCpy(NewFileInfo->FileName, DestPath);
+ }
+ if (NewFileInfo->FileName[StrLen(NewFileInfo->FileName)-1] == L'\\') {
+ if (Node->FileName[0] == L'\\') {
+ //
+ // Don't allow for double slashes. Eliminate one of them.
+ //
+ NewFileInfo->FileName[StrLen(NewFileInfo->FileName)-1] = CHAR_NULL;
+ }
+ StrCat(NewFileInfo->FileName, Node->FileName);
+ }
+ NewFileInfo->Size = sizeof(EFI_FILE_INFO) + StrSize(NewFileInfo->FileName);
+
+ ShellPrintEx(-1, -1, HiiOutput, Node->FullName, NewFileInfo->FileName);
+
+ //
+ // Perform the move operation
+ //
+ Status = ShellSetFileInfo(Node->Handle, NewFileInfo);
+
+ //
+ // Free the info object we used...
+ //
+ ASSERT (NewFileInfo != NULL);
+ FreePool(NewFileInfo);
+
+ //
+ // Check our result
+ //
+ if (EFI_ERROR(Status)) {
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status);
+ //
+ // move failed
+ //
+ switch(Status){
+ default:
+ ShellStatus = SHELL_INVALID_PARAMETER;
+ case EFI_SECURITY_VIOLATION:
+ ShellStatus = SHELL_SECURITY_VIOLATION;
+ case EFI_WRITE_PROTECTED:
+ ShellStatus = SHELL_WRITE_PROTECTED;
+ case EFI_OUT_OF_RESOURCES:
+ ShellStatus = SHELL_OUT_OF_RESOURCES;
+ case EFI_DEVICE_ERROR:
+ ShellStatus = SHELL_DEVICE_ERROR;
+ case EFI_ACCESS_DENIED:
+ ShellStatus = SHELL_ACCESS_DENIED;
+ } // switch
+ } else {
+ ShellPrintEx(-1, -1, L"%s", HiiResultOk);
+ }
+ } // for loop
+
+ FreePool(DestPath);
+ FreePool(HiiOutput);
+ FreePool(HiiResultOk);
+ return (ShellStatus);
+}
+
+SHELL_STATUS
+EFIAPI
+ShellCommandRunMv (
+ 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;
+
+ 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);
+
+ //
+ // 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, 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);
+ 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);
+ 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, ShellCommandLineGetRawValue(Package, 1));
+ ShellStatus = SHELL_NOT_FOUND;
+ } else {
+ //
+ // ValidateAndMoveFiles will report errors to the screen itself
+ //
+ ShellStatus = ValidateAndMoveFiles(FileList, ShellGetCurrentDir(NULL));
+ }
+ }
+
+ break;
+ default:
+ ///@todo make sure this works with error half way through and continues...
+ 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 (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));
+ ShellStatus = SHELL_NOT_FOUND;
+ } else {
+ //
+ // ValidateAndMoveFiles will report errors to the screen itself
+ // Only change ShellStatus if it's sucessful
+ //
+ if (ShellStatus == SHELL_SUCCESS) {
+ ShellStatus = ValidateAndMoveFiles(FileList, ShellCommandLineGetRawValue(Package, ParamCount));
+ } else {
+ ValidateAndMoveFiles(FileList, 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, ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);
+ }
+ }
+ }
+ break;
+ } // switch on parameter count
+
+ if (FileList != NULL) {
+ ShellCloseFileMetaArg(&FileList);
+ }
+
+ //
+ // free the command line package
+ //
+ ShellCommandLineFreeVarList (Package);
+ }
+
+ if (ShellGetExecutionBreakFlag()) {
+ return (SHELL_ABORTED);
+ }
+
+ return (ShellStatus);
+}