]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
ShellPkg: Fix buffer overflow issue in 'map' command.
[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 if (EFI_ERROR (Status)) {\r
175 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source);\r
176 return (SHELL_ACCESS_DENIED);\r
177 }\r
178\r
179 //\r
180 //get file size of source file and freespace available on destination volume\r
181 //\r
182 ShellGetFileSize(SourceHandle, &SourceFileSize);\r
183 ShellGetFileSize(DestHandle, &DestFileSize);\r
184\r
185 //\r
186 //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space\r
187 //\r
188 if(DestFileSize < SourceFileSize){\r
189 SourceFileSize -= DestFileSize;\r
190 } else {\r
191 SourceFileSize = 0;\r
192 }\r
193\r
194 //\r
195 //get the system volume info to check the free space\r
196 //\r
197 DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle);\r
198 DestVolumeInfo = NULL;\r
199 DestVolumeInfoSize = 0;\r
200 Status = DestVolumeFP->GetInfo(\r
201 DestVolumeFP,\r
202 &gEfiFileSystemInfoGuid,\r
203 &DestVolumeInfoSize,\r
204 DestVolumeInfo\r
205 );\r
206\r
207 if (Status == EFI_BUFFER_TOO_SMALL) {\r
208 DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize);\r
209 Status = DestVolumeFP->GetInfo(\r
210 DestVolumeFP,\r
211 &gEfiFileSystemInfoGuid,\r
212 &DestVolumeInfoSize,\r
213 DestVolumeInfo\r
214 );\r
215 }\r
216\r
217 //\r
218 //check if enough space available on destination drive to complete copy\r
219 //\r
220 if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) {\r
221 //\r
222 //not enough space on destination directory to copy file\r
223 //\r
224 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
225 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName); \r
226 return(SHELL_VOLUME_FULL);\r
227 } else {\r
228 //\r
229 // copy data between files\r
230 //\r
231 Buffer = AllocateZeroPool(ReadSize);\r
232 ASSERT(Buffer != NULL);\r
233 while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {\r
234 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);\r
235 if (!EFI_ERROR(Status)) {\r
236 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);\r
237 if (EFI_ERROR(Status)) {\r
238 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
239 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest); \r
240 break;\r
241 }\r
242 } else {\r
243 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
244 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source); \r
245 break;\r
246 }\r
247 }\r
248 }\r
249 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
250 }\r
251 \r
252 //\r
253 // close files\r
254 //\r
255 if (DestHandle != NULL) {\r
256 ShellCloseFile(&DestHandle);\r
257 DestHandle = NULL;\r
258 }\r
259 if (SourceHandle != NULL) {\r
260 ShellCloseFile(&SourceHandle);\r
261 SourceHandle = NULL;\r
262 }\r
263\r
264 //\r
265 // return\r
266 //\r
267 return ShellStatus;\r
268}\r
269\r
270/**\r
271 function to take a list of files to copy and a destination location and do\r
272 the verification and copying of those files to that location. This function\r
273 will report any errors to the user and halt.\r
274\r
275 The key is to have this function called ONLY once. this allows for the parameter\r
276 verification to happen correctly.\r
277\r
278 @param[in] FileList A LIST_ENTRY* based list of files to move.\r
279 @param[in] DestDir The destination location.\r
280 @param[in] SilentMode TRUE to eliminate screen output.\r
281 @param[in] RecursiveMode TRUE to copy directories.\r
282 @param[in] Resp The response to the overwrite query (if always).\r
283\r
284 @retval SHELL_SUCCESS the files were all moved.\r
285 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
286 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
287 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
288 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
289**/\r
290SHELL_STATUS\r
291EFIAPI\r
292ValidateAndCopyFiles(\r
293 IN CONST EFI_SHELL_FILE_INFO *FileList,\r
294 IN CONST CHAR16 *DestDir,\r
295 IN BOOLEAN SilentMode,\r
296 IN BOOLEAN RecursiveMode,\r
297 IN VOID **Resp\r
298 )\r
299{\r
300 CHAR16 *HiiOutput;\r
301 CHAR16 *HiiResultOk;\r
302 CONST EFI_SHELL_FILE_INFO *Node;\r
303 SHELL_STATUS ShellStatus;\r
304 EFI_STATUS Status;\r
305 CHAR16 *DestPath;\r
306 VOID *Response;\r
307 UINTN PathSize;\r
308 CONST CHAR16 *Cwd;\r
309 UINTN NewSize;\r
310 CHAR16 *CleanFilePathStr;\r
311\r
312 if (Resp == NULL) {\r
313 Response = NULL;\r
314 } else {\r
315 Response = *Resp;\r
316 }\r
317\r
318 DestPath = NULL;\r
319 ShellStatus = SHELL_SUCCESS;\r
320 PathSize = 0;\r
321 Cwd = ShellGetCurrentDir(NULL);\r
322 CleanFilePathStr = NULL;\r
323\r
324 ASSERT(FileList != NULL);\r
325 ASSERT(DestDir != NULL);\r
326\r
327 \r
328 Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr);\r
329 if (EFI_ERROR (Status)) {\r
330 if (Status == EFI_OUT_OF_RESOURCES) {\r
331 return SHELL_OUT_OF_RESOURCES;\r
332 } else {\r
333 return SHELL_INVALID_PARAMETER;\r
334 }\r
335 }\r
336 \r
337 ASSERT (CleanFilePathStr != NULL);\r
338\r
339 //\r
340 // If we are trying to copy multiple files... make sure we got a directory for the target...\r
341 //\r
342 if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {\r
343 //\r
344 // Error for destination not a directory\r
345 //\r
346 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
347 FreePool (CleanFilePathStr);\r
348 return (SHELL_INVALID_PARAMETER);\r
349 }\r
350 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
351 ; !IsNull(&FileList->Link, &Node->Link)\r
352 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
353 ){\r
354 //\r
355 // skip the directory traversing stuff...\r
356 //\r
357 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
358 continue;\r
359 }\r
360\r
361 NewSize = StrSize(CleanFilePathStr);\r
362 NewSize += StrSize(Node->FullName);\r
363 NewSize += (Cwd == NULL)? 0 : StrSize(Cwd);\r
364 if (NewSize > PathSize) {\r
365 PathSize = NewSize;\r
366 }\r
367\r
368 //\r
369 // Make sure got -r if required\r
370 //\r
371 if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) {\r
372 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp"); \r
373 FreePool (CleanFilePathStr);\r
374 return (SHELL_INVALID_PARAMETER);\r
375 }\r
376\r
377 //\r
378 // make sure got dest as dir if needed\r
379 //\r
380 if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))) {\r
381 //\r
382 // Error for destination not a directory\r
383 //\r
384 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
385 FreePool (CleanFilePathStr);\r
386 return (SHELL_INVALID_PARAMETER);\r
387 }\r
388 }\r
389\r
390 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);\r
391 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);\r
392 DestPath = AllocateZeroPool(PathSize);\r
393\r
394 if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) {\r
395 SHELL_FREE_NON_NULL(DestPath);\r
396 SHELL_FREE_NON_NULL(HiiOutput);\r
397 SHELL_FREE_NON_NULL(HiiResultOk);\r
398 FreePool (CleanFilePathStr);\r
399 return (SHELL_OUT_OF_RESOURCES);\r
400 }\r
401\r
402 //\r
403 // Go through the list of files to copy...\r
404 //\r
405 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
406 ; !IsNull(&FileList->Link, &Node->Link)\r
407 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
408 ){\r
409 if (ShellGetExecutionBreakFlag()) {\r
410 break;\r
411 }\r
412 ASSERT(Node->FileName != NULL);\r
413 ASSERT(Node->FullName != NULL);\r
414\r
415 //\r
416 // skip the directory traversing stuff...\r
417 //\r
418 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
419 continue;\r
420 }\r
421\r
422 if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item\r
423 && EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) // not an existing directory\r
424 ) {\r
425 if (StrStr(CleanFilePathStr, L":") == NULL) {\r
426 //\r
427 // simple copy of a single file\r
428 //\r
429 if (Cwd != NULL) {\r
430 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16)-1);\r
431 } else {\r
432 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
433 FreePool (CleanFilePathStr);\r
434 return (SHELL_INVALID_PARAMETER);\r
435 }\r
436 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
437 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
438 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
439 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
440 }\r
441 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
442 } else {\r
443 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1);\r
444 }\r
445 } else {\r
446 //\r
447 // we have multiple files or a directory in the DestDir\r
448 //\r
449 \r
450 //\r
451 // Check for leading slash\r
452 //\r
453 if (CleanFilePathStr[0] == L'\\') {\r
454 //\r
455 // Copy to the root of CWD\r
456 //\r
457 if (Cwd != NULL) {\r
458 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1);\r
459 } else {\r
460 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
461 FreePool(CleanFilePathStr);\r
462 return (SHELL_INVALID_PARAMETER);\r
463 }\r
464 while (PathRemoveLastItem(DestPath));\r
465 StrnCat(DestPath, CleanFilePathStr+1, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
466 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
467 } else if (StrStr(CleanFilePathStr, L":") == NULL) {\r
468 if (Cwd != NULL) {\r
469 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1);\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 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\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 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
481 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
482 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\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 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\r
487\r
488 } else {\r
489 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1);\r
490 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
491 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\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 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);\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)) == NULL\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
573EFIAPI\r
574ProcessValidateAndCopyFiles(\r
575 IN EFI_SHELL_FILE_INFO *FileList,\r
576 IN CONST CHAR16 *DestDir,\r
577 IN BOOLEAN SilentMode,\r
578 IN BOOLEAN RecursiveMode\r
579 )\r
580{\r
581 SHELL_STATUS ShellStatus;\r
582 EFI_SHELL_FILE_INFO *List;\r
583 EFI_FILE_INFO *FileInfo;\r
584 CHAR16 *FullName;\r
585\r
586 List = NULL;\r
587 FullName = NULL;\r
588 FileInfo = NULL;\r
589\r
590 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);\r
591 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {\r
592 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir); \r
593 ShellStatus = SHELL_INVALID_PARAMETER;\r
594 ShellCloseFileMetaArg(&List);\r
595 } else if (List != NULL) {\r
596 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);\r
597 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);\r
598 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);\r
599 ASSERT(FileInfo != NULL);\r
600 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);\r
601 ShellCloseFileMetaArg(&List);\r
602 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {\r
603 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);\r
604 } else {\r
605 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp"); \r
606 ShellStatus = SHELL_ACCESS_DENIED;\r
607 }\r
608 } else {\r
609 ShellCloseFileMetaArg(&List);\r
610 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);\r
611 }\r
612\r
613 SHELL_FREE_NON_NULL(FileInfo);\r
614 SHELL_FREE_NON_NULL(FullName);\r
615 return (ShellStatus);\r
616}\r
617\r
618STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
619 {L"-r", TypeFlag},\r
620 {L"-q", TypeFlag},\r
621 {NULL, TypeMax}\r
622 };\r
623\r
624/**\r
625 Function for 'cp' command.\r
626\r
627 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
628 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
629**/\r
630SHELL_STATUS\r
631EFIAPI\r
632ShellCommandRunCp (\r
633 IN EFI_HANDLE ImageHandle,\r
634 IN EFI_SYSTEM_TABLE *SystemTable\r
635 )\r
636{\r
637 EFI_STATUS Status;\r
638 LIST_ENTRY *Package;\r
639 CHAR16 *ProblemParam;\r
640 SHELL_STATUS ShellStatus;\r
641 UINTN ParamCount;\r
642 UINTN LoopCounter;\r
643 EFI_SHELL_FILE_INFO *FileList;\r
644 BOOLEAN SilentMode;\r
645 BOOLEAN RecursiveMode;\r
646 CONST CHAR16 *Cwd;\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 ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode);\r
716 }\r
717 }\r
718\r
719 break;\r
720 default:\r
721 //\r
722 // Make a big list of all the files...\r
723 //\r
724 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {\r
725 if (ShellGetExecutionBreakFlag()) {\r
726 break;\r
727 }\r
728 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
729 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {\r
730 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter)); \r
731 ShellStatus = SHELL_NOT_FOUND;\r
732 }\r
733 }\r
734 if (ShellStatus != SHELL_SUCCESS) {\r
735 Status = ShellCloseFileMetaArg(&FileList);\r
736 } else {\r
737 //\r
738 // now copy them all...\r
739 //\r
740 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
741 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);\r
742 Status = ShellCloseFileMetaArg(&FileList);\r
743 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
744 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT); \r
745 ShellStatus = SHELL_ACCESS_DENIED;\r
746 }\r
747 }\r
748 }\r
749 break;\r
750 } // switch on parameter count\r
751\r
752 if (FileList != NULL) {\r
753 ShellCloseFileMetaArg(&FileList);\r
754 }\r
755\r
756 //\r
757 // free the command line package\r
758 //\r
759 ShellCommandLineFreeVarList (Package);\r
760 }\r
761\r
762 if (ShellGetExecutionBreakFlag()) {\r
763 return (SHELL_ABORTED);\r
764 }\r
765\r
766 return (ShellStatus);\r
767}\r
768\r