]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
ShellPkg: Standardized HP Copyright Message String
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Mv.c
index 666cedb49dd0e3ffd4e05f2e61341e8282b348ab..916020419509469f6c4f74defe8dc15bc3de7215 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Main file for mv shell level 2 function.\r
 \r
-  (C) Copyright 2013-2014, Hewlett-Packard Development Company, L.P.\r
+  (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>\r
   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
 \r
 #include "UefiShellLevel2CommandsLib.h"\r
 \r
+/**\r
+  function to determine if a move is between file systems.\r
+  \r
+  @param FullName [in]    The name of the file to move.\r
+  @param Cwd      [in]    The current working directory\r
+  @param DestPath [in]    The target location to move to\r
+\r
+  @retval TRUE            The move is across file system.\r
+  @retval FALSE           The move is within a file system.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsBetweenFileSystem(\r
+  IN CONST CHAR16     *FullName,\r
+  IN CONST CHAR16     *Cwd,\r
+  IN CONST CHAR16     *DestPath\r
+  )\r
+{\r
+  CHAR16  *Test;\r
+  CHAR16  *Test1;\r
+  UINTN   Result;\r
+\r
+  Test = StrStr(FullName, L":");\r
+  if (Test == NULL && Cwd != NULL) {\r
+    Test = StrStr(Cwd, L":");\r
+  }\r
+  Test1 = StrStr(DestPath, L":");\r
+  if (Test1 == NULL && Cwd != NULL) {\r
+    Test1 = StrStr(Cwd, L":");\r
+  }\r
+  if (Test1 != NULL && Test != NULL) {\r
+    *Test = CHAR_NULL;\r
+    *Test1 = CHAR_NULL;\r
+    Result = StringNoCaseCompare(&FullName, &DestPath);\r
+    *Test = L':';\r
+    *Test1 = L':';\r
+    if (Result != 0) {\r
+      return (TRUE);\r
+    }\r
+  }\r
+  return (FALSE);\r
+}\r
+\r
 /**\r
   Function to validate that moving a specific file (FileName) to a specific\r
   location (DestPath) is valid.\r
 \r
   if the move is invalid this function will report the error to StdOut.\r
 \r
-  @param FullName [in]    The name of the file to move.\r
-  @param Cwd      [in]    The current working directory\r
-  @param DestPath [in]    The target location to move to\r
-  @param Attribute[in]    The Attribute of the file\r
-  @param FileStatus[in]   The Status of the file when opened\r
+  @param SourcePath [in]    The name of the file to move.\r
+  @param Cwd        [in]    The current working directory\r
+  @param DestPath   [in]    The target location to move to\r
+  @param Attribute  [in]    The Attribute of the file\r
+  @param DestAttr   [in]    The Attribute of the destination\r
+  @param FileStatus [in]    The Status of the file when opened\r
 \r
   @retval TRUE        The move is valid\r
   @retval FALSE       The move is not\r
 BOOLEAN\r
 EFIAPI\r
 IsValidMove(\r
-  IN CONST CHAR16     *FullName,\r
+  IN CONST CHAR16     *SourcePath,\r
   IN CONST CHAR16     *Cwd,\r
   IN CONST CHAR16     *DestPath,\r
   IN CONST UINT64     Attribute,\r
+  IN CONST UINT64     DestAttr,\r
   IN CONST EFI_STATUS FileStatus\r
   )\r
 {\r
-  CHAR16  *Test;\r
-  CHAR16  *Test1;\r
-  CHAR16  *TestWalker;\r
-  INTN    Result;\r
-  UINTN   TempLen;\r
-  if (Cwd != NULL && StrCmp(FullName, Cwd) == 0) {\r
+  CHAR16  *DestPathCopy;\r
+  CHAR16  *DestPathWalker;\r
+\r
+  if (Cwd != NULL && StrCmp(SourcePath, Cwd) == 0) {\r
     //\r
     // Invalid move\r
     //\r
     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle);\r
     return (FALSE);\r
   }\r
-  Test = NULL;\r
-  Test = StrnCatGrow(&Test, NULL, DestPath, 0);\r
-  TestWalker = Test;\r
-  ASSERT(TestWalker != NULL);\r
-  while(*TestWalker == L'\\') {\r
-    TestWalker++;\r
-  }\r
-  while(TestWalker != NULL && TestWalker[StrLen(TestWalker)-1] == L'\\') {\r
-    TestWalker[StrLen(TestWalker)-1] = CHAR_NULL;\r
+\r
+  //\r
+  // invalid to move read only or move to a read only destination\r
+  //\r
+  if (((Attribute & EFI_FILE_READ_ONLY) != 0) \r
+    || (FileStatus == EFI_WRITE_PROTECTED)\r
+    || ((DestAttr & EFI_FILE_READ_ONLY) != 0)\r
+    ) {\r
+    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle, SourcePath);\r
+    return (FALSE);\r
+  }  \r
+  \r
+  DestPathCopy = AllocateCopyPool(StrSize(DestPath), DestPath);\r
+  if (DestPathCopy == NULL) {\r
+    return (FALSE);\r
   }\r
-  ASSERT(TestWalker != NULL);\r
-  ASSERT(FullName   != NULL);\r
-  if (StrStr(FullName, TestWalker) != 0) {\r
-    TempLen = StrLen(FullName);\r
-    if (StrStr(FullName, TestWalker) != FullName                    // not the first items... (could below it)\r
-      && TempLen <= (StrLen(TestWalker) + 1)\r
-      && StrStr(FullName+StrLen(TestWalker) + 1, L"\\") == NULL) {\r
-      //\r
-      // Invalid move\r
-      //\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);\r
-      FreePool(Test);\r
-      return (FALSE);\r
-    }\r
+\r
+  for (DestPathWalker = DestPathCopy; *DestPathWalker == L'\\'; DestPathWalker++) ;\r
+\r
+  while(DestPathWalker != NULL && DestPathWalker[StrLen(DestPathWalker)-1] == L'\\') {\r
+    DestPathWalker[StrLen(DestPathWalker)-1] = CHAR_NULL;\r
   }\r
-  FreePool(Test);\r
-  if (StrStr(DestPath, FullName) != 0 && StrStr(DestPath, FullName) != DestPath) {\r
-    //\r
-    // Invalid move\r
-    //\r
+\r
+  ASSERT(DestPathWalker != NULL);\r
+  ASSERT(SourcePath   != NULL);\r
+\r
+  //\r
+  // If they're the same, or if source is "above" dest on file path tree\r
+  //\r
+  if ( StrCmp(DestPathWalker, SourcePath) == 0 \r
+    || StrStr(DestPathWalker, SourcePath) == DestPathWalker \r
+    ) {\r
     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);\r
+    FreePool(DestPathCopy);\r
     return (FALSE);\r
   }\r
-  if (((Attribute & EFI_FILE_READ_ONLY) != 0) || (FileStatus == EFI_WRITE_PROTECTED)) {\r
-    //\r
-    // invalid to move read only\r
-    //\r
-    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle, FullName);\r
-    return (FALSE);\r
-  }\r
-  Test  = StrStr(FullName, L":");\r
-  Test1 = StrStr(DestPath, L":");\r
-  if (Test1 != NULL && Test  != NULL) {\r
-    *Test  = CHAR_NULL;\r
-    *Test1 = CHAR_NULL;\r
-    Result = StringNoCaseCompare(&FullName, &DestPath);\r
-    *Test  = L':';\r
-    *Test1 = L':';\r
-    if (Result != 0) {\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_FS), gShellLevel2HiiHandle);\r
-      return (FALSE);\r
-    }\r
-  }\r
+  FreePool(DestPathCopy);\r
+\r
   return (TRUE);\r
 }\r
 \r
@@ -119,21 +147,25 @@ IsValidMove(
 \r
   if the result is sucessful the caller must free *DestPathPointer.\r
 \r
-  @param[in] DestDir               The original path to the destination.\r
+  @param[in] DestParameter               The original path to the destination.\r
   @param[in, out] DestPathPointer  A pointer to the callee allocated final path.\r
   @param[in] Cwd                   A pointer to the current working directory.\r
+  @param[in] SingleSource          TRUE to have only one source file.\r
+  @param[in, out] DestAttr         A pointer to the destination information attribute.\r
 \r
-  @retval SHELL_INVALID_PARAMETER  The DestDir could not be resolved to a location.\r
-  @retval SHELL_INVALID_PARAMETER  The DestDir could be resolved to more than 1 location.\r
+  @retval SHELL_INVALID_PARAMETER  The DestParameter could not be resolved to a location.\r
+  @retval SHELL_INVALID_PARAMETER  The DestParameter could be resolved to more than 1 location.\r
   @retval SHELL_INVALID_PARAMETER  Cwd is required and is NULL.\r
   @retval SHELL_SUCCESS            The operation was sucessful.\r
 **/\r
 SHELL_STATUS\r
 EFIAPI\r
 GetDestinationLocation(\r
-  IN CONST CHAR16               *DestDir,\r
+  IN CONST CHAR16               *DestParameter,\r
   IN OUT CHAR16                 **DestPathPointer,\r
-  IN CONST CHAR16               *Cwd\r
+  IN CONST CHAR16               *Cwd,\r
+  IN CONST BOOLEAN              SingleSource,\r
+  IN OUT UINT64                 *DestAttr\r
   )\r
 {\r
   EFI_SHELL_FILE_INFO       *DestList;\r
@@ -145,7 +177,9 @@ GetDestinationLocation(
   DestList = NULL;\r
   DestPath = NULL;\r
 \r
-  if (StrStr(DestDir, L"\\") == DestDir) {\r
+  ASSERT(DestAttr != NULL);\r
+\r
+  if (StrStr(DestParameter, L"\\") == DestParameter) {\r
     if (Cwd == NULL) {\r
       return SHELL_INVALID_PARAMETER;\r
     }\r
@@ -157,10 +191,10 @@ GetDestinationLocation(
     while (PathRemoveLastItem(DestPath)) ;\r
 \r
     //\r
-    // Append DestDir beyond '\' which may be present\r
+    // Append DestParameter beyond '\' which may be present\r
     //\r
     CurrentSize = StrSize(DestPath);\r
-    StrnCatGrow(&DestPath, &CurrentSize, &DestDir[1], 0);\r
+    StrnCatGrow(&DestPath, &CurrentSize, &DestParameter[1], 0);\r
 \r
     *DestPathPointer =  DestPath;\r
     return (SHELL_SUCCESS);\r
@@ -168,33 +202,34 @@ GetDestinationLocation(
   //\r
   // get the destination path\r
   //\r
-  ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);\r
+  ShellOpenFileMetaArg((CHAR16*)DestParameter, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);\r
   if (DestList == NULL || IsListEmpty(&DestList->Link)) {\r
     //\r
     // Not existing... must be renaming\r
     //\r
-    if (StrStr(DestDir, L":") == NULL) {\r
+    if (StrStr(DestParameter, L":") == NULL) {\r
       if (Cwd == NULL) {\r
         ShellCloseFileMetaArg(&DestList);\r
+        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);\r
         return (SHELL_INVALID_PARAMETER);\r
       }\r
       NewSize = StrSize(Cwd);\r
-      NewSize += StrSize(DestDir);\r
+      NewSize += StrSize(DestParameter);\r
       DestPath = AllocateZeroPool(NewSize);\r
       if (DestPath == NULL) {\r
         ShellCloseFileMetaArg(&DestList);\r
         return (SHELL_OUT_OF_RESOURCES);\r
       }\r
       StrCpy(DestPath, Cwd);\r
-      if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {\r
+      if (DestPath[StrLen(DestPath)-1] != L'\\' && DestParameter[0] != L'\\') {\r
         StrCat(DestPath, L"\\");\r
-      } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {\r
+      } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestParameter[0] == L'\\') {\r
         ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
       }\r
-      StrCat(DestPath, DestDir);\r
+      StrCat(DestPath, DestParameter);\r
     } else {\r
       ASSERT(DestPath == NULL);\r
-      DestPath = StrnCatGrow(&DestPath, NULL, DestDir, 0);\r
+      DestPath = StrnCatGrow(&DestPath, NULL, DestParameter, 0);\r
       if (DestPath == NULL) {\r
         ShellCloseFileMetaArg(&DestList);\r
         return (SHELL_OUT_OF_RESOURCES);\r
@@ -202,15 +237,20 @@ GetDestinationLocation(
     }\r
   } else {\r
     Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link);\r
+    *DestAttr = Node->Info->Attribute;\r
     //\r
     // Make sure there is only 1 node in the list.\r
     //\r
     if (!IsNodeAtEnd(&DestList->Link, &Node->Link)) {\r
       ShellCloseFileMetaArg(&DestList);\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir);\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);  \r
       return (SHELL_INVALID_PARAMETER);\r
     }\r
-    if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS) {\r
+\r
+    //\r
+    // If we are a directory or a single file, then one node is fine.\r
+    //\r
+    if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS || SingleSource) {\r
       DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16));\r
       if (DestPath == NULL) {\r
         ShellCloseFileMetaArg(&DestList);\r
@@ -220,10 +260,10 @@ GetDestinationLocation(
       StrCat(DestPath, L"\\");\r
     } else {\r
       //\r
-      // cant move onto another file.\r
+      // cant move multiple files onto a single file.\r
       //\r
       ShellCloseFileMetaArg(&DestList);\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, DestDir);\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);  \r
       return (SHELL_INVALID_PARAMETER);\r
     }\r
   }\r
@@ -234,6 +274,160 @@ GetDestinationLocation(
   return (SHELL_SUCCESS);\r
 }\r
 \r
+/**\r
+  Function to do a move across file systems.\r
+\r
+  @param[in] Node               A pointer to the file to be removed.\r
+  @param[in] DestPath           A pointer to the destination file path.\r
+  @param[out] Resp              A pointer to response from question.  Pass back on looped calling\r
+\r
+  @retval SHELL_SUCCESS     The source file was moved to the destination.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MoveBetweenFileSystems(\r
+  IN EFI_SHELL_FILE_INFO  *Node,\r
+  IN CONST CHAR16         *DestPath,\r
+  OUT VOID                **Resp\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  //\r
+  // First we copy the file\r
+  //\r
+  Status = CopySingleFile(Node->FullName, DestPath, Resp, TRUE);\r
+\r
+  //\r
+  // Check our result\r
+  //\r
+  if (!EFI_ERROR(Status)) {\r
+    //\r
+    // The copy was successful.  delete the source file.\r
+    //\r
+    CascadeDelete(Node, TRUE);\r
+    Node->Handle = NULL;\r
+  }\r
+\r
+  return (Status);\r
+}\r
+\r
+/**\r
+  Function to take the destination path and target file name to generate the full destination path.\r
+\r
+  @param[in] DestPath           A pointer to the destination file path string.\r
+  @param[out] FullDestPath      A pointer to the full destination path string.\r
+  @param[in] FileName           Name string of  the targe file.\r
+\r
+  @retval SHELL_SUCCESS             the files were all moved.\r
+  @retval SHELL_INVALID_PARAMETER   a parameter was invalid\r
+  @retval SHELL_OUT_OF_RESOURCES    a memory allocation failed\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CreateFullDestPath(\r
+  IN CONST CHAR16 **DestPath,\r
+  OUT CHAR16      **FullDestPath, \r
+  IN CONST CHAR16 *FileName\r
+  )\r
+{\r
+  UINTN Size;\r
+  if (FullDestPath == NULL || FileName == NULL || DestPath == NULL || *DestPath == NULL){\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  Size = StrSize(*DestPath) + StrSize(FileName);\r
+\r
+  *FullDestPath = AllocateZeroPool(Size);\r
+  if (*FullDestPath == NULL){\r
+    return (EFI_OUT_OF_RESOURCES);\r
+  }\r
+\r
+  StrnCpy(*FullDestPath, *DestPath, Size / sizeof(CHAR16) - 1);\r
+  if ((*FullDestPath)[StrLen(*FullDestPath)-1] != L'\\' && FileName[0] != L'\\') {\r
+    StrnCat(*FullDestPath, L"\\",Size / sizeof(CHAR16) - 1 - StrLen(*FullDestPath));\r
+  }\r
+  StrnCat(*FullDestPath, FileName, Size / sizeof(CHAR16) - 1 - StrLen(*FullDestPath));\r
+\r
+  return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+  Function to do a move within a file system.\r
+\r
+  @param[in] Node               A pointer to the file to be removed.\r
+  @param[in] DestPath           A pointer to the destination file path.\r
+  @param[out] Resp              A pointer to response from question.  Pass back on looped calling.\r
+\r
+  @retval SHELL_SUCCESS           The source file was moved to the destination.\r
+  @retval SHELL_OUT_OF_RESOURCES  A memory allocation failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MoveWithinFileSystems(\r
+  IN EFI_SHELL_FILE_INFO  *Node,\r
+  IN CHAR16               *DestPath,\r
+  OUT VOID                **Resp\r
+  )\r
+{\r
+  EFI_FILE_INFO             *NewFileInfo;\r
+  CHAR16                    *TempLocation;\r
+  UINTN                     NewSize;\r
+  UINTN                     Length;\r
+  EFI_STATUS                Status;\r
+\r
+  //\r
+  // Chop off map info from DestPath\r
+  //\r
+  if ((TempLocation = StrStr(DestPath, L":")) != NULL) {\r
+    CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1));\r
+  }\r
+\r
+  //\r
+  // construct the new file info block\r
+  //\r
+  NewSize = StrSize(DestPath);\r
+  NewSize += StrSize(Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);\r
+  NewFileInfo = AllocateZeroPool(NewSize);\r
+  if (NewFileInfo == NULL) {\r
+    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+  } else {\r
+    CopyMem(NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO);\r
+    if (DestPath[0] != L'\\') {\r
+      StrCpy(NewFileInfo->FileName, L"\\");\r
+      StrCat(NewFileInfo->FileName, DestPath);\r
+    } else {\r
+      StrCpy(NewFileInfo->FileName, DestPath);\r
+    }\r
+    Length = StrLen(NewFileInfo->FileName);\r
+    if (Length > 0) {\r
+      Length--;\r
+    }\r
+    if (NewFileInfo->FileName[Length] == L'\\') {\r
+      if (Node->FileName[0] == L'\\') {\r
+        //\r
+        // Don't allow for double slashes. Eliminate one of them.\r
+        //\r
+        NewFileInfo->FileName[Length] = CHAR_NULL;\r
+      }\r
+      StrCat(NewFileInfo->FileName, Node->FileName);\r
+    }\r
+    NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize(NewFileInfo->FileName);\r
+\r
+    //\r
+    // Perform the move operation\r
+    //\r
+    Status = ShellSetFileInfo(Node->Handle, NewFileInfo);\r
+\r
+    //\r
+    // Free the info object we used...\r
+    //\r
+    FreePool(NewFileInfo);\r
+  }\r
+\r
+  return (Status);\r
+}\r
 /**\r
   function to take a list of files to move and a destination location and do\r
   the verification and moving of those files to that location.  This function\r
@@ -241,7 +435,7 @@ GetDestinationLocation(
 \r
   @param[in] FileList           A LIST_ENTRY* based list of files to move\r
   @param[out] Resp              pointer to response from question.  Pass back on looped calling\r
-  @param[in] DestDir            the destination location\r
+  @param[in] DestParameter      the originally specified destination location\r
 \r
   @retval SHELL_SUCCESS             the files were all moved.\r
   @retval SHELL_INVALID_PARAMETER   a parameter was invalid\r
@@ -252,60 +446,66 @@ GetDestinationLocation(
 SHELL_STATUS\r
 EFIAPI\r
 ValidateAndMoveFiles(\r
-  IN CONST EFI_SHELL_FILE_INFO  *FileList,\r
+  IN EFI_SHELL_FILE_INFO        *FileList,\r
   OUT VOID                      **Resp,\r
-  IN CONST CHAR16               *DestDir\r
+  IN CONST CHAR16               *DestParameter\r
   )\r
 {\r
   EFI_STATUS                Status;\r
   CHAR16                    *HiiOutput;\r
   CHAR16                    *HiiResultOk;\r
   CHAR16                    *DestPath;\r
+  CHAR16                    *FullDestPath;\r
   CONST CHAR16              *Cwd;\r
   SHELL_STATUS              ShellStatus;\r
-  CONST EFI_SHELL_FILE_INFO *Node;\r
-  EFI_FILE_INFO             *NewFileInfo;\r
-  CHAR16                    *TempLocation;\r
-  UINTN                     NewSize;\r
-  UINTN                     Length;\r
+  EFI_SHELL_FILE_INFO       *Node;\r
   VOID                      *Response;\r
-  SHELL_FILE_HANDLE         DestHandle;\r
+  UINT64                    Attr;\r
   CHAR16                    *CleanFilePathStr;\r
 \r
   ASSERT(FileList != NULL);\r
-  ASSERT(DestDir  != NULL);\r
+  ASSERT(DestParameter  != NULL);\r
 \r
-  DestPath         = NULL;\r
-  Cwd              = ShellGetCurrentDir(NULL);\r
-  Response         = *Resp;\r
-  CleanFilePathStr = NULL;\r
+  DestPath          = NULL;\r
+  FullDestPath      = NULL;\r
+  Cwd               = ShellGetCurrentDir(NULL);\r
+  Response          = *Resp;\r
+  Attr              = 0;\r
+  CleanFilePathStr  = NULL;\r
 \r
-  Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr);\r
+  Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr);\r
   if (EFI_ERROR (Status)) {\r
     if (Status == EFI_OUT_OF_RESOURCES) {\r
       return SHELL_OUT_OF_RESOURCES;\r
     } else {\r
       return SHELL_INVALID_PARAMETER;\r
     }\r
-  }  \r
+  }\r
 \r
   ASSERT (CleanFilePathStr != NULL);\r
 \r
   //\r
   // Get and validate the destination location\r
   //\r
-  ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, Cwd);\r
+  ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, Cwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr);\r
   FreePool (CleanFilePathStr);\r
+\r
   if (ShellStatus != SHELL_SUCCESS) {\r
     return (ShellStatus);\r
   }\r
   DestPath = PathCleanUpDirectories(DestPath);\r
+  if (DestPath == NULL) {\r
+    return (SHELL_OUT_OF_RESOURCES);\r
+  }\r
 \r
   HiiOutput   = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);\r
   HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);\r
-  ASSERT  (DestPath     != NULL);\r
-  ASSERT  (HiiResultOk  != NULL);\r
-  ASSERT  (HiiOutput    != NULL);\r
+  if (HiiOutput == NULL || HiiResultOk == NULL) {\r
+    SHELL_FREE_NON_NULL(DestPath);\r
+    SHELL_FREE_NON_NULL(HiiOutput);\r
+    SHELL_FREE_NON_NULL(HiiResultOk);\r
+    return (SHELL_OUT_OF_RESOURCES);\r
+  }\r
 \r
   //\r
   // Go through the list of files and directories to move...\r
@@ -332,127 +532,90 @@ ValidateAndMoveFiles(
       continue;\r
     }\r
 \r
+    SHELL_FREE_NON_NULL(FullDestPath);\r
+    FullDestPath = NULL;\r
+    if (ShellIsDirectory(DestPath)==EFI_SUCCESS) {\r
+      CreateFullDestPath((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName);\r
+    }\r
+\r
     //\r
     // Validate that the move is valid\r
     //\r
-    if (!IsValidMove(Node->FullName, Cwd, DestPath, Node->Info->Attribute, Node->Status)) {\r
+    if (!IsValidMove(Node->FullName, Cwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) {\r
       ShellStatus = SHELL_INVALID_PARAMETER;\r
       continue;\r
     }\r
 \r
-    //\r
-    // Chop off map info from "DestPath"\r
-    //\r
-    if ((TempLocation = StrStr(DestPath, L":")) != NULL) {\r
-      CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1));\r
-    }\r
+    ShellPrintEx(-1, -1, HiiOutput, Node->FullName, FullDestPath!=NULL? FullDestPath:DestPath);\r
 \r
     //\r
-    // construct the new file info block\r
+    // See if destination exists\r
     //\r
-    NewSize = StrSize(DestPath);\r
-    NewSize += StrSize(Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);\r
-    NewFileInfo = AllocateZeroPool(NewSize);\r
-    if (NewFileInfo == NULL) {\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);\r
-      ShellStatus = SHELL_OUT_OF_RESOURCES;\r
-    } else {\r
-      CopyMem(NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO);\r
-      if (DestPath[0] != L'\\') {\r
-        StrCpy(NewFileInfo->FileName, L"\\");\r
-        StrCat(NewFileInfo->FileName, DestPath);\r
-      } else {\r
-        StrCpy(NewFileInfo->FileName, DestPath);\r
-      }\r
-      Length = StrLen(NewFileInfo->FileName);\r
-      if (Length > 0) {\r
-        Length--;\r
+    if (!EFI_ERROR(ShellFileExists(FullDestPath!=NULL? FullDestPath:DestPath))) {\r
+      if (Response == NULL) {\r
+        ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
       }\r
-      if (NewFileInfo->FileName[Length] == L'\\') {\r
-        if (Node->FileName[0] == L'\\') {\r
+      switch (*(SHELL_PROMPT_RESPONSE*)Response) {\r
+        case ShellPromptResponseNo:\r
+          FreePool(Response);\r
+          Response = NULL;\r
+          continue;\r
+        case ShellPromptResponseCancel:\r
+          *Resp = Response;\r
           //\r
-          // Don't allow for double slashes. Eliminate one of them.\r
+          // indicate to stop everything\r
           //\r
-          NewFileInfo->FileName[Length] = CHAR_NULL;\r
-        }\r
-        StrCat(NewFileInfo->FileName, Node->FileName);\r
+          return (SHELL_ABORTED);\r
+        case ShellPromptResponseAll:\r
+          *Resp = Response;\r
+          break;\r
+        case ShellPromptResponseYes:\r
+          FreePool(Response);\r
+          Response = NULL;\r
+          break;\r
+        default:\r
+          FreePool(Response);\r
+          return SHELL_ABORTED;\r
       }\r
-      NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize(NewFileInfo->FileName);\r
-      ShellPrintEx(-1, -1, HiiOutput, Node->FullName, NewFileInfo->FileName);\r
+      Status = ShellDeleteFileByName(FullDestPath!=NULL? FullDestPath:DestPath);\r
+    }\r
 \r
-      if (!EFI_ERROR(ShellFileExists(NewFileInfo->FileName))) {\r
-        if (Response == NULL) {\r
-          ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
-        }\r
-        switch (*(SHELL_PROMPT_RESPONSE*)Response) {\r
-          case ShellPromptResponseNo:\r
-            FreePool(NewFileInfo);\r
-            continue;\r
-          case ShellPromptResponseCancel:\r
-            *Resp = Response;\r
-            //\r
-            // indicate to stop everything\r
-            //\r
-            FreePool(NewFileInfo);\r
-            FreePool(DestPath);\r
-            FreePool(HiiOutput);\r
-            FreePool(HiiResultOk);\r
-            return (SHELL_ABORTED);\r
-          case ShellPromptResponseAll:\r
-            *Resp = Response;\r
-            break;\r
-          case ShellPromptResponseYes:\r
-            FreePool(Response);\r
-            break;\r
-          default:\r
-            FreePool(Response);\r
-            FreePool(NewFileInfo);\r
-            FreePool(DestPath);\r
-            FreePool(HiiOutput);\r
-            FreePool(HiiResultOk);\r
-            return SHELL_ABORTED;\r
-        }\r
-        Status = ShellOpenFileByName(NewFileInfo->FileName, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);\r
-        ShellDeleteFile(&DestHandle);\r
+    if (IsBetweenFileSystem(Node->FullName, Cwd, DestPath)) {\r
+      while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen(DestPath) - 1] == L'\\') {\r
+        DestPath[StrLen(DestPath) - 1] = CHAR_NULL;\r
       }\r
+      Status = MoveBetweenFileSystems(Node, FullDestPath!=NULL? FullDestPath:DestPath, &Response);\r
+    } else {\r
+      Status = MoveWithinFileSystems(Node, DestPath, &Response);\r
+    }\r
 \r
-\r
-      //\r
-      // Perform the move operation\r
-      //\r
-      Status = ShellSetFileInfo(Node->Handle, NewFileInfo);\r
-\r
-      //\r
-      // Free the info object we used...\r
-      //\r
-      FreePool(NewFileInfo);\r
-\r
-      //\r
-      // Check our result\r
-      //\r
-      if (EFI_ERROR(Status)) {\r
-        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status);\r
-        ShellStatus = SHELL_INVALID_PARAMETER;\r
-        if (Status == EFI_SECURITY_VIOLATION) {\r
-          ShellStatus = SHELL_SECURITY_VIOLATION;\r
-        } else if (Status == EFI_WRITE_PROTECTED) {\r
-          ShellStatus = SHELL_WRITE_PROTECTED;\r
-        } else if (Status == EFI_OUT_OF_RESOURCES) {\r
-          ShellStatus = SHELL_OUT_OF_RESOURCES;\r
-        } else if (Status == EFI_DEVICE_ERROR) {\r
-          ShellStatus = SHELL_DEVICE_ERROR;\r
-        } else if (Status == EFI_ACCESS_DENIED) {\r
-          ShellStatus = SHELL_ACCESS_DENIED;\r
-        }\r
-      } else {\r
-        ShellPrintEx(-1, -1, L"%s", HiiResultOk);\r
+    //\r
+    // Check our result\r
+    //\r
+    if (EFI_ERROR(Status)) {\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status);\r
+      ShellStatus = SHELL_INVALID_PARAMETER;\r
+      if (Status == EFI_SECURITY_VIOLATION) {\r
+        ShellStatus = SHELL_SECURITY_VIOLATION;\r
+      } else if (Status == EFI_WRITE_PROTECTED) {\r
+        ShellStatus = SHELL_WRITE_PROTECTED;\r
+      } else if (Status == EFI_OUT_OF_RESOURCES) {\r
+        ShellStatus = SHELL_OUT_OF_RESOURCES;\r
+      } else if (Status == EFI_DEVICE_ERROR) {\r
+        ShellStatus = SHELL_DEVICE_ERROR;\r
+      } else if (Status == EFI_ACCESS_DENIED) {\r
+        ShellStatus = SHELL_ACCESS_DENIED;\r
       }\r
+    } else {\r
+      ShellPrintEx(-1, -1, L"%s", HiiResultOk);\r
     }\r
-  } // for loop\r
 \r
-  FreePool(DestPath);\r
-  FreePool(HiiOutput);\r
-  FreePool(HiiResultOk);\r
+  } // main for loop\r
+\r
+  SHELL_FREE_NON_NULL(FullDestPath);\r
+  SHELL_FREE_NON_NULL(DestPath);\r
+  SHELL_FREE_NON_NULL(HiiOutput);\r
+  SHELL_FREE_NON_NULL(HiiResultOk);\r
   return (ShellStatus);\r
 }\r
 \r
@@ -496,7 +659,7 @@ ShellCommandRunMv (
   Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);\r
   if (EFI_ERROR(Status)) {\r
     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"mv", ProblemParam);  \r
       FreePool(ProblemParam);\r
       ShellStatus = SHELL_INVALID_PARAMETER;\r
     } else {\r
@@ -516,7 +679,7 @@ ShellCommandRunMv (
         //\r
         // we have insufficient parameters\r
         //\r
-        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle);\r
+        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mv");  \r
         ShellStatus = SHELL_INVALID_PARAMETER;\r
         break;\r
       case 2:\r
@@ -524,12 +687,12 @@ ShellCommandRunMv (
         // must have valid CWD for single parameter...\r
         //\r
         if (ShellGetCurrentDir(NULL) == NULL){\r
-          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);\r
+          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"mv");  \r
           ShellStatus = SHELL_INVALID_PARAMETER;\r
         } else {\r
           Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
           if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
-            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));\r
+            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1));  \r
             ShellStatus = SHELL_NOT_FOUND;\r
           } else  {\r
             //\r
@@ -548,7 +711,7 @@ ShellCommandRunMv (
           }\r
           Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
           if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
-            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, LoopCounter));\r
+            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, LoopCounter));  \r
             ShellStatus = SHELL_NOT_FOUND;\r
           } else  {\r
             //\r
@@ -565,7 +728,7 @@ ShellCommandRunMv (
             Status = ShellCloseFileMetaArg(&FileList);\r
             if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
               ShellStatus = SHELL_ACCESS_DENIED;\r
-              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);\r
+              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);  \r
             }\r
           }\r
         }\r