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