]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
ShellPkg: fix mv and cp command related issues
[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 @param[in] CmdName Source command name requesting single file copy\r
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
66 IN BOOLEAN SilentMode,\r
67 IN CONST CHAR16 *CmdName\r
68 )\r
69{\r
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
85\r
86 ASSERT(Resp != NULL);\r
87\r
88 SourceHandle = NULL;\r
89 DestHandle = NULL;\r
90 Response = *Resp;\r
91 List = NULL;\r
92 DestVolumeInfo = NULL;\r
93 ShellStatus = SHELL_SUCCESS;\r
94\r
95 ReadSize = PcdGet32(PcdShellFileOperationSize);\r
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
101 //\r
102 // if the destination file existed check response and possibly prompt user\r
103 //\r
104 if (ShellFileExists(Dest) == EFI_SUCCESS) {\r
105 if (Response == NULL && !SilentMode) {\r
106 Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
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
128 default:\r
129 return SHELL_ABORTED;\r
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
137 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest); \r
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
145 Size = 0;\r
146 StrnCatGrow(&TempName, &Size, Source, 0);\r
147 StrnCatGrow(&TempName, &Size, L"\\*", 0);\r
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
158 } else {\r
159 Status = ShellDeleteFileByName(Dest);\r
160\r
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
166 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest); \r
167 return (SHELL_ACCESS_DENIED);\r
168 }\r
169\r
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
175\r
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
181\r
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
206 Status = DestVolumeFP->GetInfo(\r
207 DestVolumeFP,\r
208 &gEfiFileSystemInfoGuid,\r
209 &DestVolumeInfoSize,\r
210 DestVolumeInfo\r
211 );\r
212 }\r
213\r
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
218 //\r
219 //not enough space on destination directory to copy file\r
220 //\r
221 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
222 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName); \r
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
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
236 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest); \r
237 break;\r
238 }\r
239 } else {\r
240 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
241 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source); \r
242 break;\r
243 }\r
244 }\r
245 }\r
246 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
247 }\r
248 \r
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
264 return ShellStatus;\r
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
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
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
301 EFI_STATUS Status;\r
302 CHAR16 *DestPath;\r
303 VOID *Response;\r
304 UINTN PathSize;\r
305 CONST CHAR16 *Cwd;\r
306 UINTN NewSize;\r
307 CHAR16 *CleanFilePathStr;\r
308\r
309 if (Resp == NULL) {\r
310 Response = NULL;\r
311 } else {\r
312 Response = *Resp;\r
313 }\r
314\r
315 DestPath = NULL;\r
316 ShellStatus = SHELL_SUCCESS;\r
317 PathSize = 0;\r
318 Cwd = ShellGetCurrentDir(NULL);\r
319 CleanFilePathStr = NULL;\r
320\r
321 ASSERT(FileList != NULL);\r
322 ASSERT(DestDir != NULL);\r
323\r
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
332 }\r
333 \r
334 ASSERT (CleanFilePathStr != NULL);\r
335\r
336 //\r
337 // If we are trying to copy multiple files... make sure we got a directory for the target...\r
338 //\r
339 if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {\r
340 //\r
341 // Error for destination not a directory\r
342 //\r
343 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
344 FreePool (CleanFilePathStr);\r
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
350 ){\r
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
358 NewSize = StrSize(CleanFilePathStr);\r
359 NewSize += StrSize(Node->FullName);\r
360 NewSize += (Cwd == NULL)? 0 : StrSize(Cwd);\r
361 if (NewSize > PathSize) {\r
362 PathSize = NewSize;\r
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
369 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp"); \r
370 FreePool (CleanFilePathStr);\r
371 return (SHELL_INVALID_PARAMETER);\r
372 }\r
373\r
374 //\r
375 // make sure got dest as dir if needed\r
376 //\r
377 if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))) {\r
378 //\r
379 // Error for destination not a directory\r
380 //\r
381 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
382 FreePool (CleanFilePathStr);\r
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
389 DestPath = AllocateZeroPool(PathSize);\r
390\r
391 if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) {\r
392 SHELL_FREE_NON_NULL(DestPath);\r
393 SHELL_FREE_NON_NULL(HiiOutput);\r
394 SHELL_FREE_NON_NULL(HiiResultOk);\r
395 FreePool (CleanFilePathStr);\r
396 return (SHELL_OUT_OF_RESOURCES);\r
397 }\r
398\r
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
405 ){\r
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
420 && EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) // not an existing directory\r
421 ) {\r
422 if (StrStr(CleanFilePathStr, L":") == NULL) {\r
423 //\r
424 // simple copy of a single file\r
425 //\r
426 if (Cwd != NULL) {\r
427 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16)-1);\r
428 } else {\r
429 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
430 FreePool (CleanFilePathStr);\r
431 return (SHELL_INVALID_PARAMETER);\r
432 }\r
433 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
434 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
435 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
436 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
437 }\r
438 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
439 } else {\r
440 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1);\r
441 }\r
442 } else {\r
443 //\r
444 // we have multiple files or a directory in the DestDir\r
445 //\r
446 \r
447 //\r
448 // Check for leading slash\r
449 //\r
450 if (CleanFilePathStr[0] == L'\\') {\r
451 //\r
452 // Copy to the root of CWD\r
453 //\r
454 if (Cwd != NULL) {\r
455 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1);\r
456 } else {\r
457 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
458 FreePool(CleanFilePathStr);\r
459 return (SHELL_INVALID_PARAMETER);\r
460 }\r
461 while (PathRemoveLastItem(DestPath));\r
462 StrnCat(DestPath, CleanFilePathStr+1, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
463 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
464 } else if (StrStr(CleanFilePathStr, L":") == NULL) {\r
465 if (Cwd != NULL) {\r
466 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1);\r
467 } else {\r
468 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
469 FreePool(CleanFilePathStr);\r
470 return (SHELL_INVALID_PARAMETER);\r
471 }\r
472 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
473 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
474 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
475 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
476 }\r
477 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
478 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
479 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
480 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
481 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
482 }\r
483 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
484\r
485 } else {\r
486 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1);\r
487 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
488 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
489 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
490 ((CHAR16*)CleanFilePathStr)[StrLen(CleanFilePathStr)-1] = CHAR_NULL;\r
491 }\r
492 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
493 }\r
494 }\r
495 \r
496 //\r
497 // Make sure the path exists\r
498 //\r
499 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {\r
500 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath); \r
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
508 ){\r
509 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp"); \r
510 ShellStatus = SHELL_INVALID_PARAMETER;\r
511 break;\r
512 }\r
513 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {\r
514 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); \r
515 ShellStatus = SHELL_INVALID_PARAMETER;\r
516 break;\r
517 }\r
518\r
519 if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0)\r
520 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')\r
521 ) {\r
522 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); \r
523 ShellStatus = SHELL_INVALID_PARAMETER;\r
524 break;\r
525 }\r
526\r
527 PathCleanUpDirectories(DestPath);\r
528\r
529 if (!SilentMode) {\r
530 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);\r
531 }\r
532\r
533 //\r
534 // copy single file...\r
535 //\r
536 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode, L"cp");\r
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
548 SHELL_FREE_NON_NULL(CleanFilePathStr);\r
549 if (Resp == NULL) {\r
550 SHELL_FREE_NON_NULL(Response);\r
551 }\r
552\r
553 return (ShellStatus);\r
554\r
555}\r
556\r
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
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
580 EFI_FILE_INFO *FileInfo;\r
581 CHAR16 *FullName;\r
582\r
583 List = NULL;\r
584 FullName = NULL;\r
585 FileInfo = NULL;\r
586\r
587 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);\r
588 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {\r
589 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir); \r
590 ShellStatus = SHELL_INVALID_PARAMETER;\r
591 ShellCloseFileMetaArg(&List);\r
592 } else if (List != NULL) {\r
593 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);\r
594 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);\r
595 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);\r
596 ASSERT(FileInfo != NULL);\r
597 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);\r
598 ShellCloseFileMetaArg(&List);\r
599 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {\r
600 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);\r
601 } else {\r
602 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp"); \r
603 ShellStatus = SHELL_ACCESS_DENIED;\r
604 }\r
605 } else {\r
606 ShellCloseFileMetaArg(&List);\r
607 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);\r
608 }\r
609\r
610 SHELL_FREE_NON_NULL(FileInfo);\r
611 SHELL_FREE_NON_NULL(FullName);\r
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
665 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam); \r
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
695 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp"); \r
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
704 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp"); \r
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
709 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1)); \r
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
727 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter)); \r
728 ShellStatus = SHELL_NOT_FOUND;\r
729 }\r
730 }\r
731 if (ShellStatus != SHELL_SUCCESS) {\r
732 Status = ShellCloseFileMetaArg(&FileList);\r
733 } else {\r
734 //\r
735 // now copy them all...\r
736 //\r
737 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
738 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);\r
739 Status = ShellCloseFileMetaArg(&FileList);\r
740 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
741 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT); \r
742 ShellStatus = SHELL_ACCESS_DENIED;\r
743 }\r
744 }\r
745 }\r
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