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