]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
ShellPkg/Ls: Consider UEFI timezone may not be set
[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 - 2019, Intel Corporation. All rights reserved.<BR>\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "UefiShellLevel2CommandsLib.h"\r
11#include <Guid/FileSystemInfo.h>\r
12#include <Guid/FileSystemVolumeLabelInfo.h>\r
13\r
14/**\r
15 Function to take a list of files to copy and a destination location and do\r
16 the verification and copying of those files to that location. This function\r
17 will report any errors to the user and halt.\r
18\r
19 @param[in] FileList A LIST_ENTRY* based list of files to move.\r
20 @param[in] DestDir The destination location.\r
21 @param[in] SilentMode TRUE to eliminate screen output.\r
22 @param[in] RecursiveMode TRUE to copy directories.\r
23 @param[in] Resp The response to the overwrite query (if always).\r
24\r
25 @retval SHELL_SUCCESS the files were all moved.\r
26 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
27 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
28 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
29 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
30**/\r
31SHELL_STATUS\r
32ValidateAndCopyFiles(\r
33 IN CONST EFI_SHELL_FILE_INFO *FileList,\r
34 IN CONST CHAR16 *DestDir,\r
35 IN BOOLEAN SilentMode,\r
36 IN BOOLEAN RecursiveMode,\r
37 IN VOID **Resp\r
38 );\r
39\r
40/**\r
41 Function to Copy one file to another location\r
42\r
43 If the destination exists the user will be prompted and the result put into *resp\r
44\r
45 @param[in] Source pointer to source file name\r
46 @param[in] Dest pointer to destination file name\r
47 @param[out] Resp pointer to response from question. Pass back on looped calling\r
48 @param[in] SilentMode whether to run in quiet mode or not\r
49 @param[in] CmdName Source command name requesting single file copy\r
50\r
51 @retval SHELL_SUCCESS The source file was copied to the destination\r
52**/\r
53SHELL_STATUS\r
54CopySingleFile(\r
55 IN CONST CHAR16 *Source,\r
56 IN CONST CHAR16 *Dest,\r
57 OUT VOID **Resp,\r
58 IN BOOLEAN SilentMode,\r
59 IN CONST CHAR16 *CmdName\r
60 )\r
61{\r
62 VOID *Response;\r
63 UINTN ReadSize;\r
64 SHELL_FILE_HANDLE SourceHandle;\r
65 SHELL_FILE_HANDLE DestHandle;\r
66 EFI_STATUS Status;\r
67 VOID *Buffer;\r
68 CHAR16 *TempName;\r
69 UINTN Size;\r
70 EFI_SHELL_FILE_INFO *List;\r
71 SHELL_STATUS ShellStatus;\r
72 UINT64 SourceFileSize;\r
73 UINT64 DestFileSize;\r
74 EFI_FILE_PROTOCOL *DestVolumeFP;\r
75 EFI_FILE_SYSTEM_INFO *DestVolumeInfo;\r
76 UINTN DestVolumeInfoSize;\r
77\r
78 ASSERT(Resp != NULL);\r
79\r
80 SourceHandle = NULL;\r
81 DestHandle = NULL;\r
82 Response = *Resp;\r
83 List = NULL;\r
84 DestVolumeInfo = NULL;\r
85 ShellStatus = SHELL_SUCCESS;\r
86\r
87 ReadSize = PcdGet32(PcdShellFileOperationSize);\r
88 // Why bother copying a file to itself\r
89 if (StrCmp(Source, Dest) == 0) {\r
90 return (SHELL_SUCCESS);\r
91 }\r
92\r
93 //\r
94 // if the destination file existed check response and possibly prompt user\r
95 //\r
96 if (ShellFileExists(Dest) == EFI_SUCCESS) {\r
97 if (Response == NULL && !SilentMode) {\r
98 Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
99 }\r
100 //\r
101 // possibly return based on response\r
102 //\r
103 if (!SilentMode) {\r
104 if (Response == NULL) {\r
105 return SHELL_ABORTED;\r
106 }\r
107 switch (*(SHELL_PROMPT_RESPONSE*)Response) {\r
108 case ShellPromptResponseNo:\r
109 //\r
110 // return success here so we dont stop the process\r
111 //\r
112 return (SHELL_SUCCESS);\r
113 case ShellPromptResponseCancel:\r
114 *Resp = Response;\r
115 //\r
116 // indicate to stop everything\r
117 //\r
118 return (SHELL_ABORTED);\r
119 case ShellPromptResponseAll:\r
120 *Resp = Response;\r
121 case ShellPromptResponseYes:\r
122 break;\r
123 default:\r
124 return SHELL_ABORTED;\r
125 }\r
126 }\r
127 }\r
128\r
129 if (ShellIsDirectory(Source) == EFI_SUCCESS) {\r
130 Status = ShellCreateDirectory(Dest, &DestHandle);\r
131 if (EFI_ERROR(Status)) {\r
132 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest);\r
133 return (SHELL_ACCESS_DENIED);\r
134 }\r
135\r
136 //\r
137 // Now copy all the files under the directory...\r
138 //\r
139 TempName = NULL;\r
140 Size = 0;\r
141 StrnCatGrow(&TempName, &Size, Source, 0);\r
142 StrnCatGrow(&TempName, &Size, L"\\*", 0);\r
143 if (TempName != NULL) {\r
144 ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List);\r
145 *TempName = CHAR_NULL;\r
146 StrnCatGrow(&TempName, &Size, Dest, 0);\r
147 StrnCatGrow(&TempName, &Size, L"\\", 0);\r
148 ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp);\r
149 ShellCloseFileMetaArg(&List);\r
150 SHELL_FREE_NON_NULL(TempName);\r
151 Size = 0;\r
152 }\r
153 } else {\r
154 Status = ShellDeleteFileByName(Dest);\r
155\r
156 //\r
157 // open file with create enabled\r
158 //\r
159 Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);\r
160 if (EFI_ERROR(Status)) {\r
161 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest);\r
162 return (SHELL_ACCESS_DENIED);\r
163 }\r
164\r
165 //\r
166 // open source file\r
167 //\r
168 Status = ShellOpenFileByName (Source, &SourceHandle, EFI_FILE_MODE_READ, 0);\r
169 if (EFI_ERROR (Status)) {\r
170 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source);\r
171 return (SHELL_ACCESS_DENIED);\r
172 }\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, CmdName);\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 if (Buffer == NULL) {\r
228 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, CmdName);\r
229 return SHELL_OUT_OF_RESOURCES;\r
230 }\r
231 while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {\r
232 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);\r
233 if (!EFI_ERROR(Status)) {\r
234 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);\r
235 if (EFI_ERROR(Status)) {\r
236 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
237 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest);\r
238 break;\r
239 }\r
240 } else {\r
241 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
242 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source);\r
243 break;\r
244 }\r
245 }\r
246 }\r
247 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
248 }\r
249\r
250 //\r
251 // close files\r
252 //\r
253 if (DestHandle != NULL) {\r
254 ShellCloseFile(&DestHandle);\r
255 DestHandle = NULL;\r
256 }\r
257 if (SourceHandle != NULL) {\r
258 ShellCloseFile(&SourceHandle);\r
259 SourceHandle = NULL;\r
260 }\r
261\r
262 //\r
263 // return\r
264 //\r
265 return ShellStatus;\r
266}\r
267\r
268/**\r
269 function to take a list of files to copy and a destination location and do\r
270 the verification and copying of those files to that location. This function\r
271 will report any errors to the user and halt.\r
272\r
273 The key is to have this function called ONLY once. this allows for the parameter\r
274 verification to happen correctly.\r
275\r
276 @param[in] FileList A LIST_ENTRY* based list of files to move.\r
277 @param[in] DestDir The destination location.\r
278 @param[in] SilentMode TRUE to eliminate screen output.\r
279 @param[in] RecursiveMode TRUE to copy directories.\r
280 @param[in] Resp The response to the overwrite query (if always).\r
281\r
282 @retval SHELL_SUCCESS the files were all moved.\r
283 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
284 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
285 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
286 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
287**/\r
288SHELL_STATUS\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) + sizeof(CHAR16));\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 StrCpyS(DestPath, PathSize / sizeof(CHAR16), Cwd);\r
428 StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");\r
429 } else {\r
430 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);\r
431 FreePool (CleanFilePathStr);\r
432 return (SHELL_INVALID_PARAMETER);\r
433 }\r
434 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
435 StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");\r
436 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
437 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
438 }\r
439 StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
440 } else {\r
441 StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
442 }\r
443 } else {\r
444 //\r
445 // we have multiple files or a directory in the DestDir\r
446 //\r
447\r
448 //\r
449 // Check for leading slash\r
450 //\r
451 if (CleanFilePathStr[0] == L'\\') {\r
452 //\r
453 // Copy to the root of CWD\r
454 //\r
455 if (Cwd != NULL) {\r
456 StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);\r
457 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
458 } else {\r
459 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);\r
460 FreePool(CleanFilePathStr);\r
461 return (SHELL_INVALID_PARAMETER);\r
462 }\r
463 while (PathRemoveLastItem(DestPath));\r
464 StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr+1);\r
465 StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);\r
466 } else if (StrStr(CleanFilePathStr, L":") == NULL) {\r
467 if (Cwd != NULL) {\r
468 StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);\r
469 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
470 } else {\r
471 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);\r
472 FreePool(CleanFilePathStr);\r
473 return (SHELL_INVALID_PARAMETER);\r
474 }\r
475 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
476 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
477 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
478 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
479 }\r
480 StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
481 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
482 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
483 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
484 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
485 }\r
486 StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);\r
487\r
488 } else {\r
489 StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
490 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
491 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
492 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
493 ((CHAR16*)CleanFilePathStr)[StrLen(CleanFilePathStr)-1] = CHAR_NULL;\r
494 }\r
495 StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);\r
496 }\r
497 }\r
498\r
499 //\r
500 // Make sure the path exists\r
501 //\r
502 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {\r
503 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath);\r
504 ShellStatus = SHELL_DEVICE_ERROR;\r
505 break;\r
506 }\r
507\r
508 if ( !EFI_ERROR(ShellIsDirectory(Node->FullName))\r
509 && !EFI_ERROR(ShellIsDirectory(DestPath))\r
510 && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == 0\r
511 ){\r
512 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp");\r
513 ShellStatus = SHELL_INVALID_PARAMETER;\r
514 break;\r
515 }\r
516 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {\r
517 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");\r
518 ShellStatus = SHELL_INVALID_PARAMETER;\r
519 break;\r
520 }\r
521\r
522 if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0)\r
523 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')\r
524 ) {\r
525 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");\r
526 ShellStatus = SHELL_INVALID_PARAMETER;\r
527 break;\r
528 }\r
529\r
530 PathCleanUpDirectories(DestPath);\r
531\r
532 if (!SilentMode) {\r
533 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);\r
534 }\r
535\r
536 //\r
537 // copy single file...\r
538 //\r
539 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode, L"cp");\r
540 if (ShellStatus != SHELL_SUCCESS) {\r
541 break;\r
542 }\r
543 }\r
544 if (ShellStatus == SHELL_SUCCESS && Resp == NULL) {\r
545 ShellPrintEx(-1, -1, L"%s", HiiResultOk);\r
546 }\r
547\r
548 SHELL_FREE_NON_NULL(DestPath);\r
549 SHELL_FREE_NON_NULL(HiiOutput);\r
550 SHELL_FREE_NON_NULL(HiiResultOk);\r
551 SHELL_FREE_NON_NULL(CleanFilePathStr);\r
552 if (Resp == NULL) {\r
553 SHELL_FREE_NON_NULL(Response);\r
554 }\r
555\r
556 return (ShellStatus);\r
557\r
558}\r
559\r
560/**\r
561 Validate and if successful copy all the files from the list into\r
562 destination directory.\r
563\r
564 @param[in] FileList The list of files to copy.\r
565 @param[in] DestDir The directory to copy files to.\r
566 @param[in] SilentMode TRUE to eliminate screen output.\r
567 @param[in] RecursiveMode TRUE to copy directories.\r
568\r
569 @retval SHELL_INVALID_PARAMETER A parameter was invalid.\r
570 @retval SHELL_SUCCESS The operation was successful.\r
571**/\r
572SHELL_STATUS\r
573ProcessValidateAndCopyFiles(\r
574 IN EFI_SHELL_FILE_INFO *FileList,\r
575 IN CONST CHAR16 *DestDir,\r
576 IN BOOLEAN SilentMode,\r
577 IN BOOLEAN RecursiveMode\r
578 )\r
579{\r
580 SHELL_STATUS ShellStatus;\r
581 EFI_SHELL_FILE_INFO *List;\r
582 EFI_FILE_INFO *FileInfo;\r
583 CHAR16 *FullName;\r
584\r
585 List = NULL;\r
586 FullName = NULL;\r
587 FileInfo = NULL;\r
588\r
589 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);\r
590 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {\r
591 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir);\r
592 ShellStatus = SHELL_INVALID_PARAMETER;\r
593 ShellCloseFileMetaArg(&List);\r
594 } else if (List != NULL) {\r
595 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);\r
596 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);\r
597 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);\r
598 ASSERT(FileInfo != NULL);\r
599 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);\r
600 ShellCloseFileMetaArg(&List);\r
601 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {\r
602 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);\r
603 } else {\r
604 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp");\r
605 ShellStatus = SHELL_ACCESS_DENIED;\r
606 }\r
607 } else {\r
608 ShellCloseFileMetaArg(&List);\r
609 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);\r
610 }\r
611\r
612 SHELL_FREE_NON_NULL(FileInfo);\r
613 SHELL_FREE_NON_NULL(FullName);\r
614 return (ShellStatus);\r
615}\r
616\r
617STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
618 {L"-r", TypeFlag},\r
619 {L"-q", TypeFlag},\r
620 {NULL, TypeMax}\r
621 };\r
622\r
623/**\r
624 Function for 'cp' command.\r
625\r
626 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
627 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
628**/\r
629SHELL_STATUS\r
630EFIAPI\r
631ShellCommandRunCp (\r
632 IN EFI_HANDLE ImageHandle,\r
633 IN EFI_SYSTEM_TABLE *SystemTable\r
634 )\r
635{\r
636 EFI_STATUS Status;\r
637 LIST_ENTRY *Package;\r
638 CHAR16 *ProblemParam;\r
639 SHELL_STATUS ShellStatus;\r
640 UINTN ParamCount;\r
641 UINTN LoopCounter;\r
642 EFI_SHELL_FILE_INFO *FileList;\r
643 BOOLEAN SilentMode;\r
644 BOOLEAN RecursiveMode;\r
645 CONST CHAR16 *Cwd;\r
646 CHAR16 *FullCwd;\r
647\r
648 ProblemParam = NULL;\r
649 ShellStatus = SHELL_SUCCESS;\r
650 ParamCount = 0;\r
651 FileList = NULL;\r
652\r
653 //\r
654 // initialize the shell lib (we must be in non-auto-init...)\r
655 //\r
656 Status = ShellInitialize();\r
657 ASSERT_EFI_ERROR(Status);\r
658\r
659 Status = CommandInit();\r
660 ASSERT_EFI_ERROR(Status);\r
661\r
662 //\r
663 // parse the command line\r
664 //\r
665 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
666 if (EFI_ERROR(Status)) {\r
667 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
668 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam);\r
669 FreePool(ProblemParam);\r
670 ShellStatus = SHELL_INVALID_PARAMETER;\r
671 } else {\r
672 ASSERT(FALSE);\r
673 }\r
674 } else {\r
675 //\r
676 // check for "-?"\r
677 //\r
678 if (ShellCommandLineGetFlag(Package, L"-?")) {\r
679 ASSERT(FALSE);\r
680 }\r
681\r
682 //\r
683 // Initialize SilentMode and RecursiveMode\r
684 //\r
685 if (gEfiShellProtocol->BatchIsActive()) {\r
686 SilentMode = TRUE;\r
687 } else {\r
688 SilentMode = ShellCommandLineGetFlag(Package, L"-q");\r
689 }\r
690 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");\r
691\r
692 switch (ParamCount = ShellCommandLineGetCount(Package)) {\r
693 case 0:\r
694 case 1:\r
695 //\r
696 // we have insufficient parameters\r
697 //\r
698 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp");\r
699 ShellStatus = SHELL_INVALID_PARAMETER;\r
700 break;\r
701 case 2:\r
702 //\r
703 // must have valid CWD for single parameter...\r
704 //\r
705 Cwd = ShellGetCurrentDir(NULL);\r
706 if (Cwd == NULL){\r
707 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp");\r
708 ShellStatus = SHELL_INVALID_PARAMETER;\r
709 } else {\r
710 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
711 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
712 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1));\r
713 ShellStatus = SHELL_NOT_FOUND;\r
714 } else {\r
715 FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16));\r
716 if (FullCwd == NULL) {\r
717 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cp");\r
718 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
719 } else {\r
720 StrCpyS (FullCwd, StrSize (Cwd) / sizeof (CHAR16) + 1, Cwd);\r
721 ShellStatus = ProcessValidateAndCopyFiles (FileList, FullCwd, SilentMode, RecursiveMode);\r
722 FreePool (FullCwd);\r
723 }\r
724 }\r
725 }\r
726\r
727 break;\r
728 default:\r
729 //\r
730 // Make a big list of all the files...\r
731 //\r
732 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {\r
733 if (ShellGetExecutionBreakFlag()) {\r
734 break;\r
735 }\r
736 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
737 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {\r
738 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter));\r
739 ShellStatus = SHELL_NOT_FOUND;\r
740 }\r
741 }\r
742 if (ShellStatus != SHELL_SUCCESS) {\r
743 Status = ShellCloseFileMetaArg(&FileList);\r
744 } else {\r
745 //\r
746 // now copy them all...\r
747 //\r
748 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
749 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);\r
750 Status = ShellCloseFileMetaArg(&FileList);\r
751 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
752 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT);\r
753 ShellStatus = SHELL_ACCESS_DENIED;\r
754 }\r
755 }\r
756 }\r
757 break;\r
758 } // switch on parameter count\r
759\r
760 if (FileList != NULL) {\r
761 ShellCloseFileMetaArg(&FileList);\r
762 }\r
763\r
764 //\r
765 // free the command line package\r
766 //\r
767 ShellCommandLineFreeVarList (Package);\r
768 }\r
769\r
770 if (ShellGetExecutionBreakFlag()) {\r
771 return (SHELL_ABORTED);\r
772 }\r
773\r
774 return (ShellStatus);\r
775}\r
776\r