]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
1. Fix TOCTOU issue in VariableSmm, FtwSmm, FpdtSmm, SmmCorePerformance SMM handler...
[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
a405b86d 90\r
91 ReadSize = PcdGet16(PcdShellFileOperationSize);\r
92 // Why bother copying a file to itself\r
93 if (StrCmp(Source, Dest) == 0) {\r
94 return (SHELL_SUCCESS);\r
95 }\r
96\r
97 //\r
98 // Open destination file without create\r
99 //\r
100 Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);\r
101\r
102 //\r
103 // close file\r
104 //\r
105 if (DestHandle != NULL) {\r
106 ShellCloseFile(&DestHandle);\r
107 DestHandle = NULL;\r
108 }\r
109\r
110 //\r
111 // if the destination file existed check response and possibly prompt user\r
112 //\r
113 if (!EFI_ERROR(Status)) {\r
114 if (Response == NULL && !SilentMode) {\r
b54fd049 115 Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
a405b86d 116 }\r
117 //\r
118 // possibly return based on response\r
119 //\r
120 if (!SilentMode) {\r
121 switch (*(SHELL_PROMPT_RESPONSE*)Response) {\r
122 case ShellPromptResponseNo:\r
123 //\r
124 // return success here so we dont stop the process\r
125 //\r
126 return (SHELL_SUCCESS);\r
127 case ShellPromptResponseCancel:\r
128 *Resp = Response;\r
129 //\r
130 // indicate to stop everything\r
131 //\r
132 return (SHELL_ABORTED);\r
133 case ShellPromptResponseAll:\r
134 *Resp = Response;\r
135 case ShellPromptResponseYes:\r
136 break;\r
e9723321 137 default:\r
138 return SHELL_ABORTED;\r
a405b86d 139 }\r
140 }\r
141 }\r
142\r
143 if (ShellIsDirectory(Source) == EFI_SUCCESS) {\r
144 Status = ShellCreateDirectory(Dest, &DestHandle);\r
145 if (EFI_ERROR(Status)) {\r
146 return (SHELL_ACCESS_DENIED);\r
147 }\r
148\r
149 //\r
150 // Now copy all the files under the directory...\r
151 //\r
152 TempName = NULL;\r
f06be00e 153 Size = 0;\r
a405b86d 154 StrnCatGrow(&TempName, &Size, Source, 0);\r
155 StrnCatGrow(&TempName, &Size, L"\\*", 0);\r
7dd05623 156 if (TempName != NULL) {\r
157 ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List);\r
158 *TempName = CHAR_NULL;\r
159 StrnCatGrow(&TempName, &Size, Dest, 0);\r
160 StrnCatGrow(&TempName, &Size, L"\\", 0);\r
161 ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp);\r
162 ShellCloseFileMetaArg(&List);\r
163 SHELL_FREE_NON_NULL(TempName);\r
164 Size = 0;\r
165 }\r
a405b86d 166 } else {\r
f06be00e 167 //\r
168 // open file with create enabled\r
169 //\r
170 Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);\r
171 if (EFI_ERROR(Status)) {\r
172 return (SHELL_ACCESS_DENIED);\r
173 }\r
a405b86d 174\r
f06be00e 175 //\r
176 // open source file\r
177 //\r
178 Status = ShellOpenFileByName(Source, &SourceHandle, EFI_FILE_MODE_READ, 0);\r
a405b86d 179 ASSERT_EFI_ERROR(Status);\r
f06be00e 180\r
181 //\r
182 //get file size of source file and freespace available on destination volume\r
183 //\r
184 ShellGetFileSize(SourceHandle, &SourceFileSize);\r
185 ShellGetFileSize(DestHandle, &DestFileSize);\r
186\r
187 //\r
188 //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space\r
189 //\r
190 if(DestFileSize < SourceFileSize){\r
191 SourceFileSize -= DestFileSize;\r
192 } else {\r
193 SourceFileSize = 0;\r
194 }\r
195\r
196 //\r
197 //get the system volume info to check the free space\r
198 //\r
199 DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle);\r
200 DestVolumeInfo = NULL;\r
201 DestVolumeInfoSize = 0;\r
202 Status = DestVolumeFP->GetInfo(\r
203 DestVolumeFP,\r
204 &gEfiFileSystemInfoGuid,\r
205 &DestVolumeInfoSize,\r
206 DestVolumeInfo\r
207 );\r
208\r
209 if (Status == EFI_BUFFER_TOO_SMALL) {\r
210 DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize);\r
211 Status = DestVolumeFP->GetInfo(\r
212 DestVolumeFP,\r
213 &gEfiFileSystemInfoGuid,\r
214 &DestVolumeInfoSize,\r
215 DestVolumeInfo\r
216 );\r
217 }\r
218\r
219 //\r
220 //check if enough space available on destination drive to complete copy\r
221 //\r
0290177a 222 if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) {\r
f06be00e 223 //\r
224 //not enough space on destination directory to copy file\r
225 //\r
226 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
227 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle);\r
228 return(SHELL_VOLUME_FULL);\r
229 } else {\r
230 //\r
231 // copy data between files\r
232 //\r
233 Buffer = AllocateZeroPool(ReadSize);\r
234 ASSERT(Buffer != NULL);\r
235 while (ReadSize == PcdGet16(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {\r
236 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);\r
237 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);\r
238 }\r
239 }\r
240 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
a405b86d 241 }\r
a405b86d 242\r
243 //\r
244 // close files\r
245 //\r
246 if (DestHandle != NULL) {\r
247 ShellCloseFile(&DestHandle);\r
248 DestHandle = NULL;\r
249 }\r
250 if (SourceHandle != NULL) {\r
251 ShellCloseFile(&SourceHandle);\r
252 SourceHandle = NULL;\r
253 }\r
254\r
255 //\r
256 // return\r
257 //\r
258 return (SHELL_SUCCESS);\r
259}\r
260\r
261/**\r
262 function to take a list of files to copy and a destination location and do\r
263 the verification and copying of those files to that location. This function\r
264 will report any errors to the user and halt.\r
265\r
266 The key is to have this function called ONLY once. this allows for the parameter\r
267 verification to happen correctly.\r
268\r
b54fd049 269 @param[in] FileList A LIST_ENTRY* based list of files to move.\r
270 @param[in] DestDir The destination location.\r
271 @param[in] SilentMode TRUE to eliminate screen output.\r
272 @param[in] RecursiveMode TRUE to copy directories.\r
273 @param[in] Resp The response to the overwrite query (if always).\r
a405b86d 274\r
275 @retval SHELL_SUCCESS the files were all moved.\r
276 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
277 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
278 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
279 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
280**/\r
281SHELL_STATUS\r
282EFIAPI\r
283ValidateAndCopyFiles(\r
284 IN CONST EFI_SHELL_FILE_INFO *FileList,\r
285 IN CONST CHAR16 *DestDir,\r
286 IN BOOLEAN SilentMode,\r
287 IN BOOLEAN RecursiveMode,\r
288 IN VOID **Resp\r
289 )\r
290{\r
291 CHAR16 *HiiOutput;\r
292 CHAR16 *HiiResultOk;\r
293 CONST EFI_SHELL_FILE_INFO *Node;\r
294 SHELL_STATUS ShellStatus;\r
295 CHAR16 *DestPath;\r
296 VOID *Response;\r
297 UINTN PathLen;\r
298 CONST CHAR16 *Cwd;\r
299 CONST CHAR16 *TempLocation;\r
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
f1518f69 316 //\r
317 // We already verified that this was present.\r
318 //\r
319 ASSERT(Cwd != NULL);\r
320\r
a405b86d 321 //\r
322 // If we are trying to copy multiple files... make sure we got a directory for the target...\r
323 //\r
324 if (EFI_ERROR(ShellIsDirectory(DestDir)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {\r
325 //\r
326 // Error for destination not a directory\r
327 //\r
328 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir);\r
329 return (SHELL_INVALID_PARAMETER);\r
330 }\r
331 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
332 ; !IsNull(&FileList->Link, &Node->Link)\r
333 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
f06be00e 334 ){\r
a405b86d 335 //\r
336 // skip the directory traversing stuff...\r
337 //\r
338 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
339 continue;\r
340 }\r
341\r
342 NewSize = StrSize(DestDir);\r
b54fd049 343 NewSize += StrSize(Node->FullName);\r
a405b86d 344 NewSize += StrSize(Cwd);\r
345 if (NewSize > PathLen) {\r
346 PathLen = NewSize;\r
347 }\r
348\r
349 //\r
350 // Make sure got -r if required\r
351 //\r
352 if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) {\r
353 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle);\r
354 return (SHELL_INVALID_PARAMETER);\r
355 }\r
356\r
357 //\r
358 // make sure got dest as dir if needed\r
359 //\r
360 if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(DestDir))) {\r
361 //\r
362 // Error for destination not a directory\r
363 //\r
364 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir);\r
365 return (SHELL_INVALID_PARAMETER);\r
366 }\r
367 }\r
368\r
369 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);\r
370 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);\r
b54fd049 371 DestPath = AllocateZeroPool(PathLen);\r
a405b86d 372\r
3e082d58 373 if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) {\r
9ea69f8a 374 SHELL_FREE_NON_NULL(DestPath);\r
375 SHELL_FREE_NON_NULL(HiiOutput);\r
376 SHELL_FREE_NON_NULL(HiiResultOk);\r
377 return (SHELL_OUT_OF_RESOURCES);\r
378 }\r
379\r
a405b86d 380 //\r
381 // Go through the list of files to copy...\r
382 //\r
383 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
384 ; !IsNull(&FileList->Link, &Node->Link)\r
385 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
f06be00e 386 ){\r
a405b86d 387 if (ShellGetExecutionBreakFlag()) {\r
388 break;\r
389 }\r
390 ASSERT(Node->FileName != NULL);\r
391 ASSERT(Node->FullName != NULL);\r
392\r
393 //\r
394 // skip the directory traversing stuff...\r
395 //\r
396 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
397 continue;\r
398 }\r
399\r
400 if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item\r
401 && EFI_ERROR(ShellIsDirectory(DestDir)) // not an existing directory\r
f06be00e 402 ) {\r
b54fd049 403 if (StrStr(DestDir, L":") == NULL) {\r
404 //\r
405 // simple copy of a single file\r
406 //\r
407 StrCpy(DestPath, Cwd);\r
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
f06be00e 426 //\r
427 // Copy to the root of CWD\r
428 //\r
1fc3749d 429 StrCpy(DestPath, Cwd);\r
430 while (PathRemoveLastItem(DestPath));\r
431 StrCat(DestPath, DestDir+1);\r
432 StrCat(DestPath, Node->FileName);\r
433 } else if (StrStr(DestDir, L":") == NULL) {\r
a405b86d 434 StrCpy(DestPath, Cwd);\r
435 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {\r
436 StrCat(DestPath, L"\\");\r
437 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {\r
438 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
439 }\r
440 StrCat(DestPath, DestDir);\r
441 if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
442 StrCat(DestPath, L"\\");\r
443 } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
444 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
445 }\r
446 StrCat(DestPath, Node->FileName);\r
447\r
448 } else {\r
449 StrCpy(DestPath, DestDir);\r
450 if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
451 StrCat(DestPath, L"\\");\r
452 } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
453 ((CHAR16*)DestDir)[StrLen(DestDir)-1] = CHAR_NULL;\r
454 }\r
455 StrCat(DestPath, Node->FileName);\r
456 }\r
457 }\r
458\r
459 //\r
460 // Make sure the path exists\r
461 //\r
462 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {\r
463 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle);\r
464 ShellStatus = SHELL_DEVICE_ERROR;\r
465 break;\r
466 }\r
467\r
468 if ( !EFI_ERROR(ShellIsDirectory(Node->FullName))\r
469 && !EFI_ERROR(ShellIsDirectory(DestPath))\r
470 && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL\r
f06be00e 471 ){\r
a405b86d 472 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle);\r
473 ShellStatus = SHELL_INVALID_PARAMETER;\r
474 break;\r
475 }\r
476 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {\r
477 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle);\r
478 ShellStatus = SHELL_INVALID_PARAMETER;\r
479 break;\r
480 }\r
481\r
482 if ((TempLocation = StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName))) == 0\r
483 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')\r
f06be00e 484 ) {\r
a405b86d 485 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle);\r
486 ShellStatus = SHELL_INVALID_PARAMETER;\r
487 break;\r
488 }\r
489\r
ab94587a 490 PathCleanUpDirectories(DestPath);\r
a405b86d 491\r
492 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);\r
493\r
494 //\r
495 // copy single file...\r
496 //\r
497 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode);\r
498 if (ShellStatus != SHELL_SUCCESS) {\r
499 break;\r
500 }\r
501 }\r
502 if (ShellStatus == SHELL_SUCCESS && Resp == NULL) {\r
503 ShellPrintEx(-1, -1, L"%s", HiiResultOk);\r
504 }\r
505\r
506 SHELL_FREE_NON_NULL(DestPath);\r
507 SHELL_FREE_NON_NULL(HiiOutput);\r
508 SHELL_FREE_NON_NULL(HiiResultOk);\r
590c3cb1 509 if (Resp == NULL) {\r
a405b86d 510 SHELL_FREE_NON_NULL(Response);\r
511 }\r
512\r
513 return (ShellStatus);\r
f06be00e 514\r
a405b86d 515}\r
516\r
b54fd049 517/**\r
518 Validate and if successful copy all the files from the list into \r
519 destination directory.\r
520\r
521 @param[in] FileList The list of files to copy.\r
522 @param[in] DestDir The directory to copy files to.\r
523 @param[in] SilentMode TRUE to eliminate screen output.\r
524 @param[in] RecursiveMode TRUE to copy directories.\r
525\r
526 @retval SHELL_INVALID_PARAMETER A parameter was invalid.\r
527 @retval SHELL_SUCCESS The operation was successful.\r
528**/\r
a405b86d 529SHELL_STATUS\r
530EFIAPI\r
531ProcessValidateAndCopyFiles(\r
532 IN EFI_SHELL_FILE_INFO *FileList,\r
533 IN CONST CHAR16 *DestDir,\r
534 IN BOOLEAN SilentMode,\r
535 IN BOOLEAN RecursiveMode\r
536 )\r
537{\r
538 SHELL_STATUS ShellStatus;\r
539 EFI_SHELL_FILE_INFO *List;\r
540 EFI_STATUS Status;\r
541 EFI_FILE_INFO *FileInfo;\r
542\r
543 List = NULL;\r
544\r
545 Status = ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);\r
546 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {\r
547 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir);\r
548 ShellStatus = SHELL_INVALID_PARAMETER;\r
549 ShellCloseFileMetaArg(&List);\r
550 } else if (List != NULL) {\r
a405b86d 551 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);\r
552 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);\r
553 FileInfo = NULL;\r
554 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);\r
555 ASSERT(FileInfo != NULL);\r
556 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {\r
557 ShellStatus = ValidateAndCopyFiles(FileList, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, SilentMode, RecursiveMode, NULL);\r
558 } else {\r
559 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle);\r
560 ShellStatus = SHELL_ACCESS_DENIED;\r
561 }\r
562 SHELL_FREE_NON_NULL(FileInfo);\r
563 ShellCloseFileMetaArg(&List);\r
564 } else {\r
565 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);\r
566 }\r
567\r
568 return (ShellStatus);\r
569}\r
570\r
571STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
572 {L"-r", TypeFlag},\r
573 {L"-q", TypeFlag},\r
574 {NULL, TypeMax}\r
575 };\r
576\r
577/**\r
578 Function for 'cp' command.\r
579\r
580 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
581 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
582**/\r
583SHELL_STATUS\r
584EFIAPI\r
585ShellCommandRunCp (\r
586 IN EFI_HANDLE ImageHandle,\r
587 IN EFI_SYSTEM_TABLE *SystemTable\r
588 )\r
589{\r
590 EFI_STATUS Status;\r
591 LIST_ENTRY *Package;\r
592 CHAR16 *ProblemParam;\r
593 SHELL_STATUS ShellStatus;\r
594 UINTN ParamCount;\r
595 UINTN LoopCounter;\r
596 EFI_SHELL_FILE_INFO *FileList;\r
597 BOOLEAN SilentMode;\r
598 BOOLEAN RecursiveMode;\r
599 CONST CHAR16 *Cwd;\r
600\r
601 ProblemParam = NULL;\r
602 ShellStatus = SHELL_SUCCESS;\r
603 ParamCount = 0;\r
604 FileList = NULL;\r
605\r
606 //\r
607 // initialize the shell lib (we must be in non-auto-init...)\r
608 //\r
609 Status = ShellInitialize();\r
610 ASSERT_EFI_ERROR(Status);\r
611\r
612 Status = CommandInit();\r
613 ASSERT_EFI_ERROR(Status);\r
614\r
615 //\r
616 // parse the command line\r
617 //\r
618 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
619 if (EFI_ERROR(Status)) {\r
620 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
621 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);\r
622 FreePool(ProblemParam);\r
623 ShellStatus = SHELL_INVALID_PARAMETER;\r
624 } else {\r
625 ASSERT(FALSE);\r
626 }\r
627 } else {\r
628 //\r
629 // check for "-?"\r
630 //\r
631 if (ShellCommandLineGetFlag(Package, L"-?")) {\r
632 ASSERT(FALSE);\r
633 }\r
634\r
635 //\r
636 // Initialize SilentMode and RecursiveMode\r
637 //\r
638 if (gEfiShellProtocol->BatchIsActive()) {\r
639 SilentMode = TRUE;\r
640 } else {\r
641 SilentMode = ShellCommandLineGetFlag(Package, L"-q");\r
642 }\r
643 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");\r
644\r
645 switch (ParamCount = ShellCommandLineGetCount(Package)) {\r
646 case 0:\r
647 case 1:\r
648 //\r
649 // we have insufficient parameters\r
650 //\r
651 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle);\r
652 ShellStatus = SHELL_INVALID_PARAMETER;\r
653 break;\r
654 case 2:\r
655 //\r
656 // must have valid CWD for single parameter...\r
657 //\r
658 Cwd = ShellGetCurrentDir(NULL);\r
659 if (Cwd == NULL){\r
660 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);\r
661 ShellStatus = SHELL_INVALID_PARAMETER;\r
662 } else {\r
663 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
664 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
665 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));\r
666 ShellStatus = SHELL_NOT_FOUND;\r
667 } else {\r
668 ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode);\r
669 }\r
670 }\r
671\r
672 break;\r
673 default:\r
674 //\r
675 // Make a big list of all the files...\r
676 //\r
677 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {\r
678 if (ShellGetExecutionBreakFlag()) {\r
679 break;\r
680 }\r
681 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
682 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {\r
b2bf9735 683 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, LoopCounter));\r
a405b86d 684 ShellStatus = SHELL_NOT_FOUND;\r
685 }\r
686 }\r
b2bf9735 687 if (ShellStatus != SHELL_SUCCESS) {\r
a405b86d 688 Status = ShellCloseFileMetaArg(&FileList);\r
b2bf9735 689 } else {\r
690 //\r
691 // now copy them all...\r
692 //\r
693 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
ab94587a 694 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);\r
b2bf9735 695 Status = ShellCloseFileMetaArg(&FileList);\r
696 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
697 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT);\r
698 ShellStatus = SHELL_ACCESS_DENIED;\r
699 }\r
a405b86d 700 }\r
701 }\r
a405b86d 702 break;\r
703 } // switch on parameter count\r
704\r
705 if (FileList != NULL) {\r
706 ShellCloseFileMetaArg(&FileList);\r
707 }\r
708\r
709 //\r
710 // free the command line package\r
711 //\r
712 ShellCommandLineFreeVarList (Package);\r
713 }\r
714\r
715 if (ShellGetExecutionBreakFlag()) {\r
716 return (SHELL_ABORTED);\r
717 }\r
718\r
719 return (ShellStatus);\r
720}\r
721\r