]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
ShellPkg/Cp: Handle memory allocation failure
[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
c011b6c9 4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
0b34dc13 5 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
a405b86d 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
f06be00e 17#include <Guid/FileSystemInfo.h>\r
18#include <Guid/FileSystemVolumeLabelInfo.h>\r
a405b86d 19\r
b54fd049 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
a405b86d 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
bf6bbc21 56 @param[in] CmdName Source command name requesting single file copy\r
a405b86d 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
bf6bbc21
TS
66 IN BOOLEAN SilentMode,\r
67 IN CONST CHAR16 *CmdName\r
a405b86d 68 )\r
69{\r
f06be00e 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
a405b86d 85\r
86 ASSERT(Resp != NULL);\r
87\r
f06be00e 88 SourceHandle = NULL;\r
89 DestHandle = NULL;\r
90 Response = *Resp;\r
91 List = NULL;\r
92 DestVolumeInfo = NULL;\r
e755a4ca 93 ShellStatus = SHELL_SUCCESS;\r
a405b86d 94\r
433a21cb 95 ReadSize = PcdGet32(PcdShellFileOperationSize);\r
a405b86d 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
a405b86d 101 //\r
102 // if the destination file existed check response and possibly prompt user\r
103 //\r
ac8783c8 104 if (ShellFileExists(Dest) == EFI_SUCCESS) {\r
a405b86d 105 if (Response == NULL && !SilentMode) {\r
b54fd049 106 Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
a405b86d 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
e9723321 128 default:\r
129 return SHELL_ABORTED;\r
a405b86d 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
bf6bbc21 137 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest); \r
a405b86d 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
f06be00e 145 Size = 0;\r
a405b86d 146 StrnCatGrow(&TempName, &Size, Source, 0);\r
147 StrnCatGrow(&TempName, &Size, L"\\*", 0);\r
7dd05623 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
a405b86d 158 } else {\r
ac8783c8 159 Status = ShellDeleteFileByName(Dest);\r
a405b86d 160\r
ac8783c8
JC
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
bf6bbc21 166 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest); \r
ac8783c8
JC
167 return (SHELL_ACCESS_DENIED);\r
168 }\r
f06be00e 169\r
ac8783c8
JC
170 //\r
171 // open source file\r
172 //\r
2ce97925
OM
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
f06be00e 178\r
ac8783c8
JC
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
f06be00e 184\r
ac8783c8
JC
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
f06be00e 209 Status = DestVolumeFP->GetInfo(\r
210 DestVolumeFP,\r
211 &gEfiFileSystemInfoGuid,\r
212 &DestVolumeInfoSize,\r
213 DestVolumeInfo\r
214 );\r
ac8783c8 215 }\r
f06be00e 216\r
ac8783c8
JC
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
f06be00e 221 //\r
ac8783c8 222 //not enough space on destination directory to copy file\r
f06be00e 223 //\r
f06be00e 224 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
bf6bbc21 225 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName); \r
ac8783c8
JC
226 return(SHELL_VOLUME_FULL);\r
227 } else {\r
228 //\r
229 // copy data between files\r
230 //\r
231 Buffer = AllocateZeroPool(ReadSize);\r
0b34dc13
RN
232 if (Buffer == NULL) {\r
233 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, CmdName);\r
234 return SHELL_OUT_OF_RESOURCES;\r
235 }\r
ac8783c8
JC
236 while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {\r
237 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);\r
f3a14a0f
SQ
238 if (!EFI_ERROR(Status)) {\r
239 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);\r
240 if (EFI_ERROR(Status)) {\r
241 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
bf6bbc21 242 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest); \r
f3a14a0f
SQ
243 break;\r
244 }\r
245 } else {\r
246 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
bf6bbc21 247 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source); \r
f3a14a0f
SQ
248 break;\r
249 }\r
ac8783c8 250 }\r
a405b86d 251 }\r
ac8783c8
JC
252 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
253 }\r
f3a14a0f 254 \r
a405b86d 255 //\r
256 // close files\r
257 //\r
258 if (DestHandle != NULL) {\r
259 ShellCloseFile(&DestHandle);\r
260 DestHandle = NULL;\r
261 }\r
262 if (SourceHandle != NULL) {\r
263 ShellCloseFile(&SourceHandle);\r
264 SourceHandle = NULL;\r
265 }\r
266\r
267 //\r
268 // return\r
269 //\r
e755a4ca 270 return ShellStatus;\r
a405b86d 271}\r
272\r
273/**\r
274 function to take a list of files to copy and a destination location and do\r
275 the verification and copying of those files to that location. This function\r
276 will report any errors to the user and halt.\r
277\r
278 The key is to have this function called ONLY once. this allows for the parameter\r
279 verification to happen correctly.\r
280\r
b54fd049 281 @param[in] FileList A LIST_ENTRY* based list of files to move.\r
282 @param[in] DestDir The destination location.\r
283 @param[in] SilentMode TRUE to eliminate screen output.\r
284 @param[in] RecursiveMode TRUE to copy directories.\r
285 @param[in] Resp The response to the overwrite query (if always).\r
a405b86d 286\r
287 @retval SHELL_SUCCESS the files were all moved.\r
288 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
289 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
290 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
291 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
292**/\r
293SHELL_STATUS\r
294EFIAPI\r
295ValidateAndCopyFiles(\r
296 IN CONST EFI_SHELL_FILE_INFO *FileList,\r
297 IN CONST CHAR16 *DestDir,\r
298 IN BOOLEAN SilentMode,\r
299 IN BOOLEAN RecursiveMode,\r
300 IN VOID **Resp\r
301 )\r
302{\r
303 CHAR16 *HiiOutput;\r
304 CHAR16 *HiiResultOk;\r
305 CONST EFI_SHELL_FILE_INFO *Node;\r
306 SHELL_STATUS ShellStatus;\r
0960ba17 307 EFI_STATUS Status;\r
a405b86d 308 CHAR16 *DestPath;\r
309 VOID *Response;\r
e1044f80 310 UINTN PathSize;\r
a405b86d 311 CONST CHAR16 *Cwd;\r
a405b86d 312 UINTN NewSize;\r
0960ba17 313 CHAR16 *CleanFilePathStr;\r
a405b86d 314\r
315 if (Resp == NULL) {\r
316 Response = NULL;\r
317 } else {\r
318 Response = *Resp;\r
319 }\r
320\r
715096c2
QS
321 DestPath = NULL;\r
322 ShellStatus = SHELL_SUCCESS;\r
323 PathSize = 0;\r
324 Cwd = ShellGetCurrentDir(NULL);\r
325 CleanFilePathStr = NULL;\r
a405b86d 326\r
327 ASSERT(FileList != NULL);\r
328 ASSERT(DestDir != NULL);\r
329\r
0960ba17
QS
330 \r
331 Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr);\r
332 if (EFI_ERROR (Status)) {\r
333 if (Status == EFI_OUT_OF_RESOURCES) {\r
334 return SHELL_OUT_OF_RESOURCES;\r
335 } else {\r
336 return SHELL_INVALID_PARAMETER;\r
337 }\r
427d61ad
QS
338 }\r
339 \r
340 ASSERT (CleanFilePathStr != NULL);\r
0960ba17 341\r
a405b86d 342 //\r
343 // If we are trying to copy multiple files... make sure we got a directory for the target...\r
344 //\r
0960ba17 345 if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {\r
a405b86d 346 //\r
347 // Error for destination not a directory\r
348 //\r
099e8ff5 349 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 350 FreePool (CleanFilePathStr);\r
a405b86d 351 return (SHELL_INVALID_PARAMETER);\r
352 }\r
353 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
354 ; !IsNull(&FileList->Link, &Node->Link)\r
355 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
f06be00e 356 ){\r
a405b86d 357 //\r
358 // skip the directory traversing stuff...\r
359 //\r
360 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
361 continue;\r
362 }\r
363\r
0960ba17 364 NewSize = StrSize(CleanFilePathStr);\r
b54fd049 365 NewSize += StrSize(Node->FullName);\r
fbd2dfad 366 NewSize += (Cwd == NULL)? 0 : (StrSize(Cwd) + sizeof(CHAR16));\r
e1044f80
JC
367 if (NewSize > PathSize) {\r
368 PathSize = NewSize;\r
a405b86d 369 }\r
370\r
371 //\r
372 // Make sure got -r if required\r
373 //\r
374 if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) {\r
099e8ff5 375 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp"); \r
0960ba17 376 FreePool (CleanFilePathStr);\r
a405b86d 377 return (SHELL_INVALID_PARAMETER);\r
378 }\r
379\r
380 //\r
381 // make sure got dest as dir if needed\r
382 //\r
0960ba17 383 if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))) {\r
a405b86d 384 //\r
385 // Error for destination not a directory\r
386 //\r
099e8ff5 387 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 388 FreePool (CleanFilePathStr);\r
a405b86d 389 return (SHELL_INVALID_PARAMETER);\r
390 }\r
391 }\r
392\r
393 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);\r
394 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);\r
e1044f80 395 DestPath = AllocateZeroPool(PathSize);\r
a405b86d 396\r
3e082d58 397 if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) {\r
9ea69f8a 398 SHELL_FREE_NON_NULL(DestPath);\r
399 SHELL_FREE_NON_NULL(HiiOutput);\r
400 SHELL_FREE_NON_NULL(HiiResultOk);\r
0960ba17 401 FreePool (CleanFilePathStr);\r
9ea69f8a 402 return (SHELL_OUT_OF_RESOURCES);\r
403 }\r
404\r
a405b86d 405 //\r
406 // Go through the list of files to copy...\r
407 //\r
408 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
409 ; !IsNull(&FileList->Link, &Node->Link)\r
410 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
f06be00e 411 ){\r
a405b86d 412 if (ShellGetExecutionBreakFlag()) {\r
413 break;\r
414 }\r
415 ASSERT(Node->FileName != NULL);\r
416 ASSERT(Node->FullName != NULL);\r
417\r
418 //\r
419 // skip the directory traversing stuff...\r
420 //\r
421 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
422 continue;\r
423 }\r
424\r
425 if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item\r
0960ba17 426 && EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) // not an existing directory\r
f06be00e 427 ) {\r
0960ba17 428 if (StrStr(CleanFilePathStr, L":") == NULL) {\r
b54fd049 429 //\r
430 // simple copy of a single file\r
431 //\r
ed053afe 432 if (Cwd != NULL) {\r
e75390f0 433 StrCpyS(DestPath, PathSize / sizeof(CHAR16), Cwd);\r
fbd2dfad 434 StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");\r
ed053afe 435 } else {\r
099e8ff5 436 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 437 FreePool (CleanFilePathStr);\r
ed053afe
ED
438 return (SHELL_INVALID_PARAMETER);\r
439 }\r
0960ba17 440 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
e75390f0 441 StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");\r
0960ba17 442 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
b54fd049 443 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
444 }\r
e75390f0 445 StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
b54fd049 446 } else {\r
e75390f0 447 StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
a405b86d 448 }\r
a405b86d 449 } else {\r
450 //\r
451 // we have multiple files or a directory in the DestDir\r
452 //\r
1fc3749d 453 \r
454 //\r
455 // Check for leading slash\r
456 //\r
0960ba17 457 if (CleanFilePathStr[0] == L'\\') {\r
ed053afe
ED
458 //\r
459 // Copy to the root of CWD\r
460 //\r
461 if (Cwd != NULL) {\r
e75390f0 462 StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);\r
fbd2dfad 463 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
ed053afe 464 } else {\r
099e8ff5 465 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 466 FreePool(CleanFilePathStr);\r
ed053afe
ED
467 return (SHELL_INVALID_PARAMETER);\r
468 }\r
1fc3749d 469 while (PathRemoveLastItem(DestPath));\r
e75390f0
QS
470 StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr+1);\r
471 StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);\r
0960ba17 472 } else if (StrStr(CleanFilePathStr, L":") == NULL) {\r
ed053afe 473 if (Cwd != NULL) {\r
e75390f0 474 StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);\r
fbd2dfad 475 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
ed053afe 476 } else {\r
099e8ff5 477 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 478 FreePool(CleanFilePathStr);\r
ed053afe
ED
479 return (SHELL_INVALID_PARAMETER);\r
480 }\r
0960ba17 481 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
e75390f0 482 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
0960ba17 483 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
a405b86d 484 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
485 }\r
e75390f0 486 StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
0960ba17 487 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
e75390f0 488 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
0960ba17 489 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
a405b86d 490 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
491 }\r
e75390f0 492 StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);\r
a405b86d 493\r
494 } else {\r
e75390f0 495 StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
0960ba17 496 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
e75390f0 497 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
0960ba17
QS
498 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
499 ((CHAR16*)CleanFilePathStr)[StrLen(CleanFilePathStr)-1] = CHAR_NULL;\r
a405b86d 500 }\r
e75390f0 501 StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);\r
a405b86d 502 }\r
503 }\r
a6e84d95 504 \r
a405b86d 505 //\r
506 // Make sure the path exists\r
507 //\r
508 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {\r
099e8ff5 509 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath); \r
a405b86d 510 ShellStatus = SHELL_DEVICE_ERROR;\r
511 break;\r
512 }\r
513\r
514 if ( !EFI_ERROR(ShellIsDirectory(Node->FullName))\r
515 && !EFI_ERROR(ShellIsDirectory(DestPath))\r
516 && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL\r
f06be00e 517 ){\r
099e8ff5 518 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 519 ShellStatus = SHELL_INVALID_PARAMETER;\r
520 break;\r
521 }\r
522 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {\r
099e8ff5 523 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 524 ShellStatus = SHELL_INVALID_PARAMETER;\r
525 break;\r
526 }\r
527\r
5051c287 528 if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0)\r
a405b86d 529 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')\r
f06be00e 530 ) {\r
099e8ff5 531 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 532 ShellStatus = SHELL_INVALID_PARAMETER;\r
533 break;\r
534 }\r
535\r
ab94587a 536 PathCleanUpDirectories(DestPath);\r
a405b86d 537\r
a737ea73
JC
538 if (!SilentMode) {\r
539 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);\r
540 }\r
a405b86d 541\r
542 //\r
543 // copy single file...\r
544 //\r
bf6bbc21 545 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode, L"cp");\r
a405b86d 546 if (ShellStatus != SHELL_SUCCESS) {\r
547 break;\r
548 }\r
549 }\r
550 if (ShellStatus == SHELL_SUCCESS && Resp == NULL) {\r
551 ShellPrintEx(-1, -1, L"%s", HiiResultOk);\r
552 }\r
553\r
554 SHELL_FREE_NON_NULL(DestPath);\r
555 SHELL_FREE_NON_NULL(HiiOutput);\r
556 SHELL_FREE_NON_NULL(HiiResultOk);\r
a6e84d95 557 SHELL_FREE_NON_NULL(CleanFilePathStr);\r
590c3cb1 558 if (Resp == NULL) {\r
a405b86d 559 SHELL_FREE_NON_NULL(Response);\r
560 }\r
561\r
562 return (ShellStatus);\r
f06be00e 563\r
a405b86d 564}\r
565\r
b54fd049 566/**\r
567 Validate and if successful copy all the files from the list into \r
568 destination directory.\r
569\r
570 @param[in] FileList The list of files to copy.\r
571 @param[in] DestDir The directory to copy files to.\r
572 @param[in] SilentMode TRUE to eliminate screen output.\r
573 @param[in] RecursiveMode TRUE to copy directories.\r
574\r
575 @retval SHELL_INVALID_PARAMETER A parameter was invalid.\r
576 @retval SHELL_SUCCESS The operation was successful.\r
577**/\r
a405b86d 578SHELL_STATUS\r
579EFIAPI\r
580ProcessValidateAndCopyFiles(\r
581 IN EFI_SHELL_FILE_INFO *FileList,\r
582 IN CONST CHAR16 *DestDir,\r
583 IN BOOLEAN SilentMode,\r
584 IN BOOLEAN RecursiveMode\r
585 )\r
586{\r
587 SHELL_STATUS ShellStatus;\r
588 EFI_SHELL_FILE_INFO *List;\r
a405b86d 589 EFI_FILE_INFO *FileInfo;\r
ac8783c8 590 CHAR16 *FullName;\r
a405b86d 591\r
ac8783c8
JC
592 List = NULL;\r
593 FullName = NULL;\r
9f56625f 594 FileInfo = NULL;\r
a405b86d 595\r
e755a4ca 596 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);\r
a405b86d 597 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {\r
099e8ff5 598 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir); \r
a405b86d 599 ShellStatus = SHELL_INVALID_PARAMETER;\r
600 ShellCloseFileMetaArg(&List);\r
601 } else if (List != NULL) {\r
a405b86d 602 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);\r
603 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);\r
a405b86d 604 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);\r
605 ASSERT(FileInfo != NULL);\r
ac8783c8
JC
606 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);\r
607 ShellCloseFileMetaArg(&List);\r
a405b86d 608 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {\r
ac8783c8 609 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);\r
a405b86d 610 } else {\r
099e8ff5 611 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 612 ShellStatus = SHELL_ACCESS_DENIED;\r
613 }\r
a405b86d 614 } else {\r
ac8783c8 615 ShellCloseFileMetaArg(&List);\r
ed053afe 616 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);\r
a405b86d 617 }\r
618\r
ac8783c8
JC
619 SHELL_FREE_NON_NULL(FileInfo);\r
620 SHELL_FREE_NON_NULL(FullName);\r
a405b86d 621 return (ShellStatus);\r
622}\r
623\r
624STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
625 {L"-r", TypeFlag},\r
626 {L"-q", TypeFlag},\r
627 {NULL, TypeMax}\r
628 };\r
629\r
630/**\r
631 Function for 'cp' command.\r
632\r
633 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
634 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
635**/\r
636SHELL_STATUS\r
637EFIAPI\r
638ShellCommandRunCp (\r
639 IN EFI_HANDLE ImageHandle,\r
640 IN EFI_SYSTEM_TABLE *SystemTable\r
641 )\r
642{\r
643 EFI_STATUS Status;\r
644 LIST_ENTRY *Package;\r
645 CHAR16 *ProblemParam;\r
646 SHELL_STATUS ShellStatus;\r
647 UINTN ParamCount;\r
648 UINTN LoopCounter;\r
649 EFI_SHELL_FILE_INFO *FileList;\r
650 BOOLEAN SilentMode;\r
651 BOOLEAN RecursiveMode;\r
652 CONST CHAR16 *Cwd;\r
fbd2dfad 653 CHAR16 *FullCwd;\r
a405b86d 654\r
655 ProblemParam = NULL;\r
656 ShellStatus = SHELL_SUCCESS;\r
657 ParamCount = 0;\r
658 FileList = NULL;\r
659\r
660 //\r
661 // initialize the shell lib (we must be in non-auto-init...)\r
662 //\r
663 Status = ShellInitialize();\r
664 ASSERT_EFI_ERROR(Status);\r
665\r
666 Status = CommandInit();\r
667 ASSERT_EFI_ERROR(Status);\r
668\r
669 //\r
670 // parse the command line\r
671 //\r
672 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
673 if (EFI_ERROR(Status)) {\r
674 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
099e8ff5 675 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam); \r
a405b86d 676 FreePool(ProblemParam);\r
677 ShellStatus = SHELL_INVALID_PARAMETER;\r
678 } else {\r
679 ASSERT(FALSE);\r
680 }\r
681 } else {\r
682 //\r
683 // check for "-?"\r
684 //\r
685 if (ShellCommandLineGetFlag(Package, L"-?")) {\r
686 ASSERT(FALSE);\r
687 }\r
688\r
689 //\r
690 // Initialize SilentMode and RecursiveMode\r
691 //\r
692 if (gEfiShellProtocol->BatchIsActive()) {\r
693 SilentMode = TRUE;\r
694 } else {\r
695 SilentMode = ShellCommandLineGetFlag(Package, L"-q");\r
696 }\r
697 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");\r
698\r
699 switch (ParamCount = ShellCommandLineGetCount(Package)) {\r
700 case 0:\r
701 case 1:\r
702 //\r
703 // we have insufficient parameters\r
704 //\r
099e8ff5 705 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 706 ShellStatus = SHELL_INVALID_PARAMETER;\r
707 break;\r
708 case 2:\r
709 //\r
710 // must have valid CWD for single parameter...\r
711 //\r
712 Cwd = ShellGetCurrentDir(NULL);\r
713 if (Cwd == NULL){\r
099e8ff5 714 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 715 ShellStatus = SHELL_INVALID_PARAMETER;\r
716 } else {\r
717 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
718 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
099e8ff5 719 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1)); \r
a405b86d 720 ShellStatus = SHELL_NOT_FOUND;\r
721 } else {\r
fbd2dfad 722 FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16));\r
0b34dc13
RN
723 if (FullCwd == NULL) {\r
724 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cp");\r
725 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
726 } else {\r
727 StrCpyS (FullCwd, StrSize (Cwd) / sizeof (CHAR16) + 1, Cwd);\r
728 ShellStatus = ProcessValidateAndCopyFiles (FileList, FullCwd, SilentMode, RecursiveMode);\r
729 FreePool (FullCwd);\r
730 }\r
a405b86d 731 }\r
732 }\r
733\r
734 break;\r
735 default:\r
736 //\r
737 // Make a big list of all the files...\r
738 //\r
739 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {\r
740 if (ShellGetExecutionBreakFlag()) {\r
741 break;\r
742 }\r
743 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
744 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {\r
099e8ff5 745 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter)); \r
a405b86d 746 ShellStatus = SHELL_NOT_FOUND;\r
747 }\r
748 }\r
b2bf9735 749 if (ShellStatus != SHELL_SUCCESS) {\r
a405b86d 750 Status = ShellCloseFileMetaArg(&FileList);\r
b2bf9735 751 } else {\r
752 //\r
753 // now copy them all...\r
754 //\r
755 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
ab94587a 756 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);\r
b2bf9735 757 Status = ShellCloseFileMetaArg(&FileList);\r
758 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
099e8ff5 759 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT); \r
b2bf9735 760 ShellStatus = SHELL_ACCESS_DENIED;\r
761 }\r
a405b86d 762 }\r
763 }\r
a405b86d 764 break;\r
765 } // switch on parameter count\r
766\r
767 if (FileList != NULL) {\r
768 ShellCloseFileMetaArg(&FileList);\r
769 }\r
770\r
771 //\r
772 // free the command line package\r
773 //\r
774 ShellCommandLineFreeVarList (Package);\r
775 }\r
776\r
777 if (ShellGetExecutionBreakFlag()) {\r
778 return (SHELL_ABORTED);\r
779 }\r
780\r
781 return (ShellStatus);\r
782}\r
783\r