]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
ShellPkg: Follow spec to remove the last '\' char in return name of GetCurDir().
[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
e75390f0 5 Copyright (c) 2009 - 2015, 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
232 ASSERT(Buffer != NULL);\r
233 while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {\r
234 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);\r
f3a14a0f
SQ
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
bf6bbc21 239 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest); \r
f3a14a0f
SQ
240 break;\r
241 }\r
242 } else {\r
243 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
bf6bbc21 244 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source); \r
f3a14a0f
SQ
245 break;\r
246 }\r
ac8783c8 247 }\r
a405b86d 248 }\r
ac8783c8
JC
249 SHELL_FREE_NON_NULL(DestVolumeInfo);\r
250 }\r
f3a14a0f 251 \r
a405b86d 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
e755a4ca 267 return ShellStatus;\r
a405b86d 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
b54fd049 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
a405b86d 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
0960ba17 304 EFI_STATUS Status;\r
a405b86d 305 CHAR16 *DestPath;\r
306 VOID *Response;\r
e1044f80 307 UINTN PathSize;\r
a405b86d 308 CONST CHAR16 *Cwd;\r
a405b86d 309 UINTN NewSize;\r
0960ba17 310 CHAR16 *CleanFilePathStr;\r
a405b86d 311\r
312 if (Resp == NULL) {\r
313 Response = NULL;\r
314 } else {\r
315 Response = *Resp;\r
316 }\r
317\r
715096c2
QS
318 DestPath = NULL;\r
319 ShellStatus = SHELL_SUCCESS;\r
320 PathSize = 0;\r
321 Cwd = ShellGetCurrentDir(NULL);\r
322 CleanFilePathStr = NULL;\r
a405b86d 323\r
324 ASSERT(FileList != NULL);\r
325 ASSERT(DestDir != NULL);\r
326\r
0960ba17
QS
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
427d61ad
QS
335 }\r
336 \r
337 ASSERT (CleanFilePathStr != NULL);\r
0960ba17 338\r
a405b86d 339 //\r
340 // If we are trying to copy multiple files... make sure we got a directory for the target...\r
341 //\r
0960ba17 342 if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {\r
a405b86d 343 //\r
344 // Error for destination not a directory\r
345 //\r
099e8ff5 346 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 347 FreePool (CleanFilePathStr);\r
a405b86d 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
f06be00e 353 ){\r
a405b86d 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
0960ba17 361 NewSize = StrSize(CleanFilePathStr);\r
b54fd049 362 NewSize += StrSize(Node->FullName);\r
fbd2dfad 363 NewSize += (Cwd == NULL)? 0 : (StrSize(Cwd) + sizeof(CHAR16));\r
e1044f80
JC
364 if (NewSize > PathSize) {\r
365 PathSize = NewSize;\r
a405b86d 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
099e8ff5 372 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp"); \r
0960ba17 373 FreePool (CleanFilePathStr);\r
a405b86d 374 return (SHELL_INVALID_PARAMETER);\r
375 }\r
376\r
377 //\r
378 // make sure got dest as dir if needed\r
379 //\r
0960ba17 380 if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))) {\r
a405b86d 381 //\r
382 // Error for destination not a directory\r
383 //\r
099e8ff5 384 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 385 FreePool (CleanFilePathStr);\r
a405b86d 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
e1044f80 392 DestPath = AllocateZeroPool(PathSize);\r
a405b86d 393\r
3e082d58 394 if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) {\r
9ea69f8a 395 SHELL_FREE_NON_NULL(DestPath);\r
396 SHELL_FREE_NON_NULL(HiiOutput);\r
397 SHELL_FREE_NON_NULL(HiiResultOk);\r
0960ba17 398 FreePool (CleanFilePathStr);\r
9ea69f8a 399 return (SHELL_OUT_OF_RESOURCES);\r
400 }\r
401\r
a405b86d 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
f06be00e 408 ){\r
a405b86d 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
0960ba17 423 && EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) // not an existing directory\r
f06be00e 424 ) {\r
0960ba17 425 if (StrStr(CleanFilePathStr, L":") == NULL) {\r
b54fd049 426 //\r
427 // simple copy of a single file\r
428 //\r
ed053afe 429 if (Cwd != NULL) {\r
e75390f0 430 StrCpyS(DestPath, PathSize / sizeof(CHAR16), Cwd);\r
fbd2dfad 431 StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");\r
ed053afe 432 } else {\r
099e8ff5 433 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 434 FreePool (CleanFilePathStr);\r
ed053afe
ED
435 return (SHELL_INVALID_PARAMETER);\r
436 }\r
0960ba17 437 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
e75390f0 438 StrCatS(DestPath, PathSize / sizeof(CHAR16), L"\\");\r
0960ba17 439 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
b54fd049 440 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
441 }\r
e75390f0 442 StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
b54fd049 443 } else {\r
e75390f0 444 StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
a405b86d 445 }\r
a405b86d 446 } else {\r
447 //\r
448 // we have multiple files or a directory in the DestDir\r
449 //\r
1fc3749d 450 \r
451 //\r
452 // Check for leading slash\r
453 //\r
0960ba17 454 if (CleanFilePathStr[0] == L'\\') {\r
ed053afe
ED
455 //\r
456 // Copy to the root of CWD\r
457 //\r
458 if (Cwd != NULL) {\r
e75390f0 459 StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);\r
fbd2dfad 460 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
ed053afe 461 } else {\r
099e8ff5 462 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 463 FreePool(CleanFilePathStr);\r
ed053afe
ED
464 return (SHELL_INVALID_PARAMETER);\r
465 }\r
1fc3749d 466 while (PathRemoveLastItem(DestPath));\r
e75390f0
QS
467 StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr+1);\r
468 StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);\r
0960ba17 469 } else if (StrStr(CleanFilePathStr, L":") == NULL) {\r
ed053afe 470 if (Cwd != NULL) {\r
e75390f0 471 StrCpyS(DestPath, PathSize/sizeof(CHAR16), Cwd);\r
fbd2dfad 472 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
ed053afe 473 } else {\r
099e8ff5 474 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); \r
0960ba17 475 FreePool(CleanFilePathStr);\r
ed053afe
ED
476 return (SHELL_INVALID_PARAMETER);\r
477 }\r
0960ba17 478 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {\r
e75390f0 479 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
0960ba17 480 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {\r
a405b86d 481 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
482 }\r
e75390f0 483 StrCatS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
0960ba17 484 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
e75390f0 485 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
0960ba17 486 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
a405b86d 487 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
488 }\r
e75390f0 489 StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);\r
a405b86d 490\r
491 } else {\r
e75390f0 492 StrCpyS(DestPath, PathSize/sizeof(CHAR16), CleanFilePathStr);\r
0960ba17 493 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {\r
e75390f0 494 StrCatS(DestPath, PathSize/sizeof(CHAR16), L"\\");\r
0960ba17
QS
495 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {\r
496 ((CHAR16*)CleanFilePathStr)[StrLen(CleanFilePathStr)-1] = CHAR_NULL;\r
a405b86d 497 }\r
e75390f0 498 StrCatS(DestPath, PathSize/sizeof(CHAR16), Node->FileName);\r
a405b86d 499 }\r
500 }\r
a6e84d95 501 \r
a405b86d 502 //\r
503 // Make sure the path exists\r
504 //\r
505 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {\r
099e8ff5 506 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath); \r
a405b86d 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)) == NULL\r
f06be00e 514 ){\r
099e8ff5 515 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 516 ShellStatus = SHELL_INVALID_PARAMETER;\r
517 break;\r
518 }\r
519 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {\r
099e8ff5 520 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 521 ShellStatus = SHELL_INVALID_PARAMETER;\r
522 break;\r
523 }\r
524\r
5051c287 525 if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0)\r
a405b86d 526 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')\r
f06be00e 527 ) {\r
099e8ff5 528 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 529 ShellStatus = SHELL_INVALID_PARAMETER;\r
530 break;\r
531 }\r
532\r
ab94587a 533 PathCleanUpDirectories(DestPath);\r
a405b86d 534\r
a737ea73
JC
535 if (!SilentMode) {\r
536 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);\r
537 }\r
a405b86d 538\r
539 //\r
540 // copy single file...\r
541 //\r
bf6bbc21 542 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode, L"cp");\r
a405b86d 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
a6e84d95 554 SHELL_FREE_NON_NULL(CleanFilePathStr);\r
590c3cb1 555 if (Resp == NULL) {\r
a405b86d 556 SHELL_FREE_NON_NULL(Response);\r
557 }\r
558\r
559 return (ShellStatus);\r
f06be00e 560\r
a405b86d 561}\r
562\r
b54fd049 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
a405b86d 575SHELL_STATUS\r
576EFIAPI\r
577ProcessValidateAndCopyFiles(\r
578 IN EFI_SHELL_FILE_INFO *FileList,\r
579 IN CONST CHAR16 *DestDir,\r
580 IN BOOLEAN SilentMode,\r
581 IN BOOLEAN RecursiveMode\r
582 )\r
583{\r
584 SHELL_STATUS ShellStatus;\r
585 EFI_SHELL_FILE_INFO *List;\r
a405b86d 586 EFI_FILE_INFO *FileInfo;\r
ac8783c8 587 CHAR16 *FullName;\r
a405b86d 588\r
ac8783c8
JC
589 List = NULL;\r
590 FullName = NULL;\r
9f56625f 591 FileInfo = NULL;\r
a405b86d 592\r
e755a4ca 593 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);\r
a405b86d 594 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {\r
099e8ff5 595 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir); \r
a405b86d 596 ShellStatus = SHELL_INVALID_PARAMETER;\r
597 ShellCloseFileMetaArg(&List);\r
598 } else if (List != NULL) {\r
a405b86d 599 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);\r
600 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);\r
a405b86d 601 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);\r
602 ASSERT(FileInfo != NULL);\r
ac8783c8
JC
603 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);\r
604 ShellCloseFileMetaArg(&List);\r
a405b86d 605 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {\r
ac8783c8 606 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);\r
a405b86d 607 } else {\r
099e8ff5 608 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 609 ShellStatus = SHELL_ACCESS_DENIED;\r
610 }\r
a405b86d 611 } else {\r
ac8783c8 612 ShellCloseFileMetaArg(&List);\r
ed053afe 613 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);\r
a405b86d 614 }\r
615\r
ac8783c8
JC
616 SHELL_FREE_NON_NULL(FileInfo);\r
617 SHELL_FREE_NON_NULL(FullName);\r
a405b86d 618 return (ShellStatus);\r
619}\r
620\r
621STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
622 {L"-r", TypeFlag},\r
623 {L"-q", TypeFlag},\r
624 {NULL, TypeMax}\r
625 };\r
626\r
627/**\r
628 Function for 'cp' command.\r
629\r
630 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
631 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
632**/\r
633SHELL_STATUS\r
634EFIAPI\r
635ShellCommandRunCp (\r
636 IN EFI_HANDLE ImageHandle,\r
637 IN EFI_SYSTEM_TABLE *SystemTable\r
638 )\r
639{\r
640 EFI_STATUS Status;\r
641 LIST_ENTRY *Package;\r
642 CHAR16 *ProblemParam;\r
643 SHELL_STATUS ShellStatus;\r
644 UINTN ParamCount;\r
645 UINTN LoopCounter;\r
646 EFI_SHELL_FILE_INFO *FileList;\r
647 BOOLEAN SilentMode;\r
648 BOOLEAN RecursiveMode;\r
649 CONST CHAR16 *Cwd;\r
fbd2dfad 650 CHAR16 *FullCwd;\r
a405b86d 651\r
652 ProblemParam = NULL;\r
653 ShellStatus = SHELL_SUCCESS;\r
654 ParamCount = 0;\r
655 FileList = NULL;\r
656\r
657 //\r
658 // initialize the shell lib (we must be in non-auto-init...)\r
659 //\r
660 Status = ShellInitialize();\r
661 ASSERT_EFI_ERROR(Status);\r
662\r
663 Status = CommandInit();\r
664 ASSERT_EFI_ERROR(Status);\r
665\r
666 //\r
667 // parse the command line\r
668 //\r
669 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
670 if (EFI_ERROR(Status)) {\r
671 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
099e8ff5 672 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam); \r
a405b86d 673 FreePool(ProblemParam);\r
674 ShellStatus = SHELL_INVALID_PARAMETER;\r
675 } else {\r
676 ASSERT(FALSE);\r
677 }\r
678 } else {\r
679 //\r
680 // check for "-?"\r
681 //\r
682 if (ShellCommandLineGetFlag(Package, L"-?")) {\r
683 ASSERT(FALSE);\r
684 }\r
685\r
686 //\r
687 // Initialize SilentMode and RecursiveMode\r
688 //\r
689 if (gEfiShellProtocol->BatchIsActive()) {\r
690 SilentMode = TRUE;\r
691 } else {\r
692 SilentMode = ShellCommandLineGetFlag(Package, L"-q");\r
693 }\r
694 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");\r
695\r
696 switch (ParamCount = ShellCommandLineGetCount(Package)) {\r
697 case 0:\r
698 case 1:\r
699 //\r
700 // we have insufficient parameters\r
701 //\r
099e8ff5 702 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 703 ShellStatus = SHELL_INVALID_PARAMETER;\r
704 break;\r
705 case 2:\r
706 //\r
707 // must have valid CWD for single parameter...\r
708 //\r
709 Cwd = ShellGetCurrentDir(NULL);\r
710 if (Cwd == NULL){\r
099e8ff5 711 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp"); \r
a405b86d 712 ShellStatus = SHELL_INVALID_PARAMETER;\r
713 } else {\r
714 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
715 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
099e8ff5 716 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1)); \r
a405b86d 717 ShellStatus = SHELL_NOT_FOUND;\r
718 } else {\r
fbd2dfad
QS
719 FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16));\r
720 ASSERT (FullCwd != NULL);\r
721 StrCpyS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, Cwd);\r
722 ShellStatus = ProcessValidateAndCopyFiles(FileList, FullCwd, SilentMode, RecursiveMode);\r
723 FreePool(FullCwd);\r
a405b86d 724 }\r
725 }\r
726\r
727 break;\r
728 default:\r
729 //\r
730 // Make a big list of all the files...\r
731 //\r
732 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {\r
733 if (ShellGetExecutionBreakFlag()) {\r
734 break;\r
735 }\r
736 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
737 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {\r
099e8ff5 738 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter)); \r
a405b86d 739 ShellStatus = SHELL_NOT_FOUND;\r
740 }\r
741 }\r
b2bf9735 742 if (ShellStatus != SHELL_SUCCESS) {\r
a405b86d 743 Status = ShellCloseFileMetaArg(&FileList);\r
b2bf9735 744 } else {\r
745 //\r
746 // now copy them all...\r
747 //\r
748 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
ab94587a 749 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);\r
b2bf9735 750 Status = ShellCloseFileMetaArg(&FileList);\r
751 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
099e8ff5 752 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT); \r
b2bf9735 753 ShellStatus = SHELL_ACCESS_DENIED;\r
754 }\r
a405b86d 755 }\r
756 }\r
a405b86d 757 break;\r
758 } // switch on parameter count\r
759\r
760 if (FileList != NULL) {\r
761 ShellCloseFileMetaArg(&FileList);\r
762 }\r
763\r
764 //\r
765 // free the command line package\r
766 //\r
767 ShellCommandLineFreeVarList (Package);\r
768 }\r
769\r
770 if (ShellGetExecutionBreakFlag()) {\r
771 return (SHELL_ABORTED);\r
772 }\r
773\r
774 return (ShellStatus);\r
775}\r
776\r