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