Home | History | Annotate | Download | only in UefiShellLevel2CommandsLib
      1 /** @file
      2   Main file for cp shell level 2 function.
      3 
      4   (C) Copyright 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 #include <Guid/FileSystemInfo.h>
     18 #include <Guid/FileSystemVolumeLabelInfo.h>
     19 
     20 /**
     21   Function to take a list of files to copy and a destination location and do
     22   the verification and copying of those files to that location.  This function
     23   will report any errors to the user and halt.
     24 
     25   @param[in] FileList           A LIST_ENTRY* based list of files to move.
     26   @param[in] DestDir            The destination location.
     27   @param[in] SilentMode         TRUE to eliminate screen output.
     28   @param[in] RecursiveMode      TRUE to copy directories.
     29   @param[in] Resp               The response to the overwrite query (if always).
     30 
     31   @retval SHELL_SUCCESS             the files were all moved.
     32   @retval SHELL_INVALID_PARAMETER   a parameter was invalid
     33   @retval SHELL_SECURITY_VIOLATION  a security violation ocurred
     34   @retval SHELL_WRITE_PROTECTED     the destination was write protected
     35   @retval SHELL_OUT_OF_RESOURCES    a memory allocation failed
     36 **/
     37 SHELL_STATUS
     38 ValidateAndCopyFiles(
     39   IN CONST EFI_SHELL_FILE_INFO  *FileList,
     40   IN CONST CHAR16               *DestDir,
     41   IN BOOLEAN                    SilentMode,
     42   IN BOOLEAN                    RecursiveMode,
     43   IN VOID                       **Resp
     44   );
     45 
     46 /**
     47   Function to Copy one file to another location
     48 
     49   If the destination exists the user will be prompted and the result put into *resp
     50 
     51   @param[in] Source     pointer to source file name
     52   @param[in] Dest       pointer to destination file name
     53   @param[out] Resp      pointer to response from question.  Pass back on looped calling
     54   @param[in] SilentMode whether to run in quiet mode or not
     55   @param[in] CmdName    Source command name requesting single file copy
     56 
     57   @retval SHELL_SUCCESS   The source file was copied to the destination
     58 **/
     59 SHELL_STATUS
     60 CopySingleFile(
     61   IN CONST CHAR16 *Source,
     62   IN CONST CHAR16 *Dest,
     63   OUT VOID        **Resp,
     64   IN BOOLEAN      SilentMode,
     65   IN CONST CHAR16 *CmdName
     66   )
     67 {
     68   VOID                  *Response;
     69   UINTN                 ReadSize;
     70   SHELL_FILE_HANDLE     SourceHandle;
     71   SHELL_FILE_HANDLE     DestHandle;
     72   EFI_STATUS            Status;
     73   VOID                  *Buffer;
     74   CHAR16                *TempName;
     75   UINTN                 Size;
     76   EFI_SHELL_FILE_INFO   *List;
     77   SHELL_STATUS          ShellStatus;
     78   UINT64                SourceFileSize;
     79   UINT64                DestFileSize;
     80   EFI_FILE_PROTOCOL     *DestVolumeFP;
     81   EFI_FILE_SYSTEM_INFO  *DestVolumeInfo;
     82   UINTN                 DestVolumeInfoSize;
     83 
     84   ASSERT(Resp != NULL);
     85 
     86   SourceHandle    = NULL;
     87   DestHandle      = NULL;
     88   Response        = *Resp;
     89   List            = NULL;
     90   DestVolumeInfo  = NULL;
     91   ShellStatus     = SHELL_SUCCESS;
     92 
     93   ReadSize = PcdGet32(PcdShellFileOperationSize);
     94   // Why bother copying a file to itself
     95   if (StrCmp(Source, Dest) == 0) {
     96     return (SHELL_SUCCESS);
     97   }
     98 
     99   //
    100   // if the destination file existed check response and possibly prompt user
    101   //
    102   if (ShellFileExists(Dest) == EFI_SUCCESS) {
    103     if (Response == NULL && !SilentMode) {
    104       Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
    105     }
    106     //
    107     // possibly return based on response
    108     //
    109     if (!SilentMode) {
    110       switch (*(SHELL_PROMPT_RESPONSE*)Response) {
    111         case ShellPromptResponseNo:
    112           //
    113           // return success here so we dont stop the process
    114           //
    115           return (SHELL_SUCCESS);
    116         case ShellPromptResponseCancel:
    117           *Resp = Response;
    118           //
    119           // indicate to stop everything
    120           //
    121           return (SHELL_ABORTED);
    122         case ShellPromptResponseAll:
    123           *Resp = Response;
    124         case ShellPromptResponseYes:
    125           break;
    126         default:
    127           return SHELL_ABORTED;
    128       }
    129     }
    130   }
    131 
    132   if (ShellIsDirectory(Source) == EFI_SUCCESS) {
    133     Status = ShellCreateDirectory(Dest, &DestHandle);
    134     if (EFI_ERROR(Status)) {
    135       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
    136       return (SHELL_ACCESS_DENIED);
    137     }
    138 
    139     //
    140     // Now copy all the files under the directory...
    141     //
    142     TempName    = NULL;
    143     Size        = 0;
    144     StrnCatGrow(&TempName, &Size, Source, 0);
    145     StrnCatGrow(&TempName, &Size, L"\\*", 0);
    146     if (TempName != NULL) {
    147       ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List);
    148       *TempName = CHAR_NULL;
    149       StrnCatGrow(&TempName, &Size, Dest, 0);
    150       StrnCatGrow(&TempName, &Size, L"\\", 0);
    151       ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp);
    152       ShellCloseFileMetaArg(&List);
    153       SHELL_FREE_NON_NULL(TempName);
    154       Size = 0;
    155     }
    156   } else {
    157     Status = ShellDeleteFileByName(Dest);
    158 
    159     //
    160     // open file with create enabled
    161     //
    162     Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
    163     if (EFI_ERROR(Status)) {
    164       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
    165       return (SHELL_ACCESS_DENIED);
    166     }
    167 
    168     //
    169     // open source file
    170     //
    171     Status = ShellOpenFileByName (Source, &SourceHandle, EFI_FILE_MODE_READ, 0);
    172     if (EFI_ERROR (Status)) {
    173       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source);
    174       return (SHELL_ACCESS_DENIED);
    175     }
    176 
    177     //
    178     //get file size of source file and freespace available on destination volume
    179     //
    180     ShellGetFileSize(SourceHandle, &SourceFileSize);
    181     ShellGetFileSize(DestHandle, &DestFileSize);
    182 
    183     //
    184     //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space
    185     //
    186     if(DestFileSize < SourceFileSize){
    187       SourceFileSize -= DestFileSize;
    188     } else {
    189       SourceFileSize = 0;
    190     }
    191 
    192     //
    193     //get the system volume info to check the free space
    194     //
    195     DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle);
    196     DestVolumeInfo = NULL;
    197     DestVolumeInfoSize = 0;
    198     Status = DestVolumeFP->GetInfo(
    199       DestVolumeFP,
    200       &gEfiFileSystemInfoGuid,
    201       &DestVolumeInfoSize,
    202       DestVolumeInfo
    203       );
    204 
    205     if (Status == EFI_BUFFER_TOO_SMALL) {
    206       DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize);
    207       Status = DestVolumeFP->GetInfo(
    208         DestVolumeFP,
    209         &gEfiFileSystemInfoGuid,
    210         &DestVolumeInfoSize,
    211         DestVolumeInfo
    212         );
    213     }
    214 
    215     //
    216     //check if enough space available on destination drive to complete copy
    217     //
    218     if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) {
    219       //
    220       //not enough space on destination directory to copy file
    221       //
    222       SHELL_FREE_NON_NULL(DestVolumeInfo);
    223       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName);
    224       return(SHELL_VOLUME_FULL);
    225     } else {
    226       //
    227       // copy data between files
    228       //
    229       Buffer = AllocateZeroPool(ReadSize);
    230       if (Buffer == NULL) {
    231         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, CmdName);
    232         return SHELL_OUT_OF_RESOURCES;
    233       }
    234       while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {
    235         Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);
    236         if (!EFI_ERROR(Status)) {
    237           Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);
    238           if (EFI_ERROR(Status)) {
    239             ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
    240             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest);
    241             break;
    242           }
    243         } else {
    244           ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
    245           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source);
    246           break;
    247         }
    248       }
    249     }
    250     SHELL_FREE_NON_NULL(DestVolumeInfo);
    251   }
    252 
    253   //
    254   // close files
    255   //
    256   if (DestHandle != NULL) {
    257     ShellCloseFile(&DestHandle);
    258     DestHandle   = NULL;
    259   }
    260   if (SourceHandle != NULL) {
    261     ShellCloseFile(&SourceHandle);
    262     SourceHandle = NULL;
    263   }
    264 
    265   //
    266   // return
    267   //
    268   return ShellStatus;
    269 }
    270 
    271 /**
    272   function to take a list of files to copy and a destination location and do
    273   the verification and copying of those files to that location.  This function
    274   will report any errors to the user and halt.
    275 
    276   The key is to have this function called ONLY once.  this allows for the parameter
    277   verification to happen correctly.
    278 
    279   @param[in] FileList           A LIST_ENTRY* based list of files to move.
    280   @param[in] DestDir            The destination location.
    281   @param[in] SilentMode         TRUE to eliminate screen output.
    282   @param[in] RecursiveMode      TRUE to copy directories.
    283   @param[in] Resp               The response to the overwrite query (if always).
    284 
    285   @retval SHELL_SUCCESS             the files were all moved.
    286   @retval SHELL_INVALID_PARAMETER   a parameter was invalid
    287   @retval SHELL_SECURITY_VIOLATION  a security violation ocurred
    288   @retval SHELL_WRITE_PROTECTED     the destination was write protected
    289   @retval SHELL_OUT_OF_RESOURCES    a memory allocation failed
    290 **/
    291 SHELL_STATUS
    292 ValidateAndCopyFiles(
    293   IN CONST EFI_SHELL_FILE_INFO  *FileList,
    294   IN CONST CHAR16               *DestDir,
    295   IN BOOLEAN                    SilentMode,
    296   IN BOOLEAN                    RecursiveMode,
    297   IN VOID                       **Resp
    298   )
    299 {
    300   CHAR16                    *HiiOutput;
    301   CHAR16                    *HiiResultOk;
    302   CONST EFI_SHELL_FILE_INFO *Node;
    303   SHELL_STATUS              ShellStatus;
    304   EFI_STATUS                Status;
    305   CHAR16                    *DestPath;
    306   VOID                      *Response;
    307   UINTN                     PathSize;
    308   CONST CHAR16              *Cwd;
    309   UINTN                     NewSize;
    310   CHAR16                    *CleanFilePathStr;
    311 
    312   if (Resp == NULL) {
    313     Response = NULL;
    314   } else {
    315     Response = *Resp;
    316   }
    317 
    318   DestPath         = NULL;
    319   ShellStatus      = SHELL_SUCCESS;
    320   PathSize         = 0;
    321   Cwd              = ShellGetCurrentDir(NULL);
    322   CleanFilePathStr = NULL;
    323 
    324   ASSERT(FileList != NULL);
    325   ASSERT(DestDir  != NULL);
    326 
    327 
    328   Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr);
    329   if (EFI_ERROR (Status)) {
    330     if (Status == EFI_OUT_OF_RESOURCES) {
    331       return SHELL_OUT_OF_RESOURCES;
    332     } else {
    333       return SHELL_INVALID_PARAMETER;
    334     }
    335   }
    336 
    337   ASSERT (CleanFilePathStr != NULL);
    338 
    339   //
    340   // If we are trying to copy multiple files... make sure we got a directory for the target...
    341   //
    342   if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {
    343     //
    344     // Error for destination not a directory
    345     //
    346     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
    347     FreePool (CleanFilePathStr);
    348     return (SHELL_INVALID_PARAMETER);
    349   }
    350   for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
    351     ;  !IsNull(&FileList->Link, &Node->Link)
    352     ;  Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
    353     ){
    354     //
    355     // skip the directory traversing stuff...
    356     //
    357     if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
    358       continue;
    359     }
    360 
    361     NewSize =  StrSize(CleanFilePathStr);
    362     NewSize += StrSize(Node->FullName);
    363     NewSize += (Cwd == NULL)? 0 : (StrSize(Cwd) + sizeof(CHAR16));
    364     if (NewSize > PathSize) {
    365       PathSize = NewSize;
    366     }
    367 
    368     //
    369     // Make sure got -r if required
    370     //
    371     if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) {
    372       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp");
    373       FreePool (CleanFilePathStr);
    374       return (SHELL_INVALID_PARAMETER);
    375     }
    376 
    377     //
    378     // make sure got dest as dir if needed
    379     //
    380     if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))) {
    381       //
    382       // Error for destination not a directory
    383       //
    384       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
    385       FreePool (CleanFilePathStr);
    386       return (SHELL_INVALID_PARAMETER);
    387     }
    388   }
    389 
    390   HiiOutput   = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);
    391   HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
    392   DestPath    = AllocateZeroPool(PathSize);
    393 
    394   if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) {
    395     SHELL_FREE_NON_NULL(DestPath);
    396     SHELL_FREE_NON_NULL(HiiOutput);
    397     SHELL_FREE_NON_NULL(HiiResultOk);
    398     FreePool (CleanFilePathStr);
    399     return (SHELL_OUT_OF_RESOURCES);
    400   }
    401 
    402   //
    403   // Go through the list of files to copy...
    404   //
    405   for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
    406     ;  !IsNull(&FileList->Link, &Node->Link)
    407     ;  Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
    408     ){
    409     if (ShellGetExecutionBreakFlag()) {
    410       break;
    411     }
    412     ASSERT(Node->FileName != NULL);
    413     ASSERT(Node->FullName != NULL);
    414 
    415     //
    416     // skip the directory traversing stuff...
    417     //
    418     if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
    419       continue;
    420     }
    421 
    422     if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item
    423       && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))                 // not an existing directory
    424       ) {
    425       if (StrStr(CleanFilePathStr, L":") == NULL) {
    426         //
    427         // simple copy of a single file
    428         //
    429         if (Cwd != NULL) {
    430           StrCpyS(DestPath, PathSize / sizeof(CHAR16), Cwd);
    431           StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");
    432         } else {
    433           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
    434           FreePool (CleanFilePathStr);
    435           return (SHELL_INVALID_PARAMETER);
    436         }
    437         if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {
    438           StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");
    439         } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {
    440           ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
    441         }
    442         StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);
    443       } else {
    444         StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);
    445       }
    446     } else {
    447       //
    448       // we have multiple files or a directory in the DestDir
    449       //
    450 
    451       //
    452       // Check for leading slash
    453       //
    454       if (CleanFilePathStr[0] == L'\\') {
    455          //
    456          // Copy to the root of CWD
    457          //
    458         if (Cwd != NULL) {
    459           StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);
    460           StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
    461         } else {
    462           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp",  CleanFilePathStr);
    463           FreePool(CleanFilePathStr);
    464           return (SHELL_INVALID_PARAMETER);
    465         }
    466         while (PathRemoveLastItem(DestPath));
    467         StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr+1);
    468         StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);
    469       } else if (StrStr(CleanFilePathStr, L":") == NULL) {
    470         if (Cwd != NULL) {
    471           StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);
    472           StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
    473         } else {
    474           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
    475           FreePool(CleanFilePathStr);
    476           return (SHELL_INVALID_PARAMETER);
    477         }
    478         if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {
    479           StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
    480         } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {
    481           ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
    482         }
    483         StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);
    484         if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {
    485           StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
    486         } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {
    487           ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
    488         }
    489         StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);
    490 
    491       } else {
    492         StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);
    493         if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {
    494           StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
    495         } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {
    496           ((CHAR16*)CleanFilePathStr)[StrLen(CleanFilePathStr)-1] = CHAR_NULL;
    497         }
    498         StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);
    499       }
    500     }
    501 
    502     //
    503     // Make sure the path exists
    504     //
    505     if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {
    506       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath);
    507       ShellStatus = SHELL_DEVICE_ERROR;
    508       break;
    509     }
    510 
    511     if ( !EFI_ERROR(ShellIsDirectory(Node->FullName))
    512       && !EFI_ERROR(ShellIsDirectory(DestPath))
    513       && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL
    514       ){
    515       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp");
    516       ShellStatus = SHELL_INVALID_PARAMETER;
    517       break;
    518     }
    519     if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {
    520       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
    521       ShellStatus = SHELL_INVALID_PARAMETER;
    522       break;
    523     }
    524 
    525     if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0)
    526       && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')
    527       ) {
    528       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
    529       ShellStatus = SHELL_INVALID_PARAMETER;
    530       break;
    531     }
    532 
    533     PathCleanUpDirectories(DestPath);
    534 
    535     if (!SilentMode) {
    536       ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);
    537     }
    538 
    539     //
    540     // copy single file...
    541     //
    542     ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode, L"cp");
    543     if (ShellStatus != SHELL_SUCCESS) {
    544       break;
    545     }
    546   }
    547   if (ShellStatus == SHELL_SUCCESS && Resp == NULL) {
    548     ShellPrintEx(-1, -1, L"%s", HiiResultOk);
    549   }
    550 
    551   SHELL_FREE_NON_NULL(DestPath);
    552   SHELL_FREE_NON_NULL(HiiOutput);
    553   SHELL_FREE_NON_NULL(HiiResultOk);
    554   SHELL_FREE_NON_NULL(CleanFilePathStr);
    555   if (Resp == NULL) {
    556     SHELL_FREE_NON_NULL(Response);
    557   }
    558 
    559   return (ShellStatus);
    560 
    561 }
    562 
    563 /**
    564   Validate and if successful copy all the files from the list into
    565   destination directory.
    566 
    567   @param[in] FileList       The list of files to copy.
    568   @param[in] DestDir        The directory to copy files to.
    569   @param[in] SilentMode     TRUE to eliminate screen output.
    570   @param[in] RecursiveMode  TRUE to copy directories.
    571 
    572   @retval SHELL_INVALID_PARAMETER   A parameter was invalid.
    573   @retval SHELL_SUCCESS             The operation was successful.
    574 **/
    575 SHELL_STATUS
    576 ProcessValidateAndCopyFiles(
    577   IN       EFI_SHELL_FILE_INFO  *FileList,
    578   IN CONST CHAR16               *DestDir,
    579   IN BOOLEAN                    SilentMode,
    580   IN BOOLEAN                    RecursiveMode
    581   )
    582 {
    583   SHELL_STATUS        ShellStatus;
    584   EFI_SHELL_FILE_INFO *List;
    585   EFI_FILE_INFO       *FileInfo;
    586   CHAR16              *FullName;
    587 
    588   List      = NULL;
    589   FullName  = NULL;
    590   FileInfo  = NULL;
    591 
    592   ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);
    593   if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {
    594     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir);
    595     ShellStatus = SHELL_INVALID_PARAMETER;
    596     ShellCloseFileMetaArg(&List);
    597   } else if (List != NULL) {
    598     ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
    599     ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
    600     FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
    601     ASSERT(FileInfo != NULL);
    602     StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);
    603     ShellCloseFileMetaArg(&List);
    604     if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
    605       ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);
    606     } else {
    607       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp");
    608       ShellStatus = SHELL_ACCESS_DENIED;
    609     }
    610   } else {
    611     ShellCloseFileMetaArg(&List);
    612     ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);
    613   }
    614 
    615   SHELL_FREE_NON_NULL(FileInfo);
    616   SHELL_FREE_NON_NULL(FullName);
    617   return (ShellStatus);
    618 }
    619 
    620 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
    621   {L"-r", TypeFlag},
    622   {L"-q", TypeFlag},
    623   {NULL, TypeMax}
    624   };
    625 
    626 /**
    627   Function for 'cp' command.
    628 
    629   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
    630   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
    631 **/
    632 SHELL_STATUS
    633 EFIAPI
    634 ShellCommandRunCp (
    635   IN EFI_HANDLE        ImageHandle,
    636   IN EFI_SYSTEM_TABLE  *SystemTable
    637   )
    638 {
    639   EFI_STATUS          Status;
    640   LIST_ENTRY          *Package;
    641   CHAR16              *ProblemParam;
    642   SHELL_STATUS        ShellStatus;
    643   UINTN               ParamCount;
    644   UINTN               LoopCounter;
    645   EFI_SHELL_FILE_INFO *FileList;
    646   BOOLEAN             SilentMode;
    647   BOOLEAN             RecursiveMode;
    648   CONST CHAR16        *Cwd;
    649   CHAR16              *FullCwd;
    650 
    651   ProblemParam        = NULL;
    652   ShellStatus         = SHELL_SUCCESS;
    653   ParamCount          = 0;
    654   FileList            = NULL;
    655 
    656   //
    657   // initialize the shell lib (we must be in non-auto-init...)
    658   //
    659   Status = ShellInitialize();
    660   ASSERT_EFI_ERROR(Status);
    661 
    662   Status = CommandInit();
    663   ASSERT_EFI_ERROR(Status);
    664 
    665   //
    666   // parse the command line
    667   //
    668   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
    669   if (EFI_ERROR(Status)) {
    670     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
    671       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam);
    672       FreePool(ProblemParam);
    673       ShellStatus = SHELL_INVALID_PARAMETER;
    674     } else {
    675       ASSERT(FALSE);
    676     }
    677   } else {
    678     //
    679     // check for "-?"
    680     //
    681     if (ShellCommandLineGetFlag(Package, L"-?")) {
    682       ASSERT(FALSE);
    683     }
    684 
    685     //
    686     // Initialize SilentMode and RecursiveMode
    687     //
    688     if (gEfiShellProtocol->BatchIsActive()) {
    689       SilentMode = TRUE;
    690     } else {
    691       SilentMode = ShellCommandLineGetFlag(Package, L"-q");
    692     }
    693     RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");
    694 
    695     switch (ParamCount = ShellCommandLineGetCount(Package)) {
    696       case 0:
    697       case 1:
    698         //
    699         // we have insufficient parameters
    700         //
    701         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp");
    702         ShellStatus = SHELL_INVALID_PARAMETER;
    703         break;
    704       case 2:
    705         //
    706         // must have valid CWD for single parameter...
    707         //
    708         Cwd = ShellGetCurrentDir(NULL);
    709         if (Cwd == NULL){
    710           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp");
    711           ShellStatus = SHELL_INVALID_PARAMETER;
    712         } else {
    713           Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
    714           if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
    715             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1));
    716             ShellStatus = SHELL_NOT_FOUND;
    717           } else  {
    718             FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16));
    719             if (FullCwd == NULL) {
    720               ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cp");
    721               ShellStatus = SHELL_OUT_OF_RESOURCES;
    722             } else {
    723               StrCpyS (FullCwd, StrSize (Cwd) / sizeof (CHAR16) + 1, Cwd);
    724               ShellStatus = ProcessValidateAndCopyFiles (FileList, FullCwd, SilentMode, RecursiveMode);
    725               FreePool (FullCwd);
    726             }
    727           }
    728         }
    729 
    730         break;
    731       default:
    732         //
    733         // Make a big list of all the files...
    734         //
    735         for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {
    736           if (ShellGetExecutionBreakFlag()) {
    737             break;
    738           }
    739           Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
    740           if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {
    741             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter));
    742             ShellStatus = SHELL_NOT_FOUND;
    743           }
    744         }
    745         if (ShellStatus != SHELL_SUCCESS) {
    746           Status = ShellCloseFileMetaArg(&FileList);
    747         } else {
    748           //
    749           // now copy them all...
    750           //
    751           if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
    752             ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);
    753             Status = ShellCloseFileMetaArg(&FileList);
    754             if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
    755               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT);
    756               ShellStatus = SHELL_ACCESS_DENIED;
    757             }
    758           }
    759         }
    760         break;
    761     } // switch on parameter count
    762 
    763     if (FileList != NULL) {
    764       ShellCloseFileMetaArg(&FileList);
    765     }
    766 
    767     //
    768     // free the command line package
    769     //
    770     ShellCommandLineFreeVarList (Package);
    771   }
    772 
    773   if (ShellGetExecutionBreakFlag()) {
    774     return (SHELL_ABORTED);
    775   }
    776 
    777   return (ShellStatus);
    778 }
    779 
    780