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