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