2 Main file for cp shell level 2 function.
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
10 #include "UefiShellLevel2CommandsLib.h"
11 #include <Guid/FileSystemInfo.h>
12 #include <Guid/FileSystemVolumeLabelInfo.h>
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.
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).
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
32 ValidateAndCopyFiles (
33 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
34 IN CONST CHAR16
*DestDir
,
35 IN BOOLEAN SilentMode
,
36 IN BOOLEAN RecursiveMode
,
41 Function to Copy one file to another location
43 If the destination exists the user will be prompted and the result put into *resp
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
51 @retval SHELL_SUCCESS The source file was copied to the destination
55 IN CONST CHAR16
*Source
,
56 IN CONST CHAR16
*Dest
,
58 IN BOOLEAN SilentMode
,
59 IN CONST CHAR16
*CmdName
64 SHELL_FILE_HANDLE SourceHandle
;
65 SHELL_FILE_HANDLE DestHandle
;
70 EFI_SHELL_FILE_INFO
*List
;
71 SHELL_STATUS ShellStatus
;
72 UINT64 SourceFileSize
;
74 EFI_FILE_PROTOCOL
*DestVolumeFP
;
75 EFI_FILE_SYSTEM_INFO
*DestVolumeInfo
;
76 UINTN DestVolumeInfoSize
;
78 ASSERT (Resp
!= NULL
);
84 DestVolumeInfo
= NULL
;
85 ShellStatus
= SHELL_SUCCESS
;
87 ReadSize
= PcdGet32 (PcdShellFileOperationSize
);
88 // Why bother copying a file to itself
89 if (StrCmp (Source
, Dest
) == 0) {
90 return (SHELL_SUCCESS
);
94 // if the destination file existed check response and possibly prompt user
96 if (ShellFileExists (Dest
) == EFI_SUCCESS
) {
97 if ((Response
== NULL
) && !SilentMode
) {
98 Status
= ShellPromptForResponseHii (ShellPromptResponseTypeYesNoAllCancel
, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR
), gShellLevel2HiiHandle
, &Response
);
102 // possibly return based on response
105 if (Response
== NULL
) {
106 return SHELL_ABORTED
;
109 switch (*(SHELL_PROMPT_RESPONSE
*)Response
) {
110 case ShellPromptResponseNo
:
112 // return success here so we dont stop the process
114 return (SHELL_SUCCESS
);
115 case ShellPromptResponseCancel
:
118 // indicate to stop everything
120 return (SHELL_ABORTED
);
121 case ShellPromptResponseAll
:
123 case ShellPromptResponseYes
:
126 return SHELL_ABORTED
;
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
);
139 // Now copy all the files under the directory...
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
);
156 Status
= ShellDeleteFileByName (Dest
);
159 // open file with create enabled
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
);
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
);
177 // get file size of source file and freespace available on destination volume
179 ShellGetFileSize (SourceHandle
, &SourceFileSize
);
180 ShellGetFileSize (DestHandle
, &DestFileSize
);
183 // if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space
185 if (DestFileSize
< SourceFileSize
) {
186 SourceFileSize
-= DestFileSize
;
192 // get the system volume info to check the free space
194 DestVolumeFP
= ConvertShellHandleToEfiFileProtocol (DestHandle
);
195 DestVolumeInfo
= NULL
;
196 DestVolumeInfoSize
= 0;
197 Status
= DestVolumeFP
->GetInfo (
199 &gEfiFileSystemInfoGuid
,
204 if (Status
== EFI_BUFFER_TOO_SMALL
) {
205 DestVolumeInfo
= AllocateZeroPool (DestVolumeInfoSize
);
206 Status
= DestVolumeFP
->GetInfo (
208 &gEfiFileSystemInfoGuid
,
215 // check if enough space available on destination drive to complete copy
217 if ((DestVolumeInfo
!= NULL
) && (DestVolumeInfo
->FreeSpace
< SourceFileSize
)) {
219 // not enough space on destination directory to copy file
221 SHELL_FREE_NON_NULL (DestVolumeInfo
);
222 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_CPY_FAIL
), gShellLevel2HiiHandle
, CmdName
);
223 return (SHELL_VOLUME_FULL
);
226 // copy data between files
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
;
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
);
244 ShellStatus
= (SHELL_STATUS
)(Status
& (~MAX_BIT
));
245 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_CPY_READ_ERROR
), gShellLevel2HiiHandle
, CmdName
, Source
);
251 SHELL_FREE_NON_NULL (DestVolumeInfo
);
257 if (DestHandle
!= NULL
) {
258 ShellCloseFile (&DestHandle
);
262 if (SourceHandle
!= NULL
) {
263 ShellCloseFile (&SourceHandle
);
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.
278 The key is to have this function called ONLY once. this allows for the parameter
279 verification to happen correctly.
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).
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
294 ValidateAndCopyFiles (
295 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
296 IN CONST CHAR16
*DestDir
,
297 IN BOOLEAN SilentMode
,
298 IN BOOLEAN RecursiveMode
,
304 CONST EFI_SHELL_FILE_INFO
*Node
;
305 SHELL_STATUS ShellStatus
;
312 CHAR16
*CleanFilePathStr
;
321 ShellStatus
= SHELL_SUCCESS
;
323 Cwd
= ShellGetCurrentDir (NULL
);
324 CleanFilePathStr
= NULL
;
326 ASSERT (FileList
!= NULL
);
327 ASSERT (DestDir
!= NULL
);
329 Status
= ShellLevel2StripQuotes (DestDir
, &CleanFilePathStr
);
330 if (EFI_ERROR (Status
)) {
331 if (Status
== EFI_OUT_OF_RESOURCES
) {
332 return SHELL_OUT_OF_RESOURCES
;
334 return SHELL_INVALID_PARAMETER
;
338 ASSERT (CleanFilePathStr
!= NULL
);
341 // If we are trying to copy multiple files... make sure we got a directory for the target...
343 if (EFI_ERROR (ShellIsDirectory (CleanFilePathStr
)) && (FileList
->Link
.ForwardLink
!= FileList
->Link
.BackLink
)) {
345 // Error for destination not a directory
347 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_NOT_DIR
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
348 FreePool (CleanFilePathStr
);
349 return (SHELL_INVALID_PARAMETER
);
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
)
358 // skip the directory traversing stuff...
360 if ((StrCmp (Node
->FileName
, L
".") == 0) || (StrCmp (Node
->FileName
, L
"..") == 0)) {
364 NewSize
= StrSize (CleanFilePathStr
);
365 NewSize
+= StrSize (Node
->FullName
);
366 NewSize
+= (Cwd
== NULL
) ? 0 : (StrSize (Cwd
) + sizeof (CHAR16
));
367 if (NewSize
> PathSize
) {
372 // Make sure got -r if required
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
);
381 // make sure got dest as dir if needed
383 if (!EFI_ERROR (ShellIsDirectory (Node
->FullName
)) && EFI_ERROR (ShellIsDirectory (CleanFilePathStr
))) {
385 // Error for destination not a directory
387 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_NOT_DIR
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
388 FreePool (CleanFilePathStr
);
389 return (SHELL_INVALID_PARAMETER
);
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
);
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
);
406 // Go through the list of files to copy...
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
)
413 if (ShellGetExecutionBreakFlag ()) {
417 ASSERT (Node
->FileName
!= NULL
);
418 ASSERT (Node
->FullName
!= NULL
);
421 // skip the directory traversing stuff...
423 if ((StrCmp (Node
->FileName
, L
".") == 0) || (StrCmp (Node
->FileName
, L
"..") == 0)) {
427 if ( (FileList
->Link
.ForwardLink
== FileList
->Link
.BackLink
) // 1 item
428 && EFI_ERROR (ShellIsDirectory (CleanFilePathStr
)) // not an existing directory
431 if (StrStr (CleanFilePathStr
, L
":") == NULL
) {
433 // simple copy of a single file
436 StrCpyS (DestPath
, PathSize
/ sizeof (CHAR16
), Cwd
);
437 StrCatS (DestPath
, PathSize
/ sizeof (CHAR16
), L
"\\");
439 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_DIR_NF
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
440 FreePool (CleanFilePathStr
);
441 return (SHELL_INVALID_PARAMETER
);
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
;
450 StrCatS (DestPath
, PathSize
/sizeof (CHAR16
), CleanFilePathStr
);
452 StrCpyS (DestPath
, PathSize
/sizeof (CHAR16
), CleanFilePathStr
);
456 // we have multiple files or a directory in the DestDir
460 // Check for leading slash
462 if (CleanFilePathStr
[0] == L
'\\') {
464 // Copy to the root of CWD
467 StrCpyS (DestPath
, PathSize
/sizeof (CHAR16
), Cwd
);
468 StrCatS (DestPath
, PathSize
/sizeof (CHAR16
), L
"\\");
470 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_DIR_NF
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
471 FreePool (CleanFilePathStr
);
472 return (SHELL_INVALID_PARAMETER
);
475 while (PathRemoveLastItem (DestPath
)) {
478 StrCatS (DestPath
, PathSize
/sizeof (CHAR16
), CleanFilePathStr
+1);
479 StrCatS (DestPath
, PathSize
/sizeof (CHAR16
), Node
->FileName
);
480 } else if (StrStr (CleanFilePathStr
, L
":") == NULL
) {
482 StrCpyS (DestPath
, PathSize
/sizeof (CHAR16
), Cwd
);
483 StrCatS (DestPath
, PathSize
/sizeof (CHAR16
), L
"\\");
485 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_DIR_NF
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
486 FreePool (CleanFilePathStr
);
487 return (SHELL_INVALID_PARAMETER
);
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
;
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
;
503 StrCatS (DestPath
, PathSize
/sizeof (CHAR16
), Node
->FileName
);
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
;
512 StrCatS (DestPath
, PathSize
/sizeof (CHAR16
), Node
->FileName
);
517 // Make sure the path exists
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
;
525 if ( !EFI_ERROR (ShellIsDirectory (Node
->FullName
))
526 && !EFI_ERROR (ShellIsDirectory (DestPath
))
527 && (StrniCmp (Node
->FullName
, DestPath
, StrLen (DestPath
)) == 0)
530 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_PARENT
), gShellLevel2HiiHandle
, L
"cp");
531 ShellStatus
= SHELL_INVALID_PARAMETER
;
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
;
541 if ( (StrniCmp (Node
->FullName
, DestPath
, StrLen (Node
->FullName
)) == 0)
542 && ((DestPath
[StrLen (Node
->FullName
)] == CHAR_NULL
) || (DestPath
[StrLen (Node
->FullName
)] == L
'\\'))
545 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_SAME
), gShellLevel2HiiHandle
, L
"cp");
546 ShellStatus
= SHELL_INVALID_PARAMETER
;
550 PathCleanUpDirectories (DestPath
);
553 ShellPrintEx (-1, -1, HiiOutput
, Node
->FullName
, DestPath
);
557 // copy single file...
559 ShellStatus
= CopySingleFile (Node
->FullName
, DestPath
, &Response
, SilentMode
, L
"cp");
560 if (ShellStatus
!= SHELL_SUCCESS
) {
565 if ((ShellStatus
== SHELL_SUCCESS
) && (Resp
== NULL
)) {
566 ShellPrintEx (-1, -1, L
"%s", HiiResultOk
);
569 SHELL_FREE_NON_NULL (DestPath
);
570 SHELL_FREE_NON_NULL (HiiOutput
);
571 SHELL_FREE_NON_NULL (HiiResultOk
);
572 SHELL_FREE_NON_NULL (CleanFilePathStr
);
574 SHELL_FREE_NON_NULL (Response
);
577 return (ShellStatus
);
581 Validate and if successful copy all the files from the list into
582 destination directory.
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.
589 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
590 @retval SHELL_SUCCESS The operation was successful.
593 ProcessValidateAndCopyFiles (
594 IN EFI_SHELL_FILE_INFO
*FileList
,
595 IN CONST CHAR16
*DestDir
,
596 IN BOOLEAN SilentMode
,
597 IN BOOLEAN RecursiveMode
600 SHELL_STATUS ShellStatus
;
601 EFI_SHELL_FILE_INFO
*List
;
602 EFI_FILE_INFO
*FileInfo
;
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
);
624 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_CP_DEST_ERROR
), gShellLevel2HiiHandle
, L
"cp");
625 ShellStatus
= SHELL_ACCESS_DENIED
;
628 ShellCloseFileMetaArg (&List
);
629 ShellStatus
= ValidateAndCopyFiles (FileList
, DestDir
, SilentMode
, RecursiveMode
, NULL
);
632 SHELL_FREE_NON_NULL (FileInfo
);
633 SHELL_FREE_NON_NULL (FullName
);
634 return (ShellStatus
);
637 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
644 Function for 'cp' command.
646 @param[in] ImageHandle Handle to the Image (NULL if Internal).
647 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
652 IN EFI_HANDLE ImageHandle
,
653 IN EFI_SYSTEM_TABLE
*SystemTable
658 CHAR16
*ProblemParam
;
659 SHELL_STATUS ShellStatus
;
662 EFI_SHELL_FILE_INFO
*FileList
;
664 BOOLEAN RecursiveMode
;
669 ShellStatus
= SHELL_SUCCESS
;
674 // initialize the shell lib (we must be in non-auto-init...)
676 Status
= ShellInitialize ();
677 ASSERT_EFI_ERROR (Status
);
679 Status
= CommandInit ();
680 ASSERT_EFI_ERROR (Status
);
683 // parse the command line
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
;
698 if (ShellCommandLineGetFlag (Package
, L
"-?")) {
703 // Initialize SilentMode and RecursiveMode
705 if (gEfiShellProtocol
->BatchIsActive ()) {
708 SilentMode
= ShellCommandLineGetFlag (Package
, L
"-q");
711 RecursiveMode
= ShellCommandLineGetFlag (Package
, L
"-r");
713 switch (ParamCount
= ShellCommandLineGetCount (Package
)) {
717 // we have insufficient parameters
719 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
, L
"cp");
720 ShellStatus
= SHELL_INVALID_PARAMETER
;
724 // must have valid CWD for single parameter...
726 Cwd
= ShellGetCurrentDir (NULL
);
728 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
, L
"cp");
729 ShellStatus
= SHELL_INVALID_PARAMETER
;
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
;
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
;
741 StrCpyS (FullCwd
, StrSize (Cwd
) / sizeof (CHAR16
) + 1, Cwd
);
742 ShellStatus
= ProcessValidateAndCopyFiles (FileList
, FullCwd
, SilentMode
, RecursiveMode
);
751 // Make a big list of all the files...
753 for (ParamCount
--, LoopCounter
= 1; LoopCounter
< ParamCount
&& ShellStatus
== SHELL_SUCCESS
; LoopCounter
++) {
754 if (ShellGetExecutionBreakFlag ()) {
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
;
765 if (ShellStatus
!= SHELL_SUCCESS
) {
766 Status
= ShellCloseFileMetaArg (&FileList
);
769 // now copy them all...
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
;
782 } // switch on parameter count
784 if (FileList
!= NULL
) {
785 ShellCloseFileMetaArg (&FileList
);
789 // free the command line package
791 ShellCommandLineFreeVarList (Package
);
794 if (ShellGetExecutionBreakFlag ()) {
795 return (SHELL_ABORTED
);
798 return (ShellStatus
);