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