]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
Add code to check whether the pointer 'PathForReturn' in ShellProtocol.c is NULL...
[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
54c9a68d 4 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>\r
a405b86d 5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "UefiShellLevel2CommandsLib.h"\r
f06be00e 16#include <Guid/FileSystemInfo.h>\r
17#include <Guid/FileSystemVolumeLabelInfo.h>\r
a405b86d 18\r
b54fd049 19/**\r
20 Function to take a list of files to copy and a destination location and do\r
21 the verification and copying of those files to that location. This function\r
22 will report any errors to the user and halt.\r
23\r
24 @param[in] FileList A LIST_ENTRY* based list of files to move.\r
25 @param[in] DestDir The destination location.\r
26 @param[in] SilentMode TRUE to eliminate screen output.\r
27 @param[in] RecursiveMode TRUE to copy directories.\r
28 @param[in] Resp The response to the overwrite query (if always).\r
29\r
30 @retval SHELL_SUCCESS the files were all moved.\r
31 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
32 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
33 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
34 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
35**/\r
a405b86d 36SHELL_STATUS\r
37EFIAPI\r
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
55\r
56 @retval SHELL_SUCCESS The source file was copied to the destination\r
57**/\r
58SHELL_STATUS\r
59EFIAPI\r
60CopySingleFile(\r
61 IN CONST CHAR16 *Source,\r
62 IN CONST CHAR16 *Dest,\r
63 OUT VOID **Resp,\r
64 IN BOOLEAN SilentMode\r
65 )\r
66{\r
f06be00e 67 VOID *Response;\r
68 UINTN ReadSize;\r
69 SHELL_FILE_HANDLE SourceHandle;\r
70 SHELL_FILE_HANDLE DestHandle;\r
71 EFI_STATUS Status;\r
72 VOID *Buffer;\r
73 CHAR16 *TempName;\r
74 UINTN Size;\r
75 EFI_SHELL_FILE_INFO *List;\r
76 SHELL_STATUS ShellStatus;\r
77 UINT64 SourceFileSize;\r
78 UINT64 DestFileSize;\r
79 EFI_FILE_PROTOCOL *DestVolumeFP;\r
80 EFI_FILE_SYSTEM_INFO *DestVolumeInfo;\r
81 UINTN DestVolumeInfoSize;\r
a405b86d 82\r
83 ASSERT(Resp != NULL);\r
84\r
f06be00e 85 SourceHandle = NULL;\r
86 DestHandle = NULL;\r
87 Response = *Resp;\r
88 List = NULL;\r
89 DestVolumeInfo = NULL;\r
e755a4ca 90 ShellStatus = SHELL_SUCCESS;\r
a405b86d 91\r
433a21cb 92 ReadSize = PcdGet32(PcdShellFileOperationSize);\r
a405b86d 93 // Why bother copying a file to itself\r
94 if (StrCmp(Source, Dest) == 0) {\r
95 return (SHELL_SUCCESS);\r
96 }\r
97\r
a405b86d 98 //\r
99 // if the destination file existed check response and possibly prompt user\r
100 //\r
ac8783c8 101 if (ShellFileExists(Dest) == EFI_SUCCESS) {\r
a405b86d 102 if (Response == NULL && !SilentMode) {\r
b54fd049 103 Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
a405b86d 104 }\r
105 //\r
106 // possibly return based on response\r
107 //\r
108 if (!SilentMode) {\r
109 switch (*(SHELL_PROMPT_RESPONSE*)Response) {\r
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
131 if (ShellIsDirectory(Source) == EFI_SUCCESS) {\r
132 Status = ShellCreateDirectory(Dest, &DestHandle);\r
133 if (EFI_ERROR(Status)) {\r
134 return (SHELL_ACCESS_DENIED);\r
135 }\r
136\r
137 //\r
138 // Now copy all the files under the directory...\r
139 //\r
140 TempName = NULL;\r
f06be00e 141 Size = 0;\r
a405b86d 142 StrnCatGrow(&TempName, &Size, Source, 0);\r
143 StrnCatGrow(&TempName, &Size, L"\\*", 0);\r
7dd05623 144 if (TempName != NULL) {\r
145 ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List);\r
146 *TempName = CHAR_NULL;\r
147 StrnCatGrow(&TempName, &Size, Dest, 0);\r
148 StrnCatGrow(&TempName, &Size, L"\\", 0);\r
149 ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp);\r
150 ShellCloseFileMetaArg(&List);\r
151 SHELL_FREE_NON_NULL(TempName);\r
152 Size = 0;\r
153 }\r
a405b86d 154 } else {\r
ac8783c8 155 Status = ShellDeleteFileByName(Dest);\r
a405b86d 156\r
ac8783c8
JC
157 //\r
158 // open file with create enabled\r
159 //\r
160 Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);\r
161 if (EFI_ERROR(Status)) {\r
162 return (SHELL_ACCESS_DENIED);\r
163 }\r
f06be00e 164\r
ac8783c8
JC
165 //\r
166 // open source file\r
167 //\r
168 Status = ShellOpenFileByName(Source, &SourceHandle, EFI_FILE_MODE_READ, 0);\r
169 ASSERT_EFI_ERROR(Status);\r
f06be00e 170\r
ac8783c8
JC
171 //\r
172 //get file size of source file and freespace available on destination volume\r
173 //\r
174 ShellGetFileSize(SourceHandle, &SourceFileSize);\r
175 ShellGetFileSize(DestHandle, &DestFileSize);\r
f06be00e 176\r
ac8783c8
JC
177 //\r
178 //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space\r
179 //\r
180 if(DestFileSize < SourceFileSize){\r
181 SourceFileSize -= DestFileSize;\r
182 } else {\r
183 SourceFileSize = 0;\r
184 }\r
185\r
186 //\r
187 //get the system volume info to check the free space\r
188 //\r
189 DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle);\r
190 DestVolumeInfo = NULL;\r
191 DestVolumeInfoSize = 0;\r
192 Status = DestVolumeFP->GetInfo(\r
193 DestVolumeFP,\r
194 &gEfiFileSystemInfoGuid,\r
195 &DestVolumeInfoSize,\r
196 DestVolumeInfo\r
197 );\r
198\r
199 if (Status == EFI_BUFFER_TOO_SMALL) {\r
200 DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize);\r
f06be00e 201 Status = DestVolumeFP->GetInfo(\r
202 DestVolumeFP,\r
203 &gEfiFileSystemInfoGuid,\r
204 &DestVolumeInfoSize,\r
205 DestVolumeInfo\r
206 );\r
ac8783c8 207 }\r
f06be00e 208\r
ac8783c8
JC
209 //\r
210 //check if enough space available on destination drive to complete copy\r
211 //\r
212 if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) {\r
f06be00e 213 //\r
ac8783c8 214 //not enough space on destination directory to copy file\r
f06be00e 215 //\r
f06be00e 216 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
ac8783c8
JC
217 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle);\r
218 return(SHELL_VOLUME_FULL);\r
219 } else {\r
220 //\r
221 // copy data between files\r
222 //\r
223 Buffer = AllocateZeroPool(ReadSize);\r
224 ASSERT(Buffer != NULL);\r
225 while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {\r
226 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);\r
227 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);\r
228 }\r
a405b86d 229 }\r
ac8783c8
JC
230 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
231 }\r
a405b86d 232\r
233 //\r
234 // close files\r
235 //\r
236 if (DestHandle != NULL) {\r
237 ShellCloseFile(&DestHandle);\r
238 DestHandle = NULL;\r
239 }\r
240 if (SourceHandle != NULL) {\r
241 ShellCloseFile(&SourceHandle);\r
242 SourceHandle = NULL;\r
243 }\r
244\r
245 //\r
246 // return\r
247 //\r
e755a4ca 248 return ShellStatus;\r
a405b86d 249}\r
250\r
251/**\r
252 function to take a list of files to copy and a destination location and do\r
253 the verification and copying of those files to that location. This function\r
254 will report any errors to the user and halt.\r
255\r
256 The key is to have this function called ONLY once. this allows for the parameter\r
257 verification to happen correctly.\r
258\r
b54fd049 259 @param[in] FileList A LIST_ENTRY* based list of files to move.\r
260 @param[in] DestDir The destination location.\r
261 @param[in] SilentMode TRUE to eliminate screen output.\r
262 @param[in] RecursiveMode TRUE to copy directories.\r
263 @param[in] Resp The response to the overwrite query (if always).\r
a405b86d 264\r
265 @retval SHELL_SUCCESS the files were all moved.\r
266 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
267 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
268 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
269 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
270**/\r
271SHELL_STATUS\r
272EFIAPI\r
273ValidateAndCopyFiles(\r
274 IN CONST EFI_SHELL_FILE_INFO *FileList,\r
275 IN CONST CHAR16 *DestDir,\r
276 IN BOOLEAN SilentMode,\r
277 IN BOOLEAN RecursiveMode,\r
278 IN VOID **Resp\r
279 )\r
280{\r
281 CHAR16 *HiiOutput;\r
282 CHAR16 *HiiResultOk;\r
283 CONST EFI_SHELL_FILE_INFO *Node;\r
284 SHELL_STATUS ShellStatus;\r
285 CHAR16 *DestPath;\r
286 VOID *Response;\r
287 UINTN PathLen;\r
288 CONST CHAR16 *Cwd;\r
a405b86d 289 UINTN NewSize;\r
290\r
291 if (Resp == NULL) {\r
292 Response = NULL;\r
293 } else {\r
294 Response = *Resp;\r
295 }\r
296\r
297 DestPath = NULL;\r
298 ShellStatus = SHELL_SUCCESS;\r
299 PathLen = 0;\r
300 Cwd = ShellGetCurrentDir(NULL);\r
301\r
302 ASSERT(FileList != NULL);\r
303 ASSERT(DestDir != NULL);\r
304\r
305 //\r
306 // If we are trying to copy multiple files... make sure we got a directory for the target...\r
307 //\r
308 if (EFI_ERROR(ShellIsDirectory(DestDir)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {\r
309 //\r
310 // Error for destination not a directory\r
311 //\r
312 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir);\r
313 return (SHELL_INVALID_PARAMETER);\r
314 }\r
315 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
316 ; !IsNull(&FileList->Link, &Node->Link)\r
317 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
f06be00e 318 ){\r
a405b86d 319 //\r
320 // skip the directory traversing stuff...\r
321 //\r
322 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
323 continue;\r
324 }\r
325\r
326 NewSize = StrSize(DestDir);\r
b54fd049 327 NewSize += StrSize(Node->FullName);\r
ed053afe 328 NewSize += (Cwd == NULL)? 0 : StrSize(Cwd);\r
a405b86d 329 if (NewSize > PathLen) {\r
330 PathLen = NewSize;\r
331 }\r
332\r
333 //\r
334 // Make sure got -r if required\r
335 //\r
336 if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) {\r
337 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle);\r
338 return (SHELL_INVALID_PARAMETER);\r
339 }\r
340\r
341 //\r
342 // make sure got dest as dir if needed\r
343 //\r
344 if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(DestDir))) {\r
345 //\r
346 // Error for destination not a directory\r
347 //\r
348 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir);\r
349 return (SHELL_INVALID_PARAMETER);\r
350 }\r
351 }\r
352\r
353 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);\r
354 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);\r
b54fd049 355 DestPath = AllocateZeroPool(PathLen);\r
a405b86d 356\r
3e082d58 357 if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) {\r
9ea69f8a 358 SHELL_FREE_NON_NULL(DestPath);\r
359 SHELL_FREE_NON_NULL(HiiOutput);\r
360 SHELL_FREE_NON_NULL(HiiResultOk);\r
361 return (SHELL_OUT_OF_RESOURCES);\r
362 }\r
363\r
a405b86d 364 //\r
365 // Go through the list of files to copy...\r
366 //\r
367 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
368 ; !IsNull(&FileList->Link, &Node->Link)\r
369 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
f06be00e 370 ){\r
a405b86d 371 if (ShellGetExecutionBreakFlag()) {\r
372 break;\r
373 }\r
374 ASSERT(Node->FileName != NULL);\r
375 ASSERT(Node->FullName != NULL);\r
376\r
377 //\r
378 // skip the directory traversing stuff...\r
379 //\r
380 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
381 continue;\r
382 }\r
383\r
384 if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item\r
385 && EFI_ERROR(ShellIsDirectory(DestDir)) // not an existing directory\r
f06be00e 386 ) {\r
b54fd049 387 if (StrStr(DestDir, L":") == NULL) {\r
388 //\r
389 // simple copy of a single file\r
390 //\r
ed053afe
ED
391 if (Cwd != NULL) {\r
392 StrCpy(DestPath, Cwd);\r
393 } else {\r
394 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, DestDir);\r
395 return (SHELL_INVALID_PARAMETER);\r
396 }\r
b54fd049 397 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {\r
398 StrCat(DestPath, L"\\");\r
399 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {\r
400 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
401 }\r
402 StrCat(DestPath, DestDir);\r
403 } else {\r
404 StrCpy(DestPath, DestDir);\r
a405b86d 405 }\r
a405b86d 406 } else {\r
407 //\r
408 // we have multiple files or a directory in the DestDir\r
409 //\r
1fc3749d 410 \r
411 //\r
412 // Check for leading slash\r
413 //\r
414 if (DestDir[0] == L'\\') {\r
ed053afe
ED
415 //\r
416 // Copy to the root of CWD\r
417 //\r
418 if (Cwd != NULL) {\r
419 StrCpy(DestPath, Cwd);\r
420 } else {\r
421 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, DestDir);\r
422 return (SHELL_INVALID_PARAMETER);\r
423 }\r
1fc3749d 424 while (PathRemoveLastItem(DestPath));\r
425 StrCat(DestPath, DestDir+1);\r
426 StrCat(DestPath, Node->FileName);\r
427 } else if (StrStr(DestDir, L":") == NULL) {\r
ed053afe
ED
428 if (Cwd != NULL) {\r
429 StrCpy(DestPath, Cwd);\r
430 } else {\r
431 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, DestDir);\r
432 return (SHELL_INVALID_PARAMETER);\r
433 }\r
a405b86d 434 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {\r
435 StrCat(DestPath, L"\\");\r
436 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {\r
437 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
438 }\r
439 StrCat(DestPath, DestDir);\r
440 if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
441 StrCat(DestPath, L"\\");\r
442 } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
443 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
444 }\r
445 StrCat(DestPath, Node->FileName);\r
446\r
447 } else {\r
448 StrCpy(DestPath, DestDir);\r
449 if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
450 StrCat(DestPath, L"\\");\r
451 } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
452 ((CHAR16*)DestDir)[StrLen(DestDir)-1] = CHAR_NULL;\r
453 }\r
454 StrCat(DestPath, Node->FileName);\r
455 }\r
456 }\r
457\r
458 //\r
459 // Make sure the path exists\r
460 //\r
461 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {\r
462 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle);\r
463 ShellStatus = SHELL_DEVICE_ERROR;\r
464 break;\r
465 }\r
466\r
467 if ( !EFI_ERROR(ShellIsDirectory(Node->FullName))\r
468 && !EFI_ERROR(ShellIsDirectory(DestPath))\r
469 && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL\r
f06be00e 470 ){\r
a405b86d 471 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle);\r
472 ShellStatus = SHELL_INVALID_PARAMETER;\r
473 break;\r
474 }\r
475 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {\r
476 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle);\r
477 ShellStatus = SHELL_INVALID_PARAMETER;\r
478 break;\r
479 }\r
480\r
5051c287 481 if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0)\r
a405b86d 482 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')\r
f06be00e 483 ) {\r
a405b86d 484 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle);\r
485 ShellStatus = SHELL_INVALID_PARAMETER;\r
486 break;\r
487 }\r
488\r
ab94587a 489 PathCleanUpDirectories(DestPath);\r
a405b86d 490\r
491 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);\r
492\r
493 //\r
494 // copy single file...\r
495 //\r
496 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode);\r
497 if (ShellStatus != SHELL_SUCCESS) {\r
498 break;\r
499 }\r
500 }\r
501 if (ShellStatus == SHELL_SUCCESS && Resp == NULL) {\r
502 ShellPrintEx(-1, -1, L"%s", HiiResultOk);\r
503 }\r
504\r
505 SHELL_FREE_NON_NULL(DestPath);\r
506 SHELL_FREE_NON_NULL(HiiOutput);\r
507 SHELL_FREE_NON_NULL(HiiResultOk);\r
590c3cb1 508 if (Resp == NULL) {\r
a405b86d 509 SHELL_FREE_NON_NULL(Response);\r
510 }\r
511\r
512 return (ShellStatus);\r
f06be00e 513\r
a405b86d 514}\r
515\r
b54fd049 516/**\r
517 Validate and if successful copy all the files from the list into \r
518 destination directory.\r
519\r
520 @param[in] FileList The list of files to copy.\r
521 @param[in] DestDir The directory to copy files to.\r
522 @param[in] SilentMode TRUE to eliminate screen output.\r
523 @param[in] RecursiveMode TRUE to copy directories.\r
524\r
525 @retval SHELL_INVALID_PARAMETER A parameter was invalid.\r
526 @retval SHELL_SUCCESS The operation was successful.\r
527**/\r
a405b86d 528SHELL_STATUS\r
529EFIAPI\r
530ProcessValidateAndCopyFiles(\r
531 IN EFI_SHELL_FILE_INFO *FileList,\r
532 IN CONST CHAR16 *DestDir,\r
533 IN BOOLEAN SilentMode,\r
534 IN BOOLEAN RecursiveMode\r
535 )\r
536{\r
537 SHELL_STATUS ShellStatus;\r
538 EFI_SHELL_FILE_INFO *List;\r
a405b86d 539 EFI_FILE_INFO *FileInfo;\r
ac8783c8 540 CHAR16 *FullName;\r
a405b86d 541\r
ac8783c8
JC
542 List = NULL;\r
543 FullName = NULL;\r
9f56625f 544 FileInfo = NULL;\r
a405b86d 545\r
e755a4ca 546 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);\r
a405b86d 547 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {\r
548 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir);\r
549 ShellStatus = SHELL_INVALID_PARAMETER;\r
550 ShellCloseFileMetaArg(&List);\r
551 } else if (List != NULL) {\r
a405b86d 552 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);\r
553 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);\r
a405b86d 554 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);\r
555 ASSERT(FileInfo != NULL);\r
ac8783c8
JC
556 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);\r
557 ShellCloseFileMetaArg(&List);\r
a405b86d 558 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {\r
ac8783c8 559 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);\r
a405b86d 560 } else {\r
561 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle);\r
562 ShellStatus = SHELL_ACCESS_DENIED;\r
563 }\r
a405b86d 564 } else {\r
ac8783c8 565 ShellCloseFileMetaArg(&List);\r
ed053afe 566 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);\r
a405b86d 567 }\r
568\r
ac8783c8
JC
569 SHELL_FREE_NON_NULL(FileInfo);\r
570 SHELL_FREE_NON_NULL(FullName);\r
a405b86d 571 return (ShellStatus);\r
572}\r
573\r
574STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
575 {L"-r", TypeFlag},\r
576 {L"-q", TypeFlag},\r
577 {NULL, TypeMax}\r
578 };\r
579\r
580/**\r
581 Function for 'cp' command.\r
582\r
583 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
584 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
585**/\r
586SHELL_STATUS\r
587EFIAPI\r
588ShellCommandRunCp (\r
589 IN EFI_HANDLE ImageHandle,\r
590 IN EFI_SYSTEM_TABLE *SystemTable\r
591 )\r
592{\r
593 EFI_STATUS Status;\r
594 LIST_ENTRY *Package;\r
595 CHAR16 *ProblemParam;\r
596 SHELL_STATUS ShellStatus;\r
597 UINTN ParamCount;\r
598 UINTN LoopCounter;\r
599 EFI_SHELL_FILE_INFO *FileList;\r
600 BOOLEAN SilentMode;\r
601 BOOLEAN RecursiveMode;\r
602 CONST CHAR16 *Cwd;\r
603\r
604 ProblemParam = NULL;\r
605 ShellStatus = SHELL_SUCCESS;\r
606 ParamCount = 0;\r
607 FileList = NULL;\r
608\r
609 //\r
610 // initialize the shell lib (we must be in non-auto-init...)\r
611 //\r
612 Status = ShellInitialize();\r
613 ASSERT_EFI_ERROR(Status);\r
614\r
615 Status = CommandInit();\r
616 ASSERT_EFI_ERROR(Status);\r
617\r
618 //\r
619 // parse the command line\r
620 //\r
621 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
622 if (EFI_ERROR(Status)) {\r
623 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
624 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);\r
625 FreePool(ProblemParam);\r
626 ShellStatus = SHELL_INVALID_PARAMETER;\r
627 } else {\r
628 ASSERT(FALSE);\r
629 }\r
630 } else {\r
631 //\r
632 // check for "-?"\r
633 //\r
634 if (ShellCommandLineGetFlag(Package, L"-?")) {\r
635 ASSERT(FALSE);\r
636 }\r
637\r
638 //\r
639 // Initialize SilentMode and RecursiveMode\r
640 //\r
641 if (gEfiShellProtocol->BatchIsActive()) {\r
642 SilentMode = TRUE;\r
643 } else {\r
644 SilentMode = ShellCommandLineGetFlag(Package, L"-q");\r
645 }\r
646 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");\r
647\r
648 switch (ParamCount = ShellCommandLineGetCount(Package)) {\r
649 case 0:\r
650 case 1:\r
651 //\r
652 // we have insufficient parameters\r
653 //\r
654 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle);\r
655 ShellStatus = SHELL_INVALID_PARAMETER;\r
656 break;\r
657 case 2:\r
658 //\r
659 // must have valid CWD for single parameter...\r
660 //\r
661 Cwd = ShellGetCurrentDir(NULL);\r
662 if (Cwd == NULL){\r
663 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);\r
664 ShellStatus = SHELL_INVALID_PARAMETER;\r
665 } else {\r
666 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
667 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
668 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));\r
669 ShellStatus = SHELL_NOT_FOUND;\r
670 } else {\r
671 ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode);\r
672 }\r
673 }\r
674\r
675 break;\r
676 default:\r
677 //\r
678 // Make a big list of all the files...\r
679 //\r
680 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {\r
681 if (ShellGetExecutionBreakFlag()) {\r
682 break;\r
683 }\r
684 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
685 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {\r
b2bf9735 686 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, LoopCounter));\r
a405b86d 687 ShellStatus = SHELL_NOT_FOUND;\r
688 }\r
689 }\r
b2bf9735 690 if (ShellStatus != SHELL_SUCCESS) {\r
a405b86d 691 Status = ShellCloseFileMetaArg(&FileList);\r
b2bf9735 692 } else {\r
693 //\r
694 // now copy them all...\r
695 //\r
696 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
ab94587a 697 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);\r
b2bf9735 698 Status = ShellCloseFileMetaArg(&FileList);\r
699 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
700 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT);\r
701 ShellStatus = SHELL_ACCESS_DENIED;\r
702 }\r
a405b86d 703 }\r
704 }\r
a405b86d 705 break;\r
706 } // switch on parameter count\r
707\r
708 if (FileList != NULL) {\r
709 ShellCloseFileMetaArg(&FileList);\r
710 }\r
711\r
712 //\r
713 // free the command line package\r
714 //\r
715 ShellCommandLineFreeVarList (Package);\r
716 }\r
717\r
718 if (ShellGetExecutionBreakFlag()) {\r
719 return (SHELL_ABORTED);\r
720 }\r
721\r
722 return (ShellStatus);\r
723}\r
724\r