]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
SourceLevelDebugPkg: Avoid NULL pointer reference.
[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
7282b505 5 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
a405b86d 6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "UefiShellLevel2CommandsLib.h"\r
f06be00e 17#include <Guid/FileSystemInfo.h>\r
18#include <Guid/FileSystemVolumeLabelInfo.h>\r
a405b86d 19\r
b54fd049 20/**\r
21 Function to take a list of files to copy and a destination location and do\r
22 the verification and copying of those files to that location. This function\r
23 will report any errors to the user and halt.\r
24\r
25 @param[in] FileList A LIST_ENTRY* based list of files to move.\r
26 @param[in] DestDir The destination location.\r
27 @param[in] SilentMode TRUE to eliminate screen output.\r
28 @param[in] RecursiveMode TRUE to copy directories.\r
29 @param[in] Resp The response to the overwrite query (if always).\r
30\r
31 @retval SHELL_SUCCESS the files were all moved.\r
32 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
33 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
34 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
35 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
36**/\r
a405b86d 37SHELL_STATUS\r
38EFIAPI\r
39ValidateAndCopyFiles(\r
40 IN CONST EFI_SHELL_FILE_INFO *FileList,\r
41 IN CONST CHAR16 *DestDir,\r
42 IN BOOLEAN SilentMode,\r
43 IN BOOLEAN RecursiveMode,\r
44 IN VOID **Resp\r
45 );\r
46\r
47/**\r
48 Function to Copy one file to another location\r
49\r
50 If the destination exists the user will be prompted and the result put into *resp\r
51\r
52 @param[in] Source pointer to source file name\r
53 @param[in] Dest pointer to destination file name\r
54 @param[out] Resp pointer to response from question. Pass back on looped calling\r
55 @param[in] SilentMode whether to run in quiet mode or not\r
bf6bbc21 56 @param[in] CmdName Source command name requesting single file copy\r
a405b86d 57\r
58 @retval SHELL_SUCCESS The source file was copied to the destination\r
59**/\r
60SHELL_STATUS\r
61EFIAPI\r
62CopySingleFile(\r
63 IN CONST CHAR16 *Source,\r
64 IN CONST CHAR16 *Dest,\r
65 OUT VOID **Resp,\r
bf6bbc21
TS
66 IN BOOLEAN SilentMode,\r
67 IN CONST CHAR16 *CmdName\r
a405b86d 68 )\r
69{\r
f06be00e 70 VOID *Response;\r
71 UINTN ReadSize;\r
72 SHELL_FILE_HANDLE SourceHandle;\r
73 SHELL_FILE_HANDLE DestHandle;\r
74 EFI_STATUS Status;\r
75 VOID *Buffer;\r
76 CHAR16 *TempName;\r
77 UINTN Size;\r
78 EFI_SHELL_FILE_INFO *List;\r
79 SHELL_STATUS ShellStatus;\r
80 UINT64 SourceFileSize;\r
81 UINT64 DestFileSize;\r
82 EFI_FILE_PROTOCOL *DestVolumeFP;\r
83 EFI_FILE_SYSTEM_INFO *DestVolumeInfo;\r
84 UINTN DestVolumeInfoSize;\r
a405b86d 85\r
86 ASSERT(Resp != NULL);\r
87\r
f06be00e 88 SourceHandle = NULL;\r
89 DestHandle = NULL;\r
90 Response = *Resp;\r
91 List = NULL;\r
92 DestVolumeInfo = NULL;\r
e755a4ca 93 ShellStatus = SHELL_SUCCESS;\r
a405b86d 94\r
433a21cb 95 ReadSize = PcdGet32(PcdShellFileOperationSize);\r
a405b86d 96 // Why bother copying a file to itself\r
97 if (StrCmp(Source, Dest) == 0) {\r
98 return (SHELL_SUCCESS);\r
99 }\r
100\r
a405b86d 101 //\r
102 // if the destination file existed check response and possibly prompt user\r
103 //\r
ac8783c8 104 if (ShellFileExists(Dest) == EFI_SUCCESS) {\r
a405b86d 105 if (Response == NULL && !SilentMode) {\r
b54fd049 106 Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
a405b86d 107 }\r
108 //\r
109 // possibly return based on response\r
110 //\r
111 if (!SilentMode) {\r
112 switch (*(SHELL_PROMPT_RESPONSE*)Response) {\r
113 case ShellPromptResponseNo:\r
114 //\r
115 // return success here so we dont stop the process\r
116 //\r
117 return (SHELL_SUCCESS);\r
118 case ShellPromptResponseCancel:\r
119 *Resp = Response;\r
120 //\r
121 // indicate to stop everything\r
122 //\r
123 return (SHELL_ABORTED);\r
124 case ShellPromptResponseAll:\r
125 *Resp = Response;\r
126 case ShellPromptResponseYes:\r
127 break;\r
e9723321 128 default:\r
129 return SHELL_ABORTED;\r
a405b86d 130 }\r
131 }\r
132 }\r
133\r
134 if (ShellIsDirectory(Source) == EFI_SUCCESS) {\r
135 Status = ShellCreateDirectory(Dest, &DestHandle);\r
136 if (EFI_ERROR(Status)) {\r
bf6bbc21 137 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest); \r
a405b86d 138 return (SHELL_ACCESS_DENIED);\r
139 }\r
140\r
141 //\r
142 // Now copy all the files under the directory...\r
143 //\r
144 TempName = NULL;\r
f06be00e 145 Size = 0;\r
a405b86d 146 StrnCatGrow(&TempName, &Size, Source, 0);\r
147 StrnCatGrow(&TempName, &Size, L"\\*", 0);\r
7dd05623 148 if (TempName != NULL) {\r
149 ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List);\r
150 *TempName = CHAR_NULL;\r
151 StrnCatGrow(&TempName, &Size, Dest, 0);\r
152 StrnCatGrow(&TempName, &Size, L"\\", 0);\r
153 ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp);\r
154 ShellCloseFileMetaArg(&List);\r
155 SHELL_FREE_NON_NULL(TempName);\r
156 Size = 0;\r
157 }\r
a405b86d 158 } else {\r
ac8783c8 159 Status = ShellDeleteFileByName(Dest);\r
a405b86d 160\r
ac8783c8
JC
161 //\r
162 // open file with create enabled\r
163 //\r
164 Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);\r
165 if (EFI_ERROR(Status)) {\r
bf6bbc21 166 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest); \r
ac8783c8
JC
167 return (SHELL_ACCESS_DENIED);\r
168 }\r
f06be00e 169\r
ac8783c8
JC
170 //\r
171 // open source file\r
172 //\r
173 Status = ShellOpenFileByName(Source, &SourceHandle, EFI_FILE_MODE_READ, 0);\r
174 ASSERT_EFI_ERROR(Status);\r
f06be00e 175\r
ac8783c8
JC
176 //\r
177 //get file size of source file and freespace available on destination volume\r
178 //\r
179 ShellGetFileSize(SourceHandle, &SourceFileSize);\r
180 ShellGetFileSize(DestHandle, &DestFileSize);\r
f06be00e 181\r
ac8783c8
JC
182 //\r
183 //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space\r
184 //\r
185 if(DestFileSize < SourceFileSize){\r
186 SourceFileSize -= DestFileSize;\r
187 } else {\r
188 SourceFileSize = 0;\r
189 }\r
190\r
191 //\r
192 //get the system volume info to check the free space\r
193 //\r
194 DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle);\r
195 DestVolumeInfo = NULL;\r
196 DestVolumeInfoSize = 0;\r
197 Status = DestVolumeFP->GetInfo(\r
198 DestVolumeFP,\r
199 &gEfiFileSystemInfoGuid,\r
200 &DestVolumeInfoSize,\r
201 DestVolumeInfo\r
202 );\r
203\r
204 if (Status == EFI_BUFFER_TOO_SMALL) {\r
205 DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize);\r
f06be00e 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
JC
214 //\r
215 //check if enough space available on destination drive to complete copy\r
216 //\r
217 if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) {\r
f06be00e 218 //\r
ac8783c8 219 //not enough space on destination directory to copy file\r
f06be00e 220 //\r
f06be00e 221 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
bf6bbc21 222 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName); \r
ac8783c8
JC
223 return(SHELL_VOLUME_FULL);\r
224 } else {\r
225 //\r
226 // copy data between files\r
227 //\r
228 Buffer = AllocateZeroPool(ReadSize);\r
229 ASSERT(Buffer != NULL);\r
230 while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {\r
231 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);\r
f3a14a0f
SQ
232 if (!EFI_ERROR(Status)) {\r
233 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);\r
234 if (EFI_ERROR(Status)) {\r
235 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
bf6bbc21 236 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest); \r
f3a14a0f
SQ
237 break;\r
238 }\r
239 } else {\r
240 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
bf6bbc21 241 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source); \r
f3a14a0f
SQ
242 break;\r
243 }\r
ac8783c8 244 }\r
a405b86d 245 }\r
ac8783c8
JC
246 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
247 }\r
f3a14a0f 248 \r
a405b86d 249 //\r
250 // close files\r
251 //\r
252 if (DestHandle != NULL) {\r
253 ShellCloseFile(&DestHandle);\r
254 DestHandle = NULL;\r
255 }\r
256 if (SourceHandle != NULL) {\r
257 ShellCloseFile(&SourceHandle);\r
258 SourceHandle = NULL;\r
259 }\r
260\r
261 //\r
262 // return\r
263 //\r
e755a4ca 264 return ShellStatus;\r
a405b86d 265}\r
266\r
267/**\r
268 function to take a list of files to copy and a destination location and do\r
269 the verification and copying of those files to that location. This function\r
270 will report any errors to the user and halt.\r
271\r
272 The key is to have this function called ONLY once. this allows for the parameter\r
273 verification to happen correctly.\r
274\r
b54fd049 275 @param[in] FileList A LIST_ENTRY* based list of files to move.\r
276 @param[in] DestDir The destination location.\r
277 @param[in] SilentMode TRUE to eliminate screen output.\r
278 @param[in] RecursiveMode TRUE to copy directories.\r
279 @param[in] Resp The response to the overwrite query (if always).\r
a405b86d 280\r
281 @retval SHELL_SUCCESS the files were all moved.\r
282 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
283 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
284 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
285 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
286**/\r
287SHELL_STATUS\r
288EFIAPI\r
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
0960ba17
QS
324 \r
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
QS
332 }\r
333 \r
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
099e8ff5 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
ed053afe 360 NewSize += (Cwd == NULL)? 0 : StrSize(Cwd);\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
099e8ff5 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
099e8ff5 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
e1044f80 427 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16)-1);\r
ed053afe 428 } else {\r
099e8ff5 429 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 430 FreePool (CleanFilePathStr);\r
ed053afe
ED
431 return (SHELL_INVALID_PARAMETER);\r
432 }\r
0960ba17 433 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
e1044f80 434 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
0960ba17 435 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
b54fd049 436 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
437 }\r
0960ba17 438 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
b54fd049 439 } else {\r
0960ba17 440 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1);\r
a405b86d 441 }\r
a405b86d 442 } else {\r
443 //\r
444 // we have multiple files or a directory in the DestDir\r
445 //\r
1fc3749d 446 \r
447 //\r
448 // Check for leading slash\r
449 //\r
0960ba17 450 if (CleanFilePathStr[0] == L'\\') {\r
ed053afe
ED
451 //\r
452 // Copy to the root of CWD\r
453 //\r
454 if (Cwd != NULL) {\r
e1044f80 455 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1);\r
ed053afe 456 } else {\r
099e8ff5 457 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 458 FreePool(CleanFilePathStr);\r
ed053afe
ED
459 return (SHELL_INVALID_PARAMETER);\r
460 }\r
1fc3749d 461 while (PathRemoveLastItem(DestPath));\r
0960ba17 462 StrnCat(DestPath, CleanFilePathStr+1, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
e1044f80 463 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
0960ba17 464 } else if (StrStr(CleanFilePathStr, L":") == NULL) {\r
ed053afe 465 if (Cwd != NULL) {\r
e1044f80 466 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1);\r
ed053afe 467 } else {\r
099e8ff5 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
e1044f80 473 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\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
0960ba17
QS
477 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
478 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
e1044f80 479 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\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
e1044f80 483 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
a405b86d 484\r
485 } else {\r
0960ba17
QS
486 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1);\r
487 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
e1044f80 488 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\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
e1044f80 492 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
a405b86d 493 }\r
494 }\r
a6e84d95 495 \r
a405b86d 496 //\r
497 // Make sure the path exists\r
498 //\r
499 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {\r
099e8ff5 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
507 && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL\r
f06be00e 508 ){\r
099e8ff5 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
099e8ff5 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
099e8ff5 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
558 Validate and if successful copy all the files from the list into \r
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
570EFIAPI\r
571ProcessValidateAndCopyFiles(\r
572 IN EFI_SHELL_FILE_INFO *FileList,\r
573 IN CONST CHAR16 *DestDir,\r
574 IN BOOLEAN SilentMode,\r
575 IN BOOLEAN RecursiveMode\r
576 )\r
577{\r
578 SHELL_STATUS ShellStatus;\r
579 EFI_SHELL_FILE_INFO *List;\r
a405b86d 580 EFI_FILE_INFO *FileInfo;\r
ac8783c8 581 CHAR16 *FullName;\r
a405b86d 582\r
ac8783c8
JC
583 List = NULL;\r
584 FullName = NULL;\r
9f56625f 585 FileInfo = NULL;\r
a405b86d 586\r
e755a4ca 587 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);\r
a405b86d 588 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {\r
099e8ff5 589 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir); \r
a405b86d 590 ShellStatus = SHELL_INVALID_PARAMETER;\r
591 ShellCloseFileMetaArg(&List);\r
592 } else if (List != NULL) {\r
a405b86d 593 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);\r
594 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);\r
a405b86d 595 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);\r
596 ASSERT(FileInfo != NULL);\r
ac8783c8
JC
597 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);\r
598 ShellCloseFileMetaArg(&List);\r
a405b86d 599 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {\r
ac8783c8 600 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);\r
a405b86d 601 } else {\r
099e8ff5 602 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 603 ShellStatus = SHELL_ACCESS_DENIED;\r
604 }\r
a405b86d 605 } else {\r
ac8783c8 606 ShellCloseFileMetaArg(&List);\r
ed053afe 607 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);\r
a405b86d 608 }\r
609\r
ac8783c8
JC
610 SHELL_FREE_NON_NULL(FileInfo);\r
611 SHELL_FREE_NON_NULL(FullName);\r
a405b86d 612 return (ShellStatus);\r
613}\r
614\r
615STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
616 {L"-r", TypeFlag},\r
617 {L"-q", TypeFlag},\r
618 {NULL, TypeMax}\r
619 };\r
620\r
621/**\r
622 Function for 'cp' command.\r
623\r
624 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
625 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
626**/\r
627SHELL_STATUS\r
628EFIAPI\r
629ShellCommandRunCp (\r
630 IN EFI_HANDLE ImageHandle,\r
631 IN EFI_SYSTEM_TABLE *SystemTable\r
632 )\r
633{\r
634 EFI_STATUS Status;\r
635 LIST_ENTRY *Package;\r
636 CHAR16 *ProblemParam;\r
637 SHELL_STATUS ShellStatus;\r
638 UINTN ParamCount;\r
639 UINTN LoopCounter;\r
640 EFI_SHELL_FILE_INFO *FileList;\r
641 BOOLEAN SilentMode;\r
642 BOOLEAN RecursiveMode;\r
643 CONST CHAR16 *Cwd;\r
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
099e8ff5 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
099e8ff5 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
099e8ff5 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
099e8ff5 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
712 ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode);\r
713 }\r
714 }\r
715\r
716 break;\r
717 default:\r
718 //\r
719 // Make a big list of all the files...\r
720 //\r
721 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {\r
722 if (ShellGetExecutionBreakFlag()) {\r
723 break;\r
724 }\r
725 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
726 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {\r
099e8ff5 727 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter)); \r
a405b86d 728 ShellStatus = SHELL_NOT_FOUND;\r
729 }\r
730 }\r
b2bf9735 731 if (ShellStatus != SHELL_SUCCESS) {\r
a405b86d 732 Status = ShellCloseFileMetaArg(&FileList);\r
b2bf9735 733 } else {\r
734 //\r
735 // now copy them all...\r
736 //\r
737 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
ab94587a 738 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);\r
b2bf9735 739 Status = ShellCloseFileMetaArg(&FileList);\r
740 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
099e8ff5 741 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT); \r
b2bf9735 742 ShellStatus = SHELL_ACCESS_DENIED;\r
743 }\r
a405b86d 744 }\r
745 }\r
a405b86d 746 break;\r
747 } // switch on parameter count\r
748\r
749 if (FileList != NULL) {\r
750 ShellCloseFileMetaArg(&FileList);\r
751 }\r
752\r
753 //\r
754 // free the command line package\r
755 //\r
756 ShellCommandLineFreeVarList (Package);\r
757 }\r
758\r
759 if (ShellGetExecutionBreakFlag()) {\r
760 return (SHELL_ABORTED);\r
761 }\r
762\r
763 return (ShellStatus);\r
764}\r
765\r