1a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey/** @file
2a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  Main file for cp shell level 2 function.
3a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
4c011b6c9e2baf57fc0557117e9875ceb3dca55a3Tapan Shah  (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
6a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  This program and the accompanying materials
7a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  are licensed and made available under the terms and conditions of the BSD License
8a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  which accompanies this distribution.  The full text of the license may be found at
9a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  http://opensource.org/licenses/bsd-license.php
10a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
11a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
14a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey**/
15a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
16a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey#include "UefiShellLevel2CommandsLib.h"
17f06be00e7aea1dc89c63728d20247a85f1511139jcarsey#include <Guid/FileSystemInfo.h>
18f06be00e7aea1dc89c63728d20247a85f1511139jcarsey#include <Guid/FileSystemVolumeLabelInfo.h>
19a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
20b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey/**
21b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  Function to take a list of files to copy and a destination location and do
22b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  the verification and copying of those files to that location.  This function
23b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  will report any errors to the user and halt.
24b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey
25b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] FileList           A LIST_ENTRY* based list of files to move.
26b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] DestDir            The destination location.
27b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] SilentMode         TRUE to eliminate screen output.
28b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] RecursiveMode      TRUE to copy directories.
29b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] Resp               The response to the overwrite query (if always).
30b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey
31b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @retval SHELL_SUCCESS             the files were all moved.
32b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @retval SHELL_INVALID_PARAMETER   a parameter was invalid
33b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @retval SHELL_SECURITY_VIOLATION  a security violation ocurred
34b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @retval SHELL_WRITE_PROTECTED     the destination was write protected
35b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @retval SHELL_OUT_OF_RESOURCES    a memory allocation failed
36b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey**/
37a405b86d274d32b92f69842bfb9a1ab143128f57jcarseySHELL_STATUS
38a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyEFIAPI
39a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyValidateAndCopyFiles(
40a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN CONST EFI_SHELL_FILE_INFO  *FileList,
41a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN CONST CHAR16               *DestDir,
42a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN BOOLEAN                    SilentMode,
43a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN BOOLEAN                    RecursiveMode,
44a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN VOID                       **Resp
45a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  );
46a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
47a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey/**
48a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  Function to Copy one file to another location
49a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
50a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  If the destination exists the user will be prompted and the result put into *resp
51a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
52a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @param[in] Source     pointer to source file name
53a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @param[in] Dest       pointer to destination file name
54a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @param[out] Resp      pointer to response from question.  Pass back on looped calling
55a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @param[in] SilentMode whether to run in quiet mode or not
56bf6bbc212d77736c9f81d6877701d4cf86030349Tapan Shah  @param[in] CmdName    Source command name requesting single file copy
57a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
58a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @retval SHELL_SUCCESS   The source file was copied to the destination
59a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey**/
60a405b86d274d32b92f69842bfb9a1ab143128f57jcarseySHELL_STATUS
61a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyEFIAPI
62a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyCopySingleFile(
63a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN CONST CHAR16 *Source,
64a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN CONST CHAR16 *Dest,
65a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  OUT VOID        **Resp,
66bf6bbc212d77736c9f81d6877701d4cf86030349Tapan Shah  IN BOOLEAN      SilentMode,
67bf6bbc212d77736c9f81d6877701d4cf86030349Tapan Shah  IN CONST CHAR16 *CmdName
68a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  )
69a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey{
70f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  VOID                  *Response;
71f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  UINTN                 ReadSize;
72f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  SHELL_FILE_HANDLE     SourceHandle;
73f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  SHELL_FILE_HANDLE     DestHandle;
74f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  EFI_STATUS            Status;
75f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  VOID                  *Buffer;
76f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  CHAR16                *TempName;
77f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  UINTN                 Size;
78f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  EFI_SHELL_FILE_INFO   *List;
79f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  SHELL_STATUS          ShellStatus;
80f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  UINT64                SourceFileSize;
81f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  UINT64                DestFileSize;
82f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  EFI_FILE_PROTOCOL     *DestVolumeFP;
83f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  EFI_FILE_SYSTEM_INFO  *DestVolumeInfo;
84f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  UINTN                 DestVolumeInfoSize;
85a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
86a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  ASSERT(Resp != NULL);
87a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
88f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  SourceHandle    = NULL;
89f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  DestHandle      = NULL;
90f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  Response        = *Resp;
91f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  List            = NULL;
92f06be00e7aea1dc89c63728d20247a85f1511139jcarsey  DestVolumeInfo  = NULL;
93e755a4ca10aad316c3620223206d63982793b26cjcarsey  ShellStatus     = SHELL_SUCCESS;
94a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
95433a21cba1a6a825b9ec07f580164b84e5d41d3aEugene Cohen  ReadSize = PcdGet32(PcdShellFileOperationSize);
96a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  // Why bother copying a file to itself
97a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  if (StrCmp(Source, Dest) == 0) {
98a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    return (SHELL_SUCCESS);
99a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
100a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
101a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
102a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  // if the destination file existed check response and possibly prompt user
103a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
104ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey  if (ShellFileExists(Dest) == EFI_SUCCESS) {
105a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (Response == NULL && !SilentMode) {
106b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey      Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
107a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
108a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
109a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // possibly return based on response
110a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
111a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (!SilentMode) {
112a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      switch (*(SHELL_PROMPT_RESPONSE*)Response) {
113a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        case ShellPromptResponseNo:
114a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          //
115a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          // return success here so we dont stop the process
116a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          //
117a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          return (SHELL_SUCCESS);
118a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        case ShellPromptResponseCancel:
119a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          *Resp = Response;
120a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          //
121a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          // indicate to stop everything
122a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          //
123a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          return (SHELL_ABORTED);
124a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        case ShellPromptResponseAll:
125a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          *Resp = Response;
126a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        case ShellPromptResponseYes:
127a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          break;
128e97233217ed6d37d7bb7fefb0ff0821515a23b48jljusten        default:
129e97233217ed6d37d7bb7fefb0ff0821515a23b48jljusten          return SHELL_ABORTED;
130a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      }
131a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
132a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
133a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
134a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  if (ShellIsDirectory(Source) == EFI_SUCCESS) {
135a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    Status = ShellCreateDirectory(Dest, &DestHandle);
136a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (EFI_ERROR(Status)) {
137bf6bbc212d77736c9f81d6877701d4cf86030349Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
138a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      return (SHELL_ACCESS_DENIED);
139a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
140a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
141a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
142a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // Now copy all the files under the directory...
143a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
144a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    TempName    = NULL;
145f06be00e7aea1dc89c63728d20247a85f1511139jcarsey    Size        = 0;
146a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    StrnCatGrow(&TempName, &Size, Source, 0);
147a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    StrnCatGrow(&TempName, &Size, L"\\*", 0);
1487dd0562309ac668b7025023f05e79687fdf7a13ajcarsey    if (TempName != NULL) {
1497dd0562309ac668b7025023f05e79687fdf7a13ajcarsey      ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List);
1507dd0562309ac668b7025023f05e79687fdf7a13ajcarsey      *TempName = CHAR_NULL;
1517dd0562309ac668b7025023f05e79687fdf7a13ajcarsey      StrnCatGrow(&TempName, &Size, Dest, 0);
1527dd0562309ac668b7025023f05e79687fdf7a13ajcarsey      StrnCatGrow(&TempName, &Size, L"\\", 0);
1537dd0562309ac668b7025023f05e79687fdf7a13ajcarsey      ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp);
1547dd0562309ac668b7025023f05e79687fdf7a13ajcarsey      ShellCloseFileMetaArg(&List);
1557dd0562309ac668b7025023f05e79687fdf7a13ajcarsey      SHELL_FREE_NON_NULL(TempName);
1567dd0562309ac668b7025023f05e79687fdf7a13ajcarsey      Size = 0;
1577dd0562309ac668b7025023f05e79687fdf7a13ajcarsey    }
158a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  } else {
159ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    Status = ShellDeleteFileByName(Dest);
160a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
161ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
162ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    // open file with create enabled
163ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
164ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
165ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    if (EFI_ERROR(Status)) {
166bf6bbc212d77736c9f81d6877701d4cf86030349Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
167ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      return (SHELL_ACCESS_DENIED);
168ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    }
169f06be00e7aea1dc89c63728d20247a85f1511139jcarsey
170ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
171ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    // open source file
172ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
1732ce9792534cebf8a70b110094d4790783da0178bOlivier Martin    Status = ShellOpenFileByName (Source, &SourceHandle, EFI_FILE_MODE_READ, 0);
1742ce9792534cebf8a70b110094d4790783da0178bOlivier Martin    if (EFI_ERROR (Status)) {
1752ce9792534cebf8a70b110094d4790783da0178bOlivier Martin      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source);
1762ce9792534cebf8a70b110094d4790783da0178bOlivier Martin      return (SHELL_ACCESS_DENIED);
1772ce9792534cebf8a70b110094d4790783da0178bOlivier Martin    }
178f06be00e7aea1dc89c63728d20247a85f1511139jcarsey
179ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
180ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //get file size of source file and freespace available on destination volume
181ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
182ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    ShellGetFileSize(SourceHandle, &SourceFileSize);
183ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    ShellGetFileSize(DestHandle, &DestFileSize);
184f06be00e7aea1dc89c63728d20247a85f1511139jcarsey
185ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
186ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space
187ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
188ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    if(DestFileSize < SourceFileSize){
189ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      SourceFileSize -= DestFileSize;
190ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    } else {
191ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      SourceFileSize = 0;
192ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    }
193ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey
194ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
195ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //get the system volume info to check the free space
196ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
197ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle);
198ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    DestVolumeInfo = NULL;
199ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    DestVolumeInfoSize = 0;
200ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    Status = DestVolumeFP->GetInfo(
201ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      DestVolumeFP,
202ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      &gEfiFileSystemInfoGuid,
203ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      &DestVolumeInfoSize,
204ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      DestVolumeInfo
205ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      );
206ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey
207ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    if (Status == EFI_BUFFER_TOO_SMALL) {
208ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize);
209f06be00e7aea1dc89c63728d20247a85f1511139jcarsey      Status = DestVolumeFP->GetInfo(
210f06be00e7aea1dc89c63728d20247a85f1511139jcarsey        DestVolumeFP,
211f06be00e7aea1dc89c63728d20247a85f1511139jcarsey        &gEfiFileSystemInfoGuid,
212f06be00e7aea1dc89c63728d20247a85f1511139jcarsey        &DestVolumeInfoSize,
213f06be00e7aea1dc89c63728d20247a85f1511139jcarsey        DestVolumeInfo
214f06be00e7aea1dc89c63728d20247a85f1511139jcarsey        );
215ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    }
216f06be00e7aea1dc89c63728d20247a85f1511139jcarsey
217ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
218ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //check if enough space available on destination drive to complete copy
219ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    //
220ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) {
221f06be00e7aea1dc89c63728d20247a85f1511139jcarsey      //
222ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      //not enough space on destination directory to copy file
223f06be00e7aea1dc89c63728d20247a85f1511139jcarsey      //
224f06be00e7aea1dc89c63728d20247a85f1511139jcarsey      SHELL_FREE_NON_NULL(DestVolumeInfo);
225bf6bbc212d77736c9f81d6877701d4cf86030349Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName);
226ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      return(SHELL_VOLUME_FULL);
227ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    } else {
228ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      //
229ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      // copy data between files
230ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      //
231ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      Buffer = AllocateZeroPool(ReadSize);
232ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      ASSERT(Buffer != NULL);
233ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {
234ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey        Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);
235f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu        if (!EFI_ERROR(Status)) {
236f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu          Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);
237f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu          if (EFI_ERROR(Status)) {
238f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu            ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
239bf6bbc212d77736c9f81d6877701d4cf86030349Tapan Shah            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest);
240f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu            break;
241f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu          }
242f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu        } else {
243f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu          ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
244bf6bbc212d77736c9f81d6877701d4cf86030349Tapan Shah          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source);
245f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu          break;
246f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu        }
247ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      }
248a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
249ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    SHELL_FREE_NON_NULL(DestVolumeInfo);
250ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey  }
251f3a14a0f575e7e856ff4d90d7d0ab73f7e02ae41Shumin Qiu
252a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
253a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  // close files
254a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
255a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  if (DestHandle != NULL) {
256a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ShellCloseFile(&DestHandle);
257a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    DestHandle   = NULL;
258a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
259a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  if (SourceHandle != NULL) {
260a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ShellCloseFile(&SourceHandle);
261a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    SourceHandle = NULL;
262a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
263a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
264a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
265a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  // return
266a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
267e755a4ca10aad316c3620223206d63982793b26cjcarsey  return ShellStatus;
268a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey}
269a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
270a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey/**
271a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  function to take a list of files to copy and a destination location and do
272a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  the verification and copying of those files to that location.  This function
273a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  will report any errors to the user and halt.
274a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
275a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  The key is to have this function called ONLY once.  this allows for the parameter
276a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  verification to happen correctly.
277a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
278b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] FileList           A LIST_ENTRY* based list of files to move.
279b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] DestDir            The destination location.
280b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] SilentMode         TRUE to eliminate screen output.
281b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] RecursiveMode      TRUE to copy directories.
282b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] Resp               The response to the overwrite query (if always).
283a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
284a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @retval SHELL_SUCCESS             the files were all moved.
285a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @retval SHELL_INVALID_PARAMETER   a parameter was invalid
286a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @retval SHELL_SECURITY_VIOLATION  a security violation ocurred
287a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @retval SHELL_WRITE_PROTECTED     the destination was write protected
288a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @retval SHELL_OUT_OF_RESOURCES    a memory allocation failed
289a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey**/
290a405b86d274d32b92f69842bfb9a1ab143128f57jcarseySHELL_STATUS
291a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyEFIAPI
292a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyValidateAndCopyFiles(
293a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN CONST EFI_SHELL_FILE_INFO  *FileList,
294a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN CONST CHAR16               *DestDir,
295a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN BOOLEAN                    SilentMode,
296a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN BOOLEAN                    RecursiveMode,
297a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN VOID                       **Resp
298a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  )
299a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey{
300a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  CHAR16                    *HiiOutput;
301a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  CHAR16                    *HiiResultOk;
302a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  CONST EFI_SHELL_FILE_INFO *Node;
303a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  SHELL_STATUS              ShellStatus;
3040960ba17e596812f211ba334cc6699d45bada328Qiu Shumin  EFI_STATUS                Status;
305a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  CHAR16                    *DestPath;
306a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  VOID                      *Response;
307e1044f8074836b74188a2371ba70be05d0e0482bJaben Carsey  UINTN                     PathSize;
308a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  CONST CHAR16              *Cwd;
309a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  UINTN                     NewSize;
3100960ba17e596812f211ba334cc6699d45bada328Qiu Shumin  CHAR16                    *CleanFilePathStr;
311a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
312a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  if (Resp == NULL) {
313a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    Response = NULL;
314a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  } else {
315a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    Response = *Resp;
316a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
317a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
318715096c2448412e54a95092942a397bd4d697524Qiu Shumin  DestPath         = NULL;
319715096c2448412e54a95092942a397bd4d697524Qiu Shumin  ShellStatus      = SHELL_SUCCESS;
320715096c2448412e54a95092942a397bd4d697524Qiu Shumin  PathSize         = 0;
321715096c2448412e54a95092942a397bd4d697524Qiu Shumin  Cwd              = ShellGetCurrentDir(NULL);
322715096c2448412e54a95092942a397bd4d697524Qiu Shumin  CleanFilePathStr = NULL;
323a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
324a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  ASSERT(FileList != NULL);
325a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  ASSERT(DestDir  != NULL);
326a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
3270960ba17e596812f211ba334cc6699d45bada328Qiu Shumin
3280960ba17e596812f211ba334cc6699d45bada328Qiu Shumin  Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr);
3290960ba17e596812f211ba334cc6699d45bada328Qiu Shumin  if (EFI_ERROR (Status)) {
3300960ba17e596812f211ba334cc6699d45bada328Qiu Shumin    if (Status == EFI_OUT_OF_RESOURCES) {
3310960ba17e596812f211ba334cc6699d45bada328Qiu Shumin      return SHELL_OUT_OF_RESOURCES;
3320960ba17e596812f211ba334cc6699d45bada328Qiu Shumin    } else {
3330960ba17e596812f211ba334cc6699d45bada328Qiu Shumin      return SHELL_INVALID_PARAMETER;
3340960ba17e596812f211ba334cc6699d45bada328Qiu Shumin    }
335427d61ad4ad1462b5f4370a78eb58c1ba73680b4Qiu Shumin  }
336427d61ad4ad1462b5f4370a78eb58c1ba73680b4Qiu Shumin
337427d61ad4ad1462b5f4370a78eb58c1ba73680b4Qiu Shumin  ASSERT (CleanFilePathStr != NULL);
3380960ba17e596812f211ba334cc6699d45bada328Qiu Shumin
339a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
340a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  // If we are trying to copy multiple files... make sure we got a directory for the target...
341a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
3420960ba17e596812f211ba334cc6699d45bada328Qiu Shumin  if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {
343a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
344a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // Error for destination not a directory
345a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
346099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
3470960ba17e596812f211ba334cc6699d45bada328Qiu Shumin    FreePool (CleanFilePathStr);
348a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    return (SHELL_INVALID_PARAMETER);
349a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
350a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
351a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ;  !IsNull(&FileList->Link, &Node->Link)
352a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ;  Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
353f06be00e7aea1dc89c63728d20247a85f1511139jcarsey    ){
354a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
355a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // skip the directory traversing stuff...
356a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
357a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
358a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      continue;
359a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
360a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
3610960ba17e596812f211ba334cc6699d45bada328Qiu Shumin    NewSize =  StrSize(CleanFilePathStr);
362b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey    NewSize += StrSize(Node->FullName);
363fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin    NewSize += (Cwd == NULL)? 0 : (StrSize(Cwd) + sizeof(CHAR16));
364e1044f8074836b74188a2371ba70be05d0e0482bJaben Carsey    if (NewSize > PathSize) {
365e1044f8074836b74188a2371ba70be05d0e0482bJaben Carsey      PathSize = NewSize;
366a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
367a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
368a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
369a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // Make sure got -r if required
370a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
371a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) {
372099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp");
3730960ba17e596812f211ba334cc6699d45bada328Qiu Shumin      FreePool (CleanFilePathStr);
374a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      return (SHELL_INVALID_PARAMETER);
375a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
376a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
377a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
378a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // make sure got dest as dir if needed
379a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
3800960ba17e596812f211ba334cc6699d45bada328Qiu Shumin    if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))) {
381a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      //
382a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      // Error for destination not a directory
383a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      //
384099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
3850960ba17e596812f211ba334cc6699d45bada328Qiu Shumin      FreePool (CleanFilePathStr);
386a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      return (SHELL_INVALID_PARAMETER);
387a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
388a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
389a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
390a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  HiiOutput   = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);
391a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
392e1044f8074836b74188a2371ba70be05d0e0482bJaben Carsey  DestPath    = AllocateZeroPool(PathSize);
393a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
3943e082d58262da4108a3f1f2ee8fa0a9441bb2a9bjcarsey  if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) {
3959ea69f8a05b808b4bab81b608436a02e2f2fba09jcarsey    SHELL_FREE_NON_NULL(DestPath);
3969ea69f8a05b808b4bab81b608436a02e2f2fba09jcarsey    SHELL_FREE_NON_NULL(HiiOutput);
3979ea69f8a05b808b4bab81b608436a02e2f2fba09jcarsey    SHELL_FREE_NON_NULL(HiiResultOk);
3980960ba17e596812f211ba334cc6699d45bada328Qiu Shumin    FreePool (CleanFilePathStr);
3999ea69f8a05b808b4bab81b608436a02e2f2fba09jcarsey    return (SHELL_OUT_OF_RESOURCES);
4009ea69f8a05b808b4bab81b608436a02e2f2fba09jcarsey  }
4019ea69f8a05b808b4bab81b608436a02e2f2fba09jcarsey
402a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
403a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  // Go through the list of files to copy...
404a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
405a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
406a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ;  !IsNull(&FileList->Link, &Node->Link)
407a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ;  Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
408f06be00e7aea1dc89c63728d20247a85f1511139jcarsey    ){
409a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (ShellGetExecutionBreakFlag()) {
410a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      break;
411a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
412a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ASSERT(Node->FileName != NULL);
413a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ASSERT(Node->FullName != NULL);
414a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
415a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
416a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // skip the directory traversing stuff...
417a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
418a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
419a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      continue;
420a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
421a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
422a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item
4230960ba17e596812f211ba334cc6699d45bada328Qiu Shumin      && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))                 // not an existing directory
424f06be00e7aea1dc89c63728d20247a85f1511139jcarsey      ) {
4250960ba17e596812f211ba334cc6699d45bada328Qiu Shumin      if (StrStr(CleanFilePathStr, L":") == NULL) {
426b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey        //
427b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey        // simple copy of a single file
428b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey        //
429ed053afece04120c1c62163475806d6aef3bc329Eric Dong        if (Cwd != NULL) {
430e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin          StrCpyS(DestPath, PathSize / sizeof(CHAR16), Cwd);
431fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin          StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");
432ed053afece04120c1c62163475806d6aef3bc329Eric Dong        } else {
433099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
4340960ba17e596812f211ba334cc6699d45bada328Qiu Shumin          FreePool (CleanFilePathStr);
435ed053afece04120c1c62163475806d6aef3bc329Eric Dong          return (SHELL_INVALID_PARAMETER);
436ed053afece04120c1c62163475806d6aef3bc329Eric Dong        }
4370960ba17e596812f211ba334cc6699d45bada328Qiu Shumin        if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {
438e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin          StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");
4390960ba17e596812f211ba334cc6699d45bada328Qiu Shumin        } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {
440b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey          ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
441b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey        }
442e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin        StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);
443b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey      } else {
444e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin        StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);
445a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      }
446a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    } else {
447a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      //
448a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      // we have multiple files or a directory in the DestDir
449a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      //
4501fc3749dad42e8d5caebf6e0e0327b713b6adaebjcarsey
4511fc3749dad42e8d5caebf6e0e0327b713b6adaebjcarsey      //
4521fc3749dad42e8d5caebf6e0e0327b713b6adaebjcarsey      // Check for leading slash
4531fc3749dad42e8d5caebf6e0e0327b713b6adaebjcarsey      //
4540960ba17e596812f211ba334cc6699d45bada328Qiu Shumin      if (CleanFilePathStr[0] == L'\\') {
455ed053afece04120c1c62163475806d6aef3bc329Eric Dong         //
456ed053afece04120c1c62163475806d6aef3bc329Eric Dong         // Copy to the root of CWD
457ed053afece04120c1c62163475806d6aef3bc329Eric Dong         //
458ed053afece04120c1c62163475806d6aef3bc329Eric Dong        if (Cwd != NULL) {
459e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin          StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);
460fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin          StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
461ed053afece04120c1c62163475806d6aef3bc329Eric Dong        } else {
462099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp",  CleanFilePathStr);
4630960ba17e596812f211ba334cc6699d45bada328Qiu Shumin          FreePool(CleanFilePathStr);
464ed053afece04120c1c62163475806d6aef3bc329Eric Dong          return (SHELL_INVALID_PARAMETER);
465ed053afece04120c1c62163475806d6aef3bc329Eric Dong        }
4661fc3749dad42e8d5caebf6e0e0327b713b6adaebjcarsey        while (PathRemoveLastItem(DestPath));
467e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin        StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr+1);
468e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin        StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);
4690960ba17e596812f211ba334cc6699d45bada328Qiu Shumin      } else if (StrStr(CleanFilePathStr, L":") == NULL) {
470ed053afece04120c1c62163475806d6aef3bc329Eric Dong        if (Cwd != NULL) {
471e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin          StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);
472fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin          StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
473ed053afece04120c1c62163475806d6aef3bc329Eric Dong        } else {
474099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
4750960ba17e596812f211ba334cc6699d45bada328Qiu Shumin          FreePool(CleanFilePathStr);
476ed053afece04120c1c62163475806d6aef3bc329Eric Dong          return (SHELL_INVALID_PARAMETER);
477ed053afece04120c1c62163475806d6aef3bc329Eric Dong        }
4780960ba17e596812f211ba334cc6699d45bada328Qiu Shumin        if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {
479e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin          StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
4800960ba17e596812f211ba334cc6699d45bada328Qiu Shumin        } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {
481a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
482a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        }
483e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin        StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);
4840960ba17e596812f211ba334cc6699d45bada328Qiu Shumin        if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {
485e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin          StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
4860960ba17e596812f211ba334cc6699d45bada328Qiu Shumin        } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {
487a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
488a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        }
489e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin        StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);
490a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
491a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      } else {
492e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin        StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);
4930960ba17e596812f211ba334cc6699d45bada328Qiu Shumin        if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {
494e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin          StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");
4950960ba17e596812f211ba334cc6699d45bada328Qiu Shumin        } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {
4960960ba17e596812f211ba334cc6699d45bada328Qiu Shumin          ((CHAR16*)CleanFilePathStr)[StrLen(CleanFilePathStr)-1] = CHAR_NULL;
497a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        }
498e75390f02971bcd4d67a9696508050bee4936a01Qiu Shumin        StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);
499a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      }
500a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
501a6e84d95f50a10e23ee9861270fb84057b5af2e9Ni Ruiyu
502a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
503a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // Make sure the path exists
504a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
505a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {
506099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath);
507a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      ShellStatus = SHELL_DEVICE_ERROR;
508a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      break;
509a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
510a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
511a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if ( !EFI_ERROR(ShellIsDirectory(Node->FullName))
512a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      && !EFI_ERROR(ShellIsDirectory(DestPath))
513a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL
514f06be00e7aea1dc89c63728d20247a85f1511139jcarsey      ){
515099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp");
516a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      ShellStatus = SHELL_INVALID_PARAMETER;
517a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      break;
518a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
519a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {
520099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
521a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      ShellStatus = SHELL_INVALID_PARAMETER;
522a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      break;
523a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
524a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
5255051c2873b78114da6349e1c7e0754233f6c0024Olivier Martin    if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0)
526a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')
527f06be00e7aea1dc89c63728d20247a85f1511139jcarsey      ) {
528099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
529a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      ShellStatus = SHELL_INVALID_PARAMETER;
530a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      break;
531a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
532a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
533ab94587a7d2cd89695f9190420daceae0d2b7446jcarsey    PathCleanUpDirectories(DestPath);
534a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
535a737ea734b9d64d6b10e399d5d0a8539604decddJaben Carsey    if (!SilentMode) {
536a737ea734b9d64d6b10e399d5d0a8539604decddJaben Carsey      ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);
537a737ea734b9d64d6b10e399d5d0a8539604decddJaben Carsey    }
538a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
539a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
540a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // copy single file...
541a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
542bf6bbc212d77736c9f81d6877701d4cf86030349Tapan Shah    ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode, L"cp");
543a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (ShellStatus != SHELL_SUCCESS) {
544a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      break;
545a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
546a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
547a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  if (ShellStatus == SHELL_SUCCESS && Resp == NULL) {
548a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ShellPrintEx(-1, -1, L"%s", HiiResultOk);
549a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
550a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
551a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  SHELL_FREE_NON_NULL(DestPath);
552a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  SHELL_FREE_NON_NULL(HiiOutput);
553a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  SHELL_FREE_NON_NULL(HiiResultOk);
554a6e84d95f50a10e23ee9861270fb84057b5af2e9Ni Ruiyu  SHELL_FREE_NON_NULL(CleanFilePathStr);
555590c3cb14ad6547528ea13805817676e32c204aajcarsey  if (Resp == NULL) {
556a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    SHELL_FREE_NON_NULL(Response);
557a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
558a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
559a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  return (ShellStatus);
560f06be00e7aea1dc89c63728d20247a85f1511139jcarsey
561a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey}
562a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
563b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey/**
564b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  Validate and if successful copy all the files from the list into
565b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  destination directory.
566b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey
567b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] FileList       The list of files to copy.
568b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] DestDir        The directory to copy files to.
569b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] SilentMode     TRUE to eliminate screen output.
570b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @param[in] RecursiveMode  TRUE to copy directories.
571b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey
572b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @retval SHELL_INVALID_PARAMETER   A parameter was invalid.
573b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey  @retval SHELL_SUCCESS             The operation was successful.
574b54fd049bdfa0d9520a40d8a1783aa681b40d751jcarsey**/
575a405b86d274d32b92f69842bfb9a1ab143128f57jcarseySHELL_STATUS
576a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyEFIAPI
577a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyProcessValidateAndCopyFiles(
578a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN       EFI_SHELL_FILE_INFO  *FileList,
579a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN CONST CHAR16               *DestDir,
580a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN BOOLEAN                    SilentMode,
581a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN BOOLEAN                    RecursiveMode
582a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  )
583a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey{
584a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  SHELL_STATUS        ShellStatus;
585a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  EFI_SHELL_FILE_INFO *List;
586a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  EFI_FILE_INFO       *FileInfo;
587ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey  CHAR16              *FullName;
588a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
589ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey  List      = NULL;
590ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey  FullName  = NULL;
5919f56625f2a904701f460c88a7dbfaf17c4c83a22Jaben Carsey  FileInfo  = NULL;
592a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
593e755a4ca10aad316c3620223206d63982793b26cjcarsey  ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);
594a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {
595099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir);
596a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ShellStatus = SHELL_INVALID_PARAMETER;
597a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ShellCloseFileMetaArg(&List);
598a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  } else if (List != NULL) {
599a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
600a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
601a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
602a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ASSERT(FileInfo != NULL);
603ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);
604ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    ShellCloseFileMetaArg(&List);
605a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
606ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey      ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);
607a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    } else {
608099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp");
609a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      ShellStatus = SHELL_ACCESS_DENIED;
610a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
611a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  } else {
612ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey    ShellCloseFileMetaArg(&List);
613ed053afece04120c1c62163475806d6aef3bc329Eric Dong    ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);
614a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
615a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
616ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey  SHELL_FREE_NON_NULL(FileInfo);
617ac8783c8b162b9a3b1e2da222cf6d088fcf63cfbJaben Carsey  SHELL_FREE_NON_NULL(FullName);
618a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  return (ShellStatus);
619a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey}
620a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
621a405b86d274d32b92f69842bfb9a1ab143128f57jcarseySTATIC CONST SHELL_PARAM_ITEM ParamList[] = {
622a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  {L"-r", TypeFlag},
623a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  {L"-q", TypeFlag},
624a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  {NULL, TypeMax}
625a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  };
626a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
627a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey/**
628a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  Function for 'cp' command.
629a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
630a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @param[in] ImageHandle  Handle to the Image (NULL if Internal).
631a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
632a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey**/
633a405b86d274d32b92f69842bfb9a1ab143128f57jcarseySHELL_STATUS
634a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyEFIAPI
635a405b86d274d32b92f69842bfb9a1ab143128f57jcarseyShellCommandRunCp (
636a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN EFI_HANDLE        ImageHandle,
637a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  IN EFI_SYSTEM_TABLE  *SystemTable
638a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  )
639a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey{
640a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  EFI_STATUS          Status;
641a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  LIST_ENTRY          *Package;
642a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  CHAR16              *ProblemParam;
643a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  SHELL_STATUS        ShellStatus;
644a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  UINTN               ParamCount;
645a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  UINTN               LoopCounter;
646a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  EFI_SHELL_FILE_INFO *FileList;
647a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  BOOLEAN             SilentMode;
648a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  BOOLEAN             RecursiveMode;
649a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  CONST CHAR16        *Cwd;
650fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin  CHAR16              *FullCwd;
651a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
652a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  ProblemParam        = NULL;
653a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  ShellStatus         = SHELL_SUCCESS;
654a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  ParamCount          = 0;
655a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  FileList            = NULL;
656a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
657a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
658a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  // initialize the shell lib (we must be in non-auto-init...)
659a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
660a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  Status = ShellInitialize();
661a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  ASSERT_EFI_ERROR(Status);
662a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
663a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  Status = CommandInit();
664a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  ASSERT_EFI_ERROR(Status);
665a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
666a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
667a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  // parse the command line
668a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  //
669a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
670a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  if (EFI_ERROR(Status)) {
671a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
672099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam);
673a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      FreePool(ProblemParam);
674a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      ShellStatus = SHELL_INVALID_PARAMETER;
675a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    } else {
676a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      ASSERT(FALSE);
677a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
678a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  } else {
679a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
680a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // check for "-?"
681a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
682a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (ShellCommandLineGetFlag(Package, L"-?")) {
683a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      ASSERT(FALSE);
684a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
685a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
686a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
687a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // Initialize SilentMode and RecursiveMode
688a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
689a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (gEfiShellProtocol->BatchIsActive()) {
690a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      SilentMode = TRUE;
691a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    } else {
692a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      SilentMode = ShellCommandLineGetFlag(Package, L"-q");
693a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
694a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");
695a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
696a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    switch (ParamCount = ShellCommandLineGetCount(Package)) {
697a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      case 0:
698a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      case 1:
699a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        //
700a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        // we have insufficient parameters
701a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        //
702099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp");
703a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        ShellStatus = SHELL_INVALID_PARAMETER;
704a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        break;
705a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      case 2:
706a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        //
707a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        // must have valid CWD for single parameter...
708a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        //
709a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        Cwd = ShellGetCurrentDir(NULL);
710a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        if (Cwd == NULL){
711099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah          ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp");
712a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          ShellStatus = SHELL_INVALID_PARAMETER;
713a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        } else {
714a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
715a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
716099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1));
717a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey            ShellStatus = SHELL_NOT_FOUND;
718a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          } else  {
719fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin            FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16));
720fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin            ASSERT (FullCwd != NULL);
721fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin            StrCpyS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, Cwd);
722fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin            ShellStatus = ProcessValidateAndCopyFiles(FileList, FullCwd, SilentMode, RecursiveMode);
723fbd2dfadfe6fb16ab7b49fca3764e05e65d97b8aQiu Shumin            FreePool(FullCwd);
724a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          }
725a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        }
726a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
727a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        break;
728a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      default:
729a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        //
730a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        // Make a big list of all the files...
731a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        //
732a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {
733a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          if (ShellGetExecutionBreakFlag()) {
734a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey            break;
735a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          }
736a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
737a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {
738099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter));
739a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey            ShellStatus = SHELL_NOT_FOUND;
740a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          }
741a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        }
742b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey        if (ShellStatus != SHELL_SUCCESS) {
743a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          Status = ShellCloseFileMetaArg(&FileList);
744b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey        } else {
745b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey          //
746b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey          // now copy them all...
747b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey          //
748b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey          if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
749ab94587a7d2cd89695f9190420daceae0d2b7446jcarsey            ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);
750b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey            Status = ShellCloseFileMetaArg(&FileList);
751b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey            if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
752099e8ff5d2876b1d1606c3424114969946c15173Tapan Shah              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT);
753b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey              ShellStatus = SHELL_ACCESS_DENIED;
754b2bf9735860994b4f4ae3904fd784bedcdd26da1jcarsey            }
755a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey          }
756a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        }
757a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey        break;
758a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    } // switch on parameter count
759a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
760a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    if (FileList != NULL) {
761a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey      ShellCloseFileMetaArg(&FileList);
762a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    }
763a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
764a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
765a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    // free the command line package
766a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    //
767a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    ShellCommandLineFreeVarList (Package);
768a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
769a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
770a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  if (ShellGetExecutionBreakFlag()) {
771a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey    return (SHELL_ABORTED);
772a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  }
773a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
774a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey  return (ShellStatus);
775a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey}
776a405b86d274d32b92f69842bfb9a1ab143128f57jcarsey
777