]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Cp.c
1 /** @file
2 Main file for cp shell level 2 function.
3
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "UefiShellLevel2CommandsLib.h"
11 #include <Guid/FileSystemInfo.h>
12 #include <Guid/FileSystemVolumeLabelInfo.h>
13
14 /**
15 Function to take a list of files to copy and a destination location and do
16 the verification and copying of those files to that location. This function
17 will report any errors to the user and halt.
18
19 @param[in] FileList A LIST_ENTRY* based list of files to move.
20 @param[in] DestDir The destination location.
21 @param[in] SilentMode TRUE to eliminate screen output.
22 @param[in] RecursiveMode TRUE to copy directories.
23 @param[in] Resp The response to the overwrite query (if always).
24
25 @retval SHELL_SUCCESS the files were all moved.
26 @retval SHELL_INVALID_PARAMETER a parameter was invalid
27 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
28 @retval SHELL_WRITE_PROTECTED the destination was write protected
29 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
30 **/
31 SHELL_STATUS
32 ValidateAndCopyFiles (
33 IN CONST EFI_SHELL_FILE_INFO *FileList,
34 IN CONST CHAR16 *DestDir,
35 IN BOOLEAN SilentMode,
36 IN BOOLEAN RecursiveMode,
37 IN VOID **Resp
38 );
39
40 /**
41 Function to Copy one file to another location
42
43 If the destination exists the user will be prompted and the result put into *resp
44
45 @param[in] Source pointer to source file name
46 @param[in] Dest pointer to destination file name
47 @param[out] Resp pointer to response from question. Pass back on looped calling
48 @param[in] SilentMode whether to run in quiet mode or not
49 @param[in] CmdName Source command name requesting single file copy
50
51 @retval SHELL_SUCCESS The source file was copied to the destination
52 **/
53 SHELL_STATUS
54 CopySingleFile (
55 IN CONST CHAR16 *Source,
56 IN CONST CHAR16 *Dest,
57 OUT VOID **Resp,
58 IN BOOLEAN SilentMode,
59 IN CONST CHAR16 *CmdName
60 )
61 {
62 VOID *Response;
63 UINTN ReadSize;
64 SHELL_FILE_HANDLE SourceHandle;
65 SHELL_FILE_HANDLE DestHandle;
66 EFI_STATUS Status;
67 VOID *Buffer;
68 CHAR16 *TempName;
69 UINTN Size;
70 EFI_SHELL_FILE_INFO *List;
71 SHELL_STATUS ShellStatus;
72 UINT64 SourceFileSize;
73 UINT64 DestFileSize;
74 EFI_FILE_PROTOCOL *DestVolumeFP;
75 EFI_FILE_SYSTEM_INFO *DestVolumeInfo;
76 UINTN DestVolumeInfoSize;
77
78 ASSERT (Resp != NULL);
79
80 SourceHandle = NULL;
81 DestHandle = NULL;
82 Response = *Resp;
83 List = NULL;
84 DestVolumeInfo = NULL;
85 ShellStatus = SHELL_SUCCESS;
86
87 ReadSize = PcdGet32 (PcdShellFileOperationSize);
88 // Why bother copying a file to itself
89 if (StrCmp (Source, Dest) == 0) {
90 return (SHELL_SUCCESS);
91 }
92
93 //
94 // if the destination file existed check response and possibly prompt user
95 //
96 if (ShellFileExists (Dest) == EFI_SUCCESS) {
97 if ((Response == NULL) && !SilentMode) {
98 Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
99 }
100
101 //
102 // possibly return based on response
103 //
104 if (!SilentMode) {
105 if (Response == NULL) {
106 return SHELL_ABORTED;
107 }
108
109 switch (*(SHELL_PROMPT_RESPONSE *)Response) {
110 case ShellPromptResponseNo:
111 //
112 // return success here so we dont stop the process
113 //
114 return (SHELL_SUCCESS);
115 case ShellPromptResponseCancel:
116 *Resp = Response;
117 //
118 // indicate to stop everything
119 //
120 return (SHELL_ABORTED);
121 case ShellPromptResponseAll:
122 *Resp = Response;
123 case ShellPromptResponseYes:
124 break;
125 default:
126 return SHELL_ABORTED;
127 }
128 }
129 }
130
131 if (ShellIsDirectory (Source) == EFI_SUCCESS) {
132 Status = ShellCreateDirectory (Dest, &DestHandle);
133 if (EFI_ERROR (Status)) {
134 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
135 return (SHELL_ACCESS_DENIED);
136 }
137
138 //
139 // Now copy all the files under the directory...
140 //
141 TempName = NULL;
142 Size = 0;
143 StrnCatGrow (&TempName, &Size, Source, 0);
144 StrnCatGrow (&TempName, &Size, L"\\*", 0);
145 if (TempName != NULL) {
146 ShellOpenFileMetaArg ((CHAR16 *)TempName, EFI_FILE_MODE_READ, &List);
147 *TempName = CHAR_NULL;
148 StrnCatGrow (&TempName, &Size, Dest, 0);
149 StrnCatGrow (&TempName, &Size, L"\\", 0);
150 ShellStatus = ValidateAndCopyFiles (List, TempName, SilentMode, TRUE, Resp);
151 ShellCloseFileMetaArg (&List);
152 SHELL_FREE_NON_NULL (TempName);
153 Size = 0;
154 }
155 } else {
156 Status = ShellDeleteFileByName (Dest);
157
158 //
159 // open file with create enabled
160 //
161 Status = ShellOpenFileByName (Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
162 if (EFI_ERROR (Status)) {
163 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
164 return (SHELL_ACCESS_DENIED);
165 }
166
167 //
168 // open source file
169 //
170 Status = ShellOpenFileByName (Source, &SourceHandle, EFI_FILE_MODE_READ, 0);
171 if (EFI_ERROR (Status)) {
172 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source);
173 return (SHELL_ACCESS_DENIED);
174 }
175
176 //
177 // get file size of source file and freespace available on destination volume
178 //
179 ShellGetFileSize (SourceHandle, &SourceFileSize);
180 ShellGetFileSize (DestHandle, &DestFileSize);
181
182 //
183 // if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space
184 //
185 if (DestFileSize < SourceFileSize) {
186 SourceFileSize -= DestFileSize;
187 } else {
188 SourceFileSize = 0;
189 }
190
191 //
192 // get the system volume info to check the free space
193 //
194 DestVolumeFP = ConvertShellHandleToEfiFileProtocol (DestHandle);
195 DestVolumeInfo = NULL;
196 DestVolumeInfoSize = 0;
197 Status = DestVolumeFP->GetInfo (
198 DestVolumeFP,
199 &gEfiFileSystemInfoGuid,
200 &DestVolumeInfoSize,
201 DestVolumeInfo
202 );
203
204 if (Status == EFI_BUFFER_TOO_SMALL) {
205 DestVolumeInfo = AllocateZeroPool (DestVolumeInfoSize);
206 Status = DestVolumeFP->GetInfo (
207 DestVolumeFP,
208 &gEfiFileSystemInfoGuid,
209 &DestVolumeInfoSize,
210 DestVolumeInfo
211 );
212 }
213
214 //
215 // check if enough space available on destination drive to complete copy
216 //
217 if ((DestVolumeInfo != NULL) && (DestVolumeInfo->FreeSpace < SourceFileSize)) {
218 //
219 // not enough space on destination directory to copy file
220 //
221 SHELL_FREE_NON_NULL (DestVolumeInfo);
222 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName);
223 return (SHELL_VOLUME_FULL);
224 } else {
225 //
226 // copy data between files
227 //
228 Buffer = AllocateZeroPool (ReadSize);
229 if (Buffer == NULL) {
230 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, CmdName);
231 return SHELL_OUT_OF_RESOURCES;
232 }
233
234 while (ReadSize == PcdGet32 (PcdShellFileOperationSize) && !EFI_ERROR (Status)) {
235 Status = ShellReadFile (SourceHandle, &ReadSize, Buffer);
236 if (!EFI_ERROR (Status)) {
237 Status = ShellWriteFile (DestHandle, &ReadSize, Buffer);
238 if (EFI_ERROR (Status)) {
239 ShellStatus = (SHELL_STATUS)(Status & (~MAX_BIT));
240 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest);
241 break;
242 }
243 } else {
244 ShellStatus = (SHELL_STATUS)(Status & (~MAX_BIT));
245 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source);
246 break;
247 }
248 }
249 }
250
251 SHELL_FREE_NON_NULL (DestVolumeInfo);
252 }
253
254 //
255 // close files
256 //
257 if (DestHandle != NULL) {
258 ShellCloseFile (&DestHandle);
259 DestHandle = NULL;
260 }
261
262 if (SourceHandle != NULL) {
263 ShellCloseFile (&SourceHandle);
264 SourceHandle = NULL;
265 }
266
267 //
268 // return
269 //
270 return ShellStatus;
271 }
272
273 /**
274 function to take a list of files to copy and a destination location and do
275 the verification and copying of those files to that location. This function
276 will report any errors to the user and halt.
277
278 The key is to have this function called ONLY once. this allows for the parameter
279 verification to happen correctly.
280
281 @param[in] FileList A LIST_ENTRY* based list of files to move.
282 @param[in] DestDir The destination location.
283 @param[in] SilentMode TRUE to eliminate screen output.
284 @param[in] RecursiveMode TRUE to copy directories.
285 @param[in] Resp The response to the overwrite query (if always).
286
287 @retval SHELL_SUCCESS the files were all moved.
288 @retval SHELL_INVALID_PARAMETER a parameter was invalid
289 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
290 @retval SHELL_WRITE_PROTECTED the destination was write protected
291 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
292 **/
293 SHELL_STATUS
294 ValidateAndCopyFiles (
295 IN CONST EFI_SHELL_FILE_INFO *FileList,
296 IN CONST CHAR16 *DestDir,
297 IN BOOLEAN SilentMode,
298 IN BOOLEAN RecursiveMode,
299 IN VOID **Resp
300 )
301 {
302 CHAR16 *HiiOutput;
303 CHAR16 *HiiResultOk;
304 CONST EFI_SHELL_FILE_INFO *Node;
305 SHELL_STATUS ShellStatus;
306 EFI_STATUS Status;
307 CHAR16 *DestPath;
308 VOID *Response;
309 UINTN PathSize;
310 CONST CHAR16 *Cwd;
311 UINTN NewSize;
312 CHAR16 *CleanFilePathStr;
313
314 if (Resp == NULL) {
315 Response = NULL;
316 } else {
317 Response = *Resp;
318 }
319
320 DestPath = NULL;
321 ShellStatus = SHELL_SUCCESS;
322 PathSize = 0;
323 Cwd = ShellGetCurrentDir (NULL);
324 CleanFilePathStr = NULL;
325
326 ASSERT (FileList != NULL);
327 ASSERT (DestDir != NULL);
328
329 Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr);
330 if (EFI_ERROR (Status)) {
331 if (Status == EFI_OUT_OF_RESOURCES) {
332 return SHELL_OUT_OF_RESOURCES;
333 } else {
334 return SHELL_INVALID_PARAMETER;
335 }
336 }
337
338 ASSERT (CleanFilePathStr != NULL);
339
340 //
341 // If we are trying to copy multiple files... make sure we got a directory for the target...
342 //
343 if (EFI_ERROR (ShellIsDirectory (CleanFilePathStr)) && (FileList->Link.ForwardLink != FileList->Link.BackLink)) {
344 //
345 // Error for destination not a directory
346 //
347 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
348 FreePool (CleanFilePathStr);
349 return (SHELL_INVALID_PARAMETER);
350 }
351
352 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link)
353 ; !IsNull (&FileList->Link, &Node->Link)
354 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &Node->Link)
355 )
356 {
357 //
358 // skip the directory traversing stuff...
359 //
360 if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
361 continue;
362 }
363
364 NewSize = StrSize (CleanFilePathStr);
365 NewSize += StrSize (Node->FullName);
366 NewSize += (Cwd == NULL) ? 0 : (StrSize (Cwd) + sizeof (CHAR16));
367 if (NewSize > PathSize) {
368 PathSize = NewSize;
369 }
370
371 //
372 // Make sure got -r if required
373 //
374 if (!RecursiveMode && !EFI_ERROR (ShellIsDirectory (Node->FullName))) {
375 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp");
376 FreePool (CleanFilePathStr);
377 return (SHELL_INVALID_PARAMETER);
378 }
379
380 //
381 // make sure got dest as dir if needed
382 //
383 if (!EFI_ERROR (ShellIsDirectory (Node->FullName)) && EFI_ERROR (ShellIsDirectory (CleanFilePathStr))) {
384 //
385 // Error for destination not a directory
386 //
387 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
388 FreePool (CleanFilePathStr);
389 return (SHELL_INVALID_PARAMETER);
390 }
391 }
392
393 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);
394 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
395 DestPath = AllocateZeroPool (PathSize);
396
397 if ((DestPath == NULL) || (HiiOutput == NULL) || (HiiResultOk == NULL)) {
398 SHELL_FREE_NON_NULL (DestPath);
399 SHELL_FREE_NON_NULL (HiiOutput);
400 SHELL_FREE_NON_NULL (HiiResultOk);
401 FreePool (CleanFilePathStr);
402 return (SHELL_OUT_OF_RESOURCES);
403 }
404
405 //
406 // Go through the list of files to copy...
407 //
408 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link)
409 ; !IsNull (&FileList->Link, &Node->Link)
410 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &Node->Link)
411 )
412 {
413 if (ShellGetExecutionBreakFlag ()) {
414 break;
415 }
416
417 ASSERT (Node->FileName != NULL);
418 ASSERT (Node->FullName != NULL);
419
420 //
421 // skip the directory traversing stuff...
422 //
423 if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
424 continue;
425 }
426
427 if ( (FileList->Link.ForwardLink == FileList->Link.BackLink) // 1 item
428 && EFI_ERROR (ShellIsDirectory (CleanFilePathStr)) // not an existing directory
429 )
430 {
431 if (StrStr (CleanFilePathStr, L":") == NULL) {
432 //
433 // simple copy of a single file
434 //
435 if (Cwd != NULL) {
436 StrCpyS (DestPath, PathSize / sizeof (CHAR16), Cwd);
437 StrCatS (DestPath, PathSize / sizeof (CHAR16), L"\\");
438 } else {
439 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
440 FreePool (CleanFilePathStr);
441 return (SHELL_INVALID_PARAMETER);
442 }
443
444 if ((DestPath[StrLen (DestPath)-1] != L'\\') && (CleanFilePathStr[0] != L'\\')) {
445 StrCatS (DestPath, PathSize / sizeof (CHAR16), L"\\");
446 } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (CleanFilePathStr[0] == L'\\')) {
447 ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
448 }
449
450 StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
451 } else {
452 StrCpyS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
453 }
454 } else {
455 //
456 // we have multiple files or a directory in the DestDir
457 //
458
459 //
460 // Check for leading slash
461 //
462 if (CleanFilePathStr[0] == L'\\') {
463 //
464 // Copy to the root of CWD
465 //
466 if (Cwd != NULL) {
467 StrCpyS (DestPath, PathSize/sizeof (CHAR16), Cwd);
468 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
469 } else {
470 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
471 FreePool (CleanFilePathStr);
472 return (SHELL_INVALID_PARAMETER);
473 }
474
475 while (PathRemoveLastItem (DestPath)) {
476 }
477
478 StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr+1);
479 StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
480 } else if (StrStr (CleanFilePathStr, L":") == NULL) {
481 if (Cwd != NULL) {
482 StrCpyS (DestPath, PathSize/sizeof (CHAR16), Cwd);
483 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
484 } else {
485 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
486 FreePool (CleanFilePathStr);
487 return (SHELL_INVALID_PARAMETER);
488 }
489
490 if ((DestPath[StrLen (DestPath)-1] != L'\\') && (CleanFilePathStr[0] != L'\\')) {
491 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
492 } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (CleanFilePathStr[0] == L'\\')) {
493 ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
494 }
495
496 StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
497 if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] != L'\\') && (Node->FileName[0] != L'\\')) {
498 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
499 } else if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] == L'\\') && (Node->FileName[0] == L'\\')) {
500 ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
501 }
502
503 StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
504 } else {
505 StrCpyS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
506 if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] != L'\\') && (Node->FileName[0] != L'\\')) {
507 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
508 } else if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] == L'\\') && (Node->FileName[0] == L'\\')) {
509 ((CHAR16 *)CleanFilePathStr)[StrLen (CleanFilePathStr)-1] = CHAR_NULL;
510 }
511
512 StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
513 }
514 }
515
516 //
517 // Make sure the path exists
518 //
519 if (EFI_ERROR (VerifyIntermediateDirectories (DestPath))) {
520 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath);
521 ShellStatus = SHELL_DEVICE_ERROR;
522 break;
523 }
524
525 if ( !EFI_ERROR (ShellIsDirectory (Node->FullName))
526 && !EFI_ERROR (ShellIsDirectory (DestPath))
527 && (StrniCmp (Node->FullName, DestPath, StrLen (DestPath)) == 0)
528 )
529 {
530 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp");
531 ShellStatus = SHELL_INVALID_PARAMETER;
532 break;
533 }
534
535 if (StringNoCaseCompare (&Node->FullName, &DestPath) == 0) {
536 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
537 ShellStatus = SHELL_INVALID_PARAMETER;
538 break;
539 }
540
541 if ( (StrniCmp (Node->FullName, DestPath, StrLen (Node->FullName)) == 0)
542 && ((DestPath[StrLen (Node->FullName)] == CHAR_NULL) || (DestPath[StrLen (Node->FullName)] == L'\\'))
543 )
544 {
545 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
546 ShellStatus = SHELL_INVALID_PARAMETER;
547 break;
548 }
549
550 PathCleanUpDirectories (DestPath);
551
552 if (!SilentMode) {
553 ShellPrintEx (-1, -1, HiiOutput, Node->FullName, DestPath);
554 }
555
556 //
557 // copy single file...
558 //
559 ShellStatus = CopySingleFile (Node->FullName, DestPath, &Response, SilentMode, L"cp");
560 if (ShellStatus != SHELL_SUCCESS) {
561 break;
562 }
563 }
564
565 if ((ShellStatus == SHELL_SUCCESS) && (Resp == NULL)) {
566 ShellPrintEx (-1, -1, L"%s", HiiResultOk);
567 }
568
569 SHELL_FREE_NON_NULL (DestPath);
570 SHELL_FREE_NON_NULL (HiiOutput);
571 SHELL_FREE_NON_NULL (HiiResultOk);
572 SHELL_FREE_NON_NULL (CleanFilePathStr);
573 if (Resp == NULL) {
574 SHELL_FREE_NON_NULL (Response);
575 }
576
577 return (ShellStatus);
578 }
579
580 /**
581 Validate and if successful copy all the files from the list into
582 destination directory.
583
584 @param[in] FileList The list of files to copy.
585 @param[in] DestDir The directory to copy files to.
586 @param[in] SilentMode TRUE to eliminate screen output.
587 @param[in] RecursiveMode TRUE to copy directories.
588
589 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
590 @retval SHELL_SUCCESS The operation was successful.
591 **/
592 SHELL_STATUS
593 ProcessValidateAndCopyFiles (
594 IN EFI_SHELL_FILE_INFO *FileList,
595 IN CONST CHAR16 *DestDir,
596 IN BOOLEAN SilentMode,
597 IN BOOLEAN RecursiveMode
598 )
599 {
600 SHELL_STATUS ShellStatus;
601 EFI_SHELL_FILE_INFO *List;
602 EFI_FILE_INFO *FileInfo;
603 CHAR16 *FullName;
604
605 List = NULL;
606 FullName = NULL;
607 FileInfo = NULL;
608
609 ShellOpenFileMetaArg ((CHAR16 *)DestDir, EFI_FILE_MODE_READ, &List);
610 if ((List != NULL) && (List->Link.ForwardLink != List->Link.BackLink)) {
611 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir);
612 ShellStatus = SHELL_INVALID_PARAMETER;
613 ShellCloseFileMetaArg (&List);
614 } else if (List != NULL) {
615 ASSERT (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
616 ASSERT (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
617 FileInfo = gEfiShellProtocol->GetFileInfo (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
618 ASSERT (FileInfo != NULL);
619 StrnCatGrow (&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);
620 ShellCloseFileMetaArg (&List);
621 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
622 ShellStatus = ValidateAndCopyFiles (FileList, FullName, SilentMode, RecursiveMode, NULL);
623 } else {
624 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp");
625 ShellStatus = SHELL_ACCESS_DENIED;
626 }
627 } else {
628 ShellCloseFileMetaArg (&List);
629 ShellStatus = ValidateAndCopyFiles (FileList, DestDir, SilentMode, RecursiveMode, NULL);
630 }
631
632 SHELL_FREE_NON_NULL (FileInfo);
633 SHELL_FREE_NON_NULL (FullName);
634 return (ShellStatus);
635 }
636
637 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
638 { L"-r", TypeFlag },
639 { L"-q", TypeFlag },
640 { NULL, TypeMax }
641 };
642
643 /**
644 Function for 'cp' command.
645
646 @param[in] ImageHandle Handle to the Image (NULL if Internal).
647 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
648 **/
649 SHELL_STATUS
650 EFIAPI
651 ShellCommandRunCp (
652 IN EFI_HANDLE ImageHandle,
653 IN EFI_SYSTEM_TABLE *SystemTable
654 )
655 {
656 EFI_STATUS Status;
657 LIST_ENTRY *Package;
658 CHAR16 *ProblemParam;
659 SHELL_STATUS ShellStatus;
660 UINTN ParamCount;
661 UINTN LoopCounter;
662 EFI_SHELL_FILE_INFO *FileList;
663 BOOLEAN SilentMode;
664 BOOLEAN RecursiveMode;
665 CONST CHAR16 *Cwd;
666 CHAR16 *FullCwd;
667
668 ProblemParam = NULL;
669 ShellStatus = SHELL_SUCCESS;
670 ParamCount = 0;
671 FileList = NULL;
672
673 //
674 // initialize the shell lib (we must be in non-auto-init...)
675 //
676 Status = ShellInitialize ();
677 ASSERT_EFI_ERROR (Status);
678
679 Status = CommandInit ();
680 ASSERT_EFI_ERROR (Status);
681
682 //
683 // parse the command line
684 //
685 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
686 if (EFI_ERROR (Status)) {
687 if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
688 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam);
689 FreePool (ProblemParam);
690 ShellStatus = SHELL_INVALID_PARAMETER;
691 } else {
692 ASSERT (FALSE);
693 }
694 } else {
695 //
696 // check for "-?"
697 //
698 if (ShellCommandLineGetFlag (Package, L"-?")) {
699 ASSERT (FALSE);
700 }
701
702 //
703 // Initialize SilentMode and RecursiveMode
704 //
705 if (gEfiShellProtocol->BatchIsActive ()) {
706 SilentMode = TRUE;
707 } else {
708 SilentMode = ShellCommandLineGetFlag (Package, L"-q");
709 }
710
711 RecursiveMode = ShellCommandLineGetFlag (Package, L"-r");
712
713 switch (ParamCount = ShellCommandLineGetCount (Package)) {
714 case 0:
715 case 1:
716 //
717 // we have insufficient parameters
718 //
719 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp");
720 ShellStatus = SHELL_INVALID_PARAMETER;
721 break;
722 case 2:
723 //
724 // must have valid CWD for single parameter...
725 //
726 Cwd = ShellGetCurrentDir (NULL);
727 if (Cwd == NULL) {
728 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp");
729 ShellStatus = SHELL_INVALID_PARAMETER;
730 } else {
731 Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
732 if ((FileList == NULL) || IsListEmpty (&FileList->Link) || EFI_ERROR (Status)) {
733 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, 1));
734 ShellStatus = SHELL_NOT_FOUND;
735 } else {
736 FullCwd = AllocateZeroPool (StrSize (Cwd) + sizeof (CHAR16));
737 if (FullCwd == NULL) {
738 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cp");
739 ShellStatus = SHELL_OUT_OF_RESOURCES;
740 } else {
741 StrCpyS (FullCwd, StrSize (Cwd) / sizeof (CHAR16) + 1, Cwd);
742 ShellStatus = ProcessValidateAndCopyFiles (FileList, FullCwd, SilentMode, RecursiveMode);
743 FreePool (FullCwd);
744 }
745 }
746 }
747
748 break;
749 default:
750 //
751 // Make a big list of all the files...
752 //
753 for (ParamCount--, LoopCounter = 1; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS; LoopCounter++) {
754 if (ShellGetExecutionBreakFlag ()) {
755 break;
756 }
757
758 Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
759 if (EFI_ERROR (Status) || (FileList == NULL) || IsListEmpty (&FileList->Link)) {
760 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, LoopCounter));
761 ShellStatus = SHELL_NOT_FOUND;
762 }
763 }
764
765 if (ShellStatus != SHELL_SUCCESS) {
766 Status = ShellCloseFileMetaArg (&FileList);
767 } else {
768 //
769 // now copy them all...
770 //
771 if ((FileList != NULL) && !IsListEmpty (&FileList->Link)) {
772 ShellStatus = ProcessValidateAndCopyFiles (FileList, PathCleanUpDirectories ((CHAR16 *)ShellCommandLineGetRawValue (Package, ParamCount)), SilentMode, RecursiveMode);
773 Status = ShellCloseFileMetaArg (&FileList);
774 if (EFI_ERROR (Status) && (ShellStatus == SHELL_SUCCESS)) {
775 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, ParamCount), ShellStatus|MAX_BIT);
776 ShellStatus = SHELL_ACCESS_DENIED;
777 }
778 }
779 }
780
781 break;
782 } // switch on parameter count
783
784 if (FileList != NULL) {
785 ShellCloseFileMetaArg (&FileList);
786 }
787
788 //
789 // free the command line package
790 //
791 ShellCommandLineFreeVarList (Package);
792 }
793
794 if (ShellGetExecutionBreakFlag ()) {
795 return (SHELL_ABORTED);
796 }
797
798 return (ShellStatus);
799 }