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