Home | History | Annotate | Download | only in UefiShellLevel2CommandsLib
      1 /** @file
      2   Main file for mv shell level 2 function.
      3 
      4   (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "UefiShellLevel2CommandsLib.h"
     17 
     18 /**
     19   function to determine if a move is between file systems.
     20 
     21   @param FullName [in]    The name of the file to move.
     22   @param Cwd      [in]    The current working directory
     23   @param DestPath [in]    The target location to move to
     24 
     25   @retval TRUE            The move is across file system.
     26   @retval FALSE           The move is within a file system.
     27 **/
     28 BOOLEAN
     29 EFIAPI
     30 IsBetweenFileSystem(
     31   IN CONST CHAR16     *FullName,
     32   IN CONST CHAR16     *Cwd,
     33   IN CONST CHAR16     *DestPath
     34   )
     35 {
     36   CHAR16  *Test;
     37   CHAR16  *Test1;
     38   UINTN   Result;
     39 
     40   Test = StrStr(FullName, L":");
     41   if (Test == NULL && Cwd != NULL) {
     42     Test = StrStr(Cwd, L":");
     43   }
     44   Test1 = StrStr(DestPath, L":");
     45   if (Test1 == NULL && Cwd != NULL) {
     46     Test1 = StrStr(Cwd, L":");
     47   }
     48   if (Test1 != NULL && Test != NULL) {
     49     *Test = CHAR_NULL;
     50     *Test1 = CHAR_NULL;
     51     Result = StringNoCaseCompare(&FullName, &DestPath);
     52     *Test = L':';
     53     *Test1 = L':';
     54     if (Result != 0) {
     55       return (TRUE);
     56     }
     57   }
     58   return (FALSE);
     59 }
     60 
     61 /**
     62   Function to validate that moving a specific file (FileName) to a specific
     63   location (DestPath) is valid.
     64 
     65   This function will verify that the destination is not a subdirectory of
     66   FullName, that the Current working Directory is not being moved, and that
     67   the directory is not read only.
     68 
     69   if the move is invalid this function will report the error to StdOut.
     70 
     71   @param SourcePath [in]    The name of the file to move.
     72   @param Cwd        [in]    The current working directory
     73   @param DestPath   [in]    The target location to move to
     74   @param Attribute  [in]    The Attribute of the file
     75   @param DestAttr   [in]    The Attribute of the destination
     76   @param FileStatus [in]    The Status of the file when opened
     77 
     78   @retval TRUE        The move is valid
     79   @retval FALSE       The move is not
     80 **/
     81 BOOLEAN
     82 EFIAPI
     83 IsValidMove(
     84   IN CONST CHAR16     *SourcePath,
     85   IN CONST CHAR16     *Cwd,
     86   IN CONST CHAR16     *DestPath,
     87   IN CONST UINT64     Attribute,
     88   IN CONST UINT64     DestAttr,
     89   IN CONST EFI_STATUS FileStatus
     90   )
     91 {
     92   CHAR16  *DestPathCopy;
     93   CHAR16  *DestPathWalker;
     94 
     95   if (Cwd != NULL && StrCmp(SourcePath, Cwd) == 0) {
     96     //
     97     // Invalid move
     98     //
     99     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle);
    100     return (FALSE);
    101   }
    102 
    103   //
    104   // invalid to move read only or move to a read only destination
    105   //
    106   if (((Attribute & EFI_FILE_READ_ONLY) != 0)
    107     || (FileStatus == EFI_WRITE_PROTECTED)
    108     || ((DestAttr & EFI_FILE_READ_ONLY) != 0)
    109     ) {
    110     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle, SourcePath);
    111     return (FALSE);
    112   }
    113 
    114   DestPathCopy = AllocateCopyPool(StrSize(DestPath), DestPath);
    115   if (DestPathCopy == NULL) {
    116     return (FALSE);
    117   }
    118 
    119   for (DestPathWalker = DestPathCopy; *DestPathWalker == L'\\'; DestPathWalker++) ;
    120 
    121   while(DestPathWalker != NULL && DestPathWalker[StrLen(DestPathWalker)-1] == L'\\') {
    122     DestPathWalker[StrLen(DestPathWalker)-1] = CHAR_NULL;
    123   }
    124 
    125   ASSERT(DestPathWalker != NULL);
    126   ASSERT(SourcePath   != NULL);
    127 
    128   //
    129   // If they're the same, or if source is "above" dest on file path tree
    130   //
    131   if ( StringNoCaseCompare (&DestPathWalker, &SourcePath) == 0 ||
    132        ((StrStr(DestPathWalker, SourcePath) == DestPathWalker) &&
    133         (DestPathWalker[StrLen(SourcePath)] == '\\')
    134        )
    135      ) {
    136     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);
    137     FreePool(DestPathCopy);
    138     return (FALSE);
    139   }
    140   FreePool(DestPathCopy);
    141 
    142   return (TRUE);
    143 }
    144 
    145 /**
    146   Function to take a destination path that might contain wildcards and verify
    147   that there is only a single possible target (IE we cant have wildcards that
    148   have 2 possible destination).
    149 
    150   if the result is sucessful the caller must free *DestPathPointer.
    151 
    152   @param[in] DestParameter               The original path to the destination.
    153   @param[in, out] DestPathPointer  A pointer to the callee allocated final path.
    154   @param[in] Cwd                   A pointer to the current working directory.
    155   @param[in] SingleSource          TRUE to have only one source file.
    156   @param[in, out] DestAttr         A pointer to the destination information attribute.
    157 
    158   @retval SHELL_INVALID_PARAMETER  The DestParameter could not be resolved to a location.
    159   @retval SHELL_INVALID_PARAMETER  The DestParameter could be resolved to more than 1 location.
    160   @retval SHELL_INVALID_PARAMETER  Cwd is required and is NULL.
    161   @retval SHELL_SUCCESS            The operation was sucessful.
    162 **/
    163 SHELL_STATUS
    164 EFIAPI
    165 GetDestinationLocation(
    166   IN CONST CHAR16               *DestParameter,
    167   IN OUT CHAR16                 **DestPathPointer,
    168   IN CONST CHAR16               *Cwd,
    169   IN CONST BOOLEAN              SingleSource,
    170   IN OUT UINT64                 *DestAttr
    171   )
    172 {
    173   EFI_SHELL_FILE_INFO       *DestList;
    174   EFI_SHELL_FILE_INFO       *Node;
    175   CHAR16                    *DestPath;
    176   UINTN                     NewSize;
    177   UINTN                     CurrentSize;
    178 
    179   DestList = NULL;
    180   DestPath = NULL;
    181 
    182   ASSERT(DestAttr != NULL);
    183 
    184   if (StrStr(DestParameter, L"\\") == DestParameter) {
    185     if (Cwd == NULL) {
    186       return SHELL_INVALID_PARAMETER;
    187     }
    188     DestPath = AllocateZeroPool(StrSize(Cwd));
    189     if (DestPath == NULL) {
    190       return (SHELL_OUT_OF_RESOURCES);
    191     }
    192     StrCpyS(DestPath, StrSize(Cwd) / sizeof(CHAR16), Cwd);
    193     while (PathRemoveLastItem(DestPath)) ;
    194 
    195     //
    196     // Append DestParameter beyond '\' which may be present
    197     //
    198     CurrentSize = StrSize(DestPath);
    199     StrnCatGrow(&DestPath, &CurrentSize, &DestParameter[1], 0);
    200 
    201     *DestPathPointer =  DestPath;
    202     return (SHELL_SUCCESS);
    203   }
    204   //
    205   // get the destination path
    206   //
    207   ShellOpenFileMetaArg((CHAR16*)DestParameter, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);
    208   if (DestList == NULL || IsListEmpty(&DestList->Link)) {
    209     //
    210     // Not existing... must be renaming
    211     //
    212     if (StrStr(DestParameter, L":") == NULL) {
    213       if (Cwd == NULL) {
    214         ShellCloseFileMetaArg(&DestList);
    215         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
    216         return (SHELL_INVALID_PARAMETER);
    217       }
    218       NewSize = StrSize(Cwd);
    219       NewSize += StrSize(DestParameter);
    220       DestPath = AllocateZeroPool(NewSize);
    221       if (DestPath == NULL) {
    222         ShellCloseFileMetaArg(&DestList);
    223         return (SHELL_OUT_OF_RESOURCES);
    224       }
    225       StrCpyS(DestPath, NewSize / sizeof(CHAR16), Cwd);
    226       if (DestPath[StrLen(DestPath)-1] != L'\\' && DestParameter[0] != L'\\') {
    227         StrCatS(DestPath, NewSize / sizeof(CHAR16), L"\\");
    228       } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestParameter[0] == L'\\') {
    229         ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
    230       }
    231       StrCatS(DestPath, NewSize / sizeof(CHAR16), DestParameter);
    232     } else {
    233       ASSERT(DestPath == NULL);
    234       DestPath = StrnCatGrow(&DestPath, NULL, DestParameter, 0);
    235       if (DestPath == NULL) {
    236         ShellCloseFileMetaArg(&DestList);
    237         return (SHELL_OUT_OF_RESOURCES);
    238       }
    239     }
    240   } else {
    241     Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link);
    242     *DestAttr = Node->Info->Attribute;
    243     //
    244     // Make sure there is only 1 node in the list.
    245     //
    246     if (!IsNodeAtEnd(&DestList->Link, &Node->Link)) {
    247       ShellCloseFileMetaArg(&DestList);
    248       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);
    249       return (SHELL_INVALID_PARAMETER);
    250     }
    251 
    252     //
    253     // If we are a directory or a single file, then one node is fine.
    254     //
    255     if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS || SingleSource) {
    256       DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16));
    257       if (DestPath == NULL) {
    258         ShellCloseFileMetaArg(&DestList);
    259         return (SHELL_OUT_OF_RESOURCES);
    260       }
    261       StrCpyS(DestPath, (StrSize(Node->FullName)+sizeof(CHAR16)) / sizeof(CHAR16), Node->FullName);
    262       StrCatS(DestPath, (StrSize(Node->FullName)+sizeof(CHAR16)) / sizeof(CHAR16), L"\\");
    263     } else {
    264       //
    265       // cant move multiple files onto a single file.
    266       //
    267       ShellCloseFileMetaArg(&DestList);
    268       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);
    269       return (SHELL_INVALID_PARAMETER);
    270     }
    271   }
    272 
    273   *DestPathPointer =  DestPath;
    274   ShellCloseFileMetaArg(&DestList);
    275 
    276   return (SHELL_SUCCESS);
    277 }
    278 
    279 /**
    280   Function to do a move across file systems.
    281 
    282   @param[in] Node               A pointer to the file to be removed.
    283   @param[in] DestPath           A pointer to the destination file path.
    284   @param[out] Resp              A pointer to response from question.  Pass back on looped calling
    285 
    286   @retval SHELL_SUCCESS     The source file was moved to the destination.
    287 **/
    288 EFI_STATUS
    289 EFIAPI
    290 MoveBetweenFileSystems(
    291   IN EFI_SHELL_FILE_INFO  *Node,
    292   IN CONST CHAR16         *DestPath,
    293   OUT VOID                **Resp
    294   )
    295 {
    296   SHELL_STATUS    ShellStatus;
    297 
    298   //
    299   // First we copy the file
    300   //
    301   ShellStatus = CopySingleFile (Node->FullName, DestPath, Resp, TRUE, L"mv");
    302 
    303   //
    304   // Check our result
    305   //
    306   if (ShellStatus == SHELL_SUCCESS) {
    307     //
    308     // The copy was successful.  delete the source file.
    309     //
    310     CascadeDelete(Node, TRUE);
    311     Node->Handle = NULL;
    312   } else if (ShellStatus == SHELL_ABORTED) {
    313     return EFI_ABORTED;
    314   } else if (ShellStatus == SHELL_ACCESS_DENIED) {
    315     return EFI_ACCESS_DENIED;
    316   } else if (ShellStatus == SHELL_VOLUME_FULL) {
    317     return EFI_VOLUME_FULL;
    318   } else {
    319     return EFI_UNSUPPORTED;
    320   }
    321 
    322   return (EFI_SUCCESS);
    323 }
    324 
    325 /**
    326   Function to take the destination path and target file name to generate the full destination path.
    327 
    328   @param[in] DestPath           A pointer to the destination file path string.
    329   @param[out] FullDestPath      A pointer to the full destination path string.
    330   @param[in] FileName           Name string of  the targe file.
    331 
    332   @retval SHELL_SUCCESS             the files were all moved.
    333   @retval SHELL_INVALID_PARAMETER   a parameter was invalid
    334   @retval SHELL_OUT_OF_RESOURCES    a memory allocation failed
    335 **/
    336 EFI_STATUS
    337 EFIAPI
    338 CreateFullDestPath(
    339   IN CONST CHAR16 **DestPath,
    340   OUT CHAR16      **FullDestPath,
    341   IN CONST CHAR16 *FileName
    342   )
    343 {
    344   UINTN Size;
    345   if (FullDestPath == NULL || FileName == NULL || DestPath == NULL || *DestPath == NULL){
    346     return (EFI_INVALID_PARAMETER);
    347   }
    348 
    349   Size = StrSize(*DestPath) + StrSize(FileName);
    350 
    351   *FullDestPath = AllocateZeroPool(Size);
    352   if (*FullDestPath == NULL){
    353     return (EFI_OUT_OF_RESOURCES);
    354   }
    355 
    356   StrCpyS(*FullDestPath, Size / sizeof(CHAR16), *DestPath);
    357   if ((*FullDestPath)[StrLen(*FullDestPath)-1] != L'\\' && FileName[0] != L'\\') {
    358     StrCatS(*FullDestPath, Size / sizeof(CHAR16), L"\\");
    359   }
    360   StrCatS(*FullDestPath, Size / sizeof(CHAR16), FileName);
    361 
    362   return (EFI_SUCCESS);
    363 }
    364 
    365 /**
    366   Function to do a move within a file system.
    367 
    368   @param[in] Node               A pointer to the file to be removed.
    369   @param[in] DestPath           A pointer to the destination file path.
    370   @param[out] Resp              A pointer to response from question.  Pass back on looped calling.
    371 
    372   @retval SHELL_SUCCESS           The source file was moved to the destination.
    373   @retval SHELL_OUT_OF_RESOURCES  A memory allocation failed.
    374 **/
    375 EFI_STATUS
    376 EFIAPI
    377 MoveWithinFileSystems(
    378   IN EFI_SHELL_FILE_INFO  *Node,
    379   IN CHAR16               *DestPath,
    380   OUT VOID                **Resp
    381   )
    382 {
    383   EFI_FILE_INFO             *NewFileInfo;
    384   CHAR16                    *TempLocation;
    385   UINTN                     NewSize;
    386   UINTN                     Length;
    387   EFI_STATUS                Status;
    388 
    389   //
    390   // Chop off map info from DestPath
    391   //
    392   if ((TempLocation = StrStr(DestPath, L":")) != NULL) {
    393     CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1));
    394   }
    395 
    396   //
    397   // construct the new file info block
    398   //
    399   NewSize = StrSize(DestPath);
    400   NewSize += StrSize(Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);
    401   NewFileInfo = AllocateZeroPool(NewSize);
    402   if (NewFileInfo == NULL) {
    403     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);
    404     Status = EFI_OUT_OF_RESOURCES;
    405   } else {
    406     CopyMem(NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO);
    407     if (DestPath[0] != L'\\') {
    408       StrCpyS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), L"\\");
    409       StrCatS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), DestPath);
    410     } else {
    411       StrCpyS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), DestPath);
    412     }
    413     Length = StrLen(NewFileInfo->FileName);
    414     if (Length > 0) {
    415       Length--;
    416     }
    417     if (NewFileInfo->FileName[Length] == L'\\') {
    418       if (Node->FileName[0] == L'\\') {
    419         //
    420         // Don't allow for double slashes. Eliminate one of them.
    421         //
    422         NewFileInfo->FileName[Length] = CHAR_NULL;
    423       }
    424       StrCatS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), Node->FileName);
    425     }
    426     NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize(NewFileInfo->FileName);
    427 
    428     //
    429     // Perform the move operation
    430     //
    431     Status = ShellSetFileInfo(Node->Handle, NewFileInfo);
    432 
    433     //
    434     // Free the info object we used...
    435     //
    436     FreePool(NewFileInfo);
    437   }
    438 
    439   return (Status);
    440 }
    441 /**
    442   function to take a list of files to move and a destination location and do
    443   the verification and moving of those files to that location.  This function
    444   will report any errors to the user and continue to move the rest of the files.
    445 
    446   @param[in] FileList           A LIST_ENTRY* based list of files to move
    447   @param[out] Resp              pointer to response from question.  Pass back on looped calling
    448   @param[in] DestParameter      the originally specified destination location
    449 
    450   @retval SHELL_SUCCESS             the files were all moved.
    451   @retval SHELL_INVALID_PARAMETER   a parameter was invalid
    452   @retval SHELL_SECURITY_VIOLATION  a security violation ocurred
    453   @retval SHELL_WRITE_PROTECTED     the destination was write protected
    454   @retval SHELL_OUT_OF_RESOURCES    a memory allocation failed
    455 **/
    456 SHELL_STATUS
    457 EFIAPI
    458 ValidateAndMoveFiles(
    459   IN EFI_SHELL_FILE_INFO        *FileList,
    460   OUT VOID                      **Resp,
    461   IN CONST CHAR16               *DestParameter
    462   )
    463 {
    464   EFI_STATUS                Status;
    465   CHAR16                    *HiiOutput;
    466   CHAR16                    *HiiResultOk;
    467   CHAR16                    *DestPath;
    468   CHAR16                    *FullDestPath;
    469   CONST CHAR16              *Cwd;
    470   CHAR16                    *FullCwd;
    471   SHELL_STATUS              ShellStatus;
    472   EFI_SHELL_FILE_INFO       *Node;
    473   VOID                      *Response;
    474   UINT64                    Attr;
    475   CHAR16                    *CleanFilePathStr;
    476 
    477   ASSERT(FileList != NULL);
    478   ASSERT(DestParameter  != NULL);
    479 
    480   DestPath          = NULL;
    481   FullDestPath      = NULL;
    482   Cwd               = ShellGetCurrentDir(NULL);
    483   Response          = *Resp;
    484   Attr              = 0;
    485   CleanFilePathStr  = NULL;
    486 
    487   FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16));
    488   if (FullCwd == NULL) {
    489     return SHELL_OUT_OF_RESOURCES;
    490   } else {
    491     StrCpyS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, Cwd);
    492     StrCatS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, L"\\");
    493   }
    494 
    495   Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr);
    496   if (EFI_ERROR (Status)) {
    497     FreePool (FullCwd);
    498     if (Status == EFI_OUT_OF_RESOURCES) {
    499       return SHELL_OUT_OF_RESOURCES;
    500     } else {
    501       return SHELL_INVALID_PARAMETER;
    502     }
    503   }
    504 
    505   ASSERT (CleanFilePathStr != NULL);
    506 
    507   //
    508   // Get and validate the destination location
    509   //
    510   ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, FullCwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr);
    511   FreePool (CleanFilePathStr);
    512 
    513   if (ShellStatus != SHELL_SUCCESS) {
    514     FreePool (FullCwd);
    515     return (ShellStatus);
    516   }
    517   DestPath = PathCleanUpDirectories(DestPath);
    518   if (DestPath == NULL) {
    519     FreePool (FullCwd);
    520     return (SHELL_OUT_OF_RESOURCES);
    521   }
    522 
    523   HiiOutput   = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);
    524   HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
    525   if (HiiOutput == NULL || HiiResultOk == NULL) {
    526     SHELL_FREE_NON_NULL(DestPath);
    527     SHELL_FREE_NON_NULL(HiiOutput);
    528     SHELL_FREE_NON_NULL(HiiResultOk);
    529     FreePool (FullCwd);
    530     return (SHELL_OUT_OF_RESOURCES);
    531   }
    532 
    533   //
    534   // Go through the list of files and directories to move...
    535   //
    536   for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
    537     ;  !IsNull(&FileList->Link, &Node->Link)
    538     ;  Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
    539    ){
    540     if (ShellGetExecutionBreakFlag()) {
    541       break;
    542     }
    543 
    544     //
    545     // These should never be NULL
    546     //
    547     ASSERT(Node->FileName != NULL);
    548     ASSERT(Node->FullName != NULL);
    549     ASSERT(Node->Info     != NULL);
    550 
    551     //
    552     // skip the directory traversing stuff...
    553     //
    554     if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
    555       continue;
    556     }
    557 
    558     SHELL_FREE_NON_NULL(FullDestPath);
    559     FullDestPath = NULL;
    560     if (ShellIsDirectory(DestPath)==EFI_SUCCESS) {
    561       CreateFullDestPath((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName);
    562     }
    563 
    564     //
    565     // Validate that the move is valid
    566     //
    567     if (!IsValidMove(Node->FullName, FullCwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) {
    568       ShellStatus = SHELL_INVALID_PARAMETER;
    569       continue;
    570     }
    571 
    572     ShellPrintEx(-1, -1, HiiOutput, Node->FullName, FullDestPath!=NULL? FullDestPath:DestPath);
    573 
    574     //
    575     // See if destination exists
    576     //
    577     if (!EFI_ERROR(ShellFileExists(FullDestPath!=NULL? FullDestPath:DestPath))) {
    578       if (Response == NULL) {
    579         ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
    580       }
    581       switch (*(SHELL_PROMPT_RESPONSE*)Response) {
    582         case ShellPromptResponseNo:
    583           FreePool(Response);
    584           Response = NULL;
    585           continue;
    586         case ShellPromptResponseCancel:
    587           *Resp = Response;
    588           //
    589           // indicate to stop everything
    590           //
    591           FreePool(FullCwd);
    592           return (SHELL_ABORTED);
    593         case ShellPromptResponseAll:
    594           *Resp = Response;
    595           break;
    596         case ShellPromptResponseYes:
    597           FreePool(Response);
    598           Response = NULL;
    599           break;
    600         default:
    601           FreePool(Response);
    602           FreePool(FullCwd);
    603           return SHELL_ABORTED;
    604       }
    605       Status = ShellDeleteFileByName(FullDestPath!=NULL? FullDestPath:DestPath);
    606     }
    607 
    608     if (IsBetweenFileSystem(Node->FullName, FullCwd, DestPath)) {
    609       while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen(DestPath) - 1] == L'\\') {
    610         DestPath[StrLen(DestPath) - 1] = CHAR_NULL;
    611       }
    612       Status = MoveBetweenFileSystems(Node, FullDestPath!=NULL? FullDestPath:DestPath, &Response);
    613     } else {
    614       Status = MoveWithinFileSystems(Node, DestPath, &Response);
    615       //
    616       // Display error status
    617       //
    618       if (EFI_ERROR(Status)) {
    619         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"mv", Status);
    620       }
    621     }
    622 
    623     //
    624     // Check our result
    625     //
    626     if (EFI_ERROR(Status)) {
    627       ShellStatus = SHELL_INVALID_PARAMETER;
    628       if (Status == EFI_SECURITY_VIOLATION) {
    629         ShellStatus = SHELL_SECURITY_VIOLATION;
    630       } else if (Status == EFI_WRITE_PROTECTED) {
    631         ShellStatus = SHELL_WRITE_PROTECTED;
    632       } else if (Status == EFI_OUT_OF_RESOURCES) {
    633         ShellStatus = SHELL_OUT_OF_RESOURCES;
    634       } else if (Status == EFI_DEVICE_ERROR) {
    635         ShellStatus = SHELL_DEVICE_ERROR;
    636       } else if (Status == EFI_ACCESS_DENIED) {
    637         ShellStatus = SHELL_ACCESS_DENIED;
    638       }
    639     } else {
    640       ShellPrintEx(-1, -1, L"%s", HiiResultOk);
    641     }
    642 
    643   } // main for loop
    644 
    645   SHELL_FREE_NON_NULL(FullDestPath);
    646   SHELL_FREE_NON_NULL(DestPath);
    647   SHELL_FREE_NON_NULL(HiiOutput);
    648   SHELL_FREE_NON_NULL(HiiResultOk);
    649   FreePool (FullCwd);
    650   return (ShellStatus);
    651 }
    652 
    653 /**
    654   Function for 'mv' command.
    655 
    656   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
    657   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
    658 **/
    659 SHELL_STATUS
    660 EFIAPI
    661 ShellCommandRunMv (
    662   IN EFI_HANDLE        ImageHandle,
    663   IN EFI_SYSTEM_TABLE  *SystemTable
    664   )
    665 {
    666   EFI_STATUS          Status;
    667   LIST_ENTRY          *Package;
    668   CHAR16              *ProblemParam;
    669   CHAR16              *Cwd;
    670   UINTN               CwdSize;
    671   SHELL_STATUS        ShellStatus;
    672   UINTN               ParamCount;
    673   UINTN               LoopCounter;
    674   EFI_SHELL_FILE_INFO *FileList;
    675   VOID                *Response;
    676 
    677   ProblemParam        = NULL;
    678   ShellStatus         = SHELL_SUCCESS;
    679   ParamCount          = 0;
    680   FileList            = NULL;
    681   Response            = NULL;
    682 
    683   //
    684   // initialize the shell lib (we must be in non-auto-init...)
    685   //
    686   Status = ShellInitialize();
    687   ASSERT_EFI_ERROR(Status);
    688 
    689   //
    690   // parse the command line
    691   //
    692   Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);
    693   if (EFI_ERROR(Status)) {
    694     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
    695       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"mv", ProblemParam);
    696       FreePool(ProblemParam);
    697       ShellStatus = SHELL_INVALID_PARAMETER;
    698     } else {
    699       ASSERT(FALSE);
    700     }
    701   } else {
    702     //
    703     // check for "-?"
    704     //
    705     if (ShellCommandLineGetFlag(Package, L"-?")) {
    706       ASSERT(FALSE);
    707     }
    708 
    709     switch (ParamCount = ShellCommandLineGetCount(Package)) {
    710       case 0:
    711       case 1:
    712         //
    713         // we have insufficient parameters
    714         //
    715         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mv");
    716         ShellStatus = SHELL_INVALID_PARAMETER;
    717         break;
    718       case 2:
    719         //
    720         // must have valid CWD for single parameter...
    721         //
    722         if (ShellGetCurrentDir(NULL) == NULL){
    723           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"mv");
    724           ShellStatus = SHELL_INVALID_PARAMETER;
    725         } else {
    726           Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
    727           if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
    728             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1));
    729             ShellStatus = SHELL_NOT_FOUND;
    730           } else  {
    731             //
    732             // ValidateAndMoveFiles will report errors to the screen itself
    733             //
    734             CwdSize = StrSize(ShellGetCurrentDir(NULL)) + sizeof(CHAR16);
    735             Cwd = AllocateZeroPool(CwdSize);
    736             ASSERT (Cwd != NULL);
    737             StrCpyS(Cwd, CwdSize/sizeof(CHAR16), ShellGetCurrentDir(NULL));
    738             StrCatS(Cwd, CwdSize/sizeof(CHAR16), L"\\");
    739             ShellStatus = ValidateAndMoveFiles(FileList, &Response, Cwd);
    740             FreePool(Cwd);
    741           }
    742         }
    743 
    744         break;
    745       default:
    746         ///@todo make sure this works with error half way through and continues...
    747         for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount ; LoopCounter++) {
    748           if (ShellGetExecutionBreakFlag()) {
    749             break;
    750           }
    751           Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
    752           if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
    753             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, LoopCounter));
    754             ShellStatus = SHELL_NOT_FOUND;
    755           } else  {
    756             //
    757             // ValidateAndMoveFiles will report errors to the screen itself
    758             // Only change ShellStatus if it's sucessful
    759             //
    760             if (ShellStatus == SHELL_SUCCESS) {
    761               ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));
    762             } else {
    763               ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));
    764             }
    765           }
    766           if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
    767             Status = ShellCloseFileMetaArg(&FileList);
    768             if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
    769               ShellStatus = SHELL_ACCESS_DENIED;
    770               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);
    771             }
    772           }
    773         }
    774         break;
    775     } // switch on parameter count
    776 
    777     if (FileList != NULL) {
    778       ShellCloseFileMetaArg(&FileList);
    779     }
    780 
    781     //
    782     // free the command line package
    783     //
    784     ShellCommandLineFreeVarList (Package);
    785   }
    786 
    787   SHELL_FREE_NON_NULL(Response);
    788 
    789   if (ShellGetExecutionBreakFlag()) {
    790     return (SHELL_ABORTED);
    791   }
    792 
    793   return (ShellStatus);
    794 }
    795