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