2 Main file for cp shell level 2 function.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "UefiShellLevel2CommandsLib.h"
17 #include <Guid/FileSystemInfo.h>
18 #include <Guid/FileSystemVolumeLabelInfo.h>
21 Function to take a list of files to copy and a destination location and do
22 the verification and copying of those files to that location. This function
23 will report any errors to the user and halt.
25 @param[in] FileList A LIST_ENTRY* based list of files to move.
26 @param[in] DestDir The destination location.
27 @param[in] SilentMode TRUE to eliminate screen output.
28 @param[in] RecursiveMode TRUE to copy directories.
29 @param[in] Resp The response to the overwrite query (if always).
31 @retval SHELL_SUCCESS the files were all moved.
32 @retval SHELL_INVALID_PARAMETER a parameter was invalid
33 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
34 @retval SHELL_WRITE_PROTECTED the destination was write protected
35 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
40 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
41 IN CONST CHAR16
*DestDir
,
42 IN BOOLEAN SilentMode
,
43 IN BOOLEAN RecursiveMode
,
48 Function to Copy one file to another location
50 If the destination exists the user will be prompted and the result put into *resp
52 @param[in] Source pointer to source file name
53 @param[in] Dest pointer to destination file name
54 @param[out] Resp pointer to response from question. Pass back on looped calling
55 @param[in] SilentMode whether to run in quiet mode or not
56 @param[in] CmdName Source command name requesting single file copy
58 @retval SHELL_SUCCESS The source file was copied to the destination
63 IN CONST CHAR16
*Source
,
64 IN CONST CHAR16
*Dest
,
66 IN BOOLEAN SilentMode
,
67 IN CONST CHAR16
*CmdName
72 SHELL_FILE_HANDLE SourceHandle
;
73 SHELL_FILE_HANDLE DestHandle
;
78 EFI_SHELL_FILE_INFO
*List
;
79 SHELL_STATUS ShellStatus
;
80 UINT64 SourceFileSize
;
82 EFI_FILE_PROTOCOL
*DestVolumeFP
;
83 EFI_FILE_SYSTEM_INFO
*DestVolumeInfo
;
84 UINTN DestVolumeInfoSize
;
92 DestVolumeInfo
= NULL
;
93 ShellStatus
= SHELL_SUCCESS
;
95 ReadSize
= PcdGet32(PcdShellFileOperationSize
);
96 // Why bother copying a file to itself
97 if (StrCmp(Source
, Dest
) == 0) {
98 return (SHELL_SUCCESS
);
102 // if the destination file existed check response and possibly prompt user
104 if (ShellFileExists(Dest
) == EFI_SUCCESS
) {
105 if (Response
== NULL
&& !SilentMode
) {
106 Status
= ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel
, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR
), gShellLevel2HiiHandle
, &Response
);
109 // possibly return based on response
112 switch (*(SHELL_PROMPT_RESPONSE
*)Response
) {
113 case ShellPromptResponseNo
:
115 // return success here so we dont stop the process
117 return (SHELL_SUCCESS
);
118 case ShellPromptResponseCancel
:
121 // indicate to stop everything
123 return (SHELL_ABORTED
);
124 case ShellPromptResponseAll
:
126 case ShellPromptResponseYes
:
129 return SHELL_ABORTED
;
134 if (ShellIsDirectory(Source
) == EFI_SUCCESS
) {
135 Status
= ShellCreateDirectory(Dest
, &DestHandle
);
136 if (EFI_ERROR(Status
)) {
137 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DEST_DIR_FAIL
), gShellLevel2HiiHandle
, CmdName
, Dest
);
138 return (SHELL_ACCESS_DENIED
);
142 // Now copy all the files under the directory...
146 StrnCatGrow(&TempName
, &Size
, Source
, 0);
147 StrnCatGrow(&TempName
, &Size
, L
"\\*", 0);
148 if (TempName
!= NULL
) {
149 ShellOpenFileMetaArg((CHAR16
*)TempName
, EFI_FILE_MODE_READ
, &List
);
150 *TempName
= CHAR_NULL
;
151 StrnCatGrow(&TempName
, &Size
, Dest
, 0);
152 StrnCatGrow(&TempName
, &Size
, L
"\\", 0);
153 ShellStatus
= ValidateAndCopyFiles(List
, TempName
, SilentMode
, TRUE
, Resp
);
154 ShellCloseFileMetaArg(&List
);
155 SHELL_FREE_NON_NULL(TempName
);
159 Status
= ShellDeleteFileByName(Dest
);
162 // open file with create enabled
164 Status
= ShellOpenFileByName(Dest
, &DestHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_CREATE
, 0);
165 if (EFI_ERROR(Status
)) {
166 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL
), gShellLevel2HiiHandle
, CmdName
, Dest
);
167 return (SHELL_ACCESS_DENIED
);
173 Status
= ShellOpenFileByName(Source
, &SourceHandle
, EFI_FILE_MODE_READ
, 0);
174 ASSERT_EFI_ERROR(Status
);
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 ASSERT(Buffer
!= NULL
);
230 while (ReadSize
== PcdGet32(PcdShellFileOperationSize
) && !EFI_ERROR(Status
)) {
231 Status
= ShellReadFile(SourceHandle
, &ReadSize
, Buffer
);
232 if (!EFI_ERROR(Status
)) {
233 Status
= ShellWriteFile(DestHandle
, &ReadSize
, Buffer
);
234 if (EFI_ERROR(Status
)) {
235 ShellStatus
= (SHELL_STATUS
) (Status
& (~MAX_BIT
));
236 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR
), gShellLevel2HiiHandle
, CmdName
, Dest
);
240 ShellStatus
= (SHELL_STATUS
) (Status
& (~MAX_BIT
));
241 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_CPY_READ_ERROR
), gShellLevel2HiiHandle
, CmdName
, Source
);
246 SHELL_FREE_NON_NULL(DestVolumeInfo
);
252 if (DestHandle
!= NULL
) {
253 ShellCloseFile(&DestHandle
);
256 if (SourceHandle
!= NULL
) {
257 ShellCloseFile(&SourceHandle
);
268 function to take a list of files to copy and a destination location and do
269 the verification and copying of those files to that location. This function
270 will report any errors to the user and halt.
272 The key is to have this function called ONLY once. this allows for the parameter
273 verification to happen correctly.
275 @param[in] FileList A LIST_ENTRY* based list of files to move.
276 @param[in] DestDir The destination location.
277 @param[in] SilentMode TRUE to eliminate screen output.
278 @param[in] RecursiveMode TRUE to copy directories.
279 @param[in] Resp The response to the overwrite query (if always).
281 @retval SHELL_SUCCESS the files were all moved.
282 @retval SHELL_INVALID_PARAMETER a parameter was invalid
283 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
284 @retval SHELL_WRITE_PROTECTED the destination was write protected
285 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
289 ValidateAndCopyFiles(
290 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
291 IN CONST CHAR16
*DestDir
,
292 IN BOOLEAN SilentMode
,
293 IN BOOLEAN RecursiveMode
,
299 CONST EFI_SHELL_FILE_INFO
*Node
;
300 SHELL_STATUS ShellStatus
;
307 CHAR16
*CleanFilePathStr
;
316 ShellStatus
= SHELL_SUCCESS
;
318 Cwd
= ShellGetCurrentDir(NULL
);
319 CleanFilePathStr
= NULL
;
321 ASSERT(FileList
!= NULL
);
322 ASSERT(DestDir
!= NULL
);
325 Status
= ShellLevel2StripQuotes (DestDir
, &CleanFilePathStr
);
326 if (EFI_ERROR (Status
)) {
327 if (Status
== EFI_OUT_OF_RESOURCES
) {
328 return SHELL_OUT_OF_RESOURCES
;
330 return SHELL_INVALID_PARAMETER
;
334 ASSERT (CleanFilePathStr
!= NULL
);
337 // If we are trying to copy multiple files... make sure we got a directory for the target...
339 if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr
)) && FileList
->Link
.ForwardLink
!= FileList
->Link
.BackLink
) {
341 // Error for destination not a directory
343 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NOT_DIR
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
344 FreePool (CleanFilePathStr
);
345 return (SHELL_INVALID_PARAMETER
);
347 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
348 ; !IsNull(&FileList
->Link
, &Node
->Link
)
349 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
352 // skip the directory traversing stuff...
354 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
358 NewSize
= StrSize(CleanFilePathStr
);
359 NewSize
+= StrSize(Node
->FullName
);
360 NewSize
+= (Cwd
== NULL
)? 0 : StrSize(Cwd
);
361 if (NewSize
> PathSize
) {
366 // Make sure got -r if required
368 if (!RecursiveMode
&& !EFI_ERROR(ShellIsDirectory(Node
->FullName
))) {
369 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DIR_REQ
), gShellLevel2HiiHandle
, L
"cp");
370 FreePool (CleanFilePathStr
);
371 return (SHELL_INVALID_PARAMETER
);
375 // make sure got dest as dir if needed
377 if (!EFI_ERROR(ShellIsDirectory(Node
->FullName
)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr
))) {
379 // Error for destination not a directory
381 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NOT_DIR
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
382 FreePool (CleanFilePathStr
);
383 return (SHELL_INVALID_PARAMETER
);
387 HiiOutput
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_CP_OUTPUT
), NULL
);
388 HiiResultOk
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_GEN_RES_OK
), NULL
);
389 DestPath
= AllocateZeroPool(PathSize
);
391 if (DestPath
== NULL
|| HiiOutput
== NULL
|| HiiResultOk
== NULL
) {
392 SHELL_FREE_NON_NULL(DestPath
);
393 SHELL_FREE_NON_NULL(HiiOutput
);
394 SHELL_FREE_NON_NULL(HiiResultOk
);
395 FreePool (CleanFilePathStr
);
396 return (SHELL_OUT_OF_RESOURCES
);
400 // Go through the list of files to copy...
402 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
403 ; !IsNull(&FileList
->Link
, &Node
->Link
)
404 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
406 if (ShellGetExecutionBreakFlag()) {
409 ASSERT(Node
->FileName
!= NULL
);
410 ASSERT(Node
->FullName
!= NULL
);
413 // skip the directory traversing stuff...
415 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
419 if (FileList
->Link
.ForwardLink
== FileList
->Link
.BackLink
// 1 item
420 && EFI_ERROR(ShellIsDirectory(CleanFilePathStr
)) // not an existing directory
422 if (StrStr(CleanFilePathStr
, L
":") == NULL
) {
424 // simple copy of a single file
427 StrnCpy(DestPath
, Cwd
, PathSize
/sizeof(CHAR16
)-1);
429 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_DIR_NF
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
430 FreePool (CleanFilePathStr
);
431 return (SHELL_INVALID_PARAMETER
);
433 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && CleanFilePathStr
[0] != L
'\\') {
434 StrnCat(DestPath
, L
"\\", PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
435 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && CleanFilePathStr
[0] == L
'\\') {
436 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
438 StrnCat(DestPath
, CleanFilePathStr
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
440 StrnCpy(DestPath
, CleanFilePathStr
, PathSize
/sizeof(CHAR16
) -1);
444 // we have multiple files or a directory in the DestDir
448 // Check for leading slash
450 if (CleanFilePathStr
[0] == L
'\\') {
452 // Copy to the root of CWD
455 StrnCpy(DestPath
, Cwd
, PathSize
/sizeof(CHAR16
) -1);
457 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_DIR_NF
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
458 FreePool(CleanFilePathStr
);
459 return (SHELL_INVALID_PARAMETER
);
461 while (PathRemoveLastItem(DestPath
));
462 StrnCat(DestPath
, CleanFilePathStr
+1, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
463 StrnCat(DestPath
, Node
->FileName
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
464 } else if (StrStr(CleanFilePathStr
, L
":") == NULL
) {
466 StrnCpy(DestPath
, Cwd
, PathSize
/sizeof(CHAR16
) -1);
468 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_DIR_NF
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
469 FreePool(CleanFilePathStr
);
470 return (SHELL_INVALID_PARAMETER
);
472 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && CleanFilePathStr
[0] != L
'\\') {
473 StrnCat(DestPath
, L
"\\", PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
474 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && CleanFilePathStr
[0] == L
'\\') {
475 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
477 StrnCat(DestPath
, CleanFilePathStr
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
478 if (CleanFilePathStr
[StrLen(CleanFilePathStr
)-1] != L
'\\' && Node
->FileName
[0] != L
'\\') {
479 StrnCat(DestPath
, L
"\\", PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
480 } else if (CleanFilePathStr
[StrLen(CleanFilePathStr
)-1] == L
'\\' && Node
->FileName
[0] == L
'\\') {
481 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
483 StrnCat(DestPath
, Node
->FileName
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
486 StrnCpy(DestPath
, CleanFilePathStr
, PathSize
/sizeof(CHAR16
) -1);
487 if (CleanFilePathStr
[StrLen(CleanFilePathStr
)-1] != L
'\\' && Node
->FileName
[0] != L
'\\') {
488 StrnCat(DestPath
, L
"\\", PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
489 } else if (CleanFilePathStr
[StrLen(CleanFilePathStr
)-1] == L
'\\' && Node
->FileName
[0] == L
'\\') {
490 ((CHAR16
*)CleanFilePathStr
)[StrLen(CleanFilePathStr
)-1] = CHAR_NULL
;
492 StrnCat(DestPath
, Node
->FileName
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
497 // Make sure the path exists
499 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath
))) {
500 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DIR_WNF
), gShellLevel2HiiHandle
, L
"cp", DestPath
);
501 ShellStatus
= SHELL_DEVICE_ERROR
;
505 if ( !EFI_ERROR(ShellIsDirectory(Node
->FullName
))
506 && !EFI_ERROR(ShellIsDirectory(DestPath
))
507 && StrniCmp(Node
->FullName
, DestPath
, StrLen(DestPath
)) == NULL
509 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_PARENT
), gShellLevel2HiiHandle
, L
"cp");
510 ShellStatus
= SHELL_INVALID_PARAMETER
;
513 if (StringNoCaseCompare(&Node
->FullName
, &DestPath
) == 0) {
514 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_SAME
), gShellLevel2HiiHandle
, L
"cp");
515 ShellStatus
= SHELL_INVALID_PARAMETER
;
519 if ((StrniCmp(Node
->FullName
, DestPath
, StrLen(Node
->FullName
)) == 0)
520 && (DestPath
[StrLen(Node
->FullName
)] == CHAR_NULL
|| DestPath
[StrLen(Node
->FullName
)] == L
'\\')
522 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_SAME
), gShellLevel2HiiHandle
, L
"cp");
523 ShellStatus
= SHELL_INVALID_PARAMETER
;
527 PathCleanUpDirectories(DestPath
);
530 ShellPrintEx(-1, -1, HiiOutput
, Node
->FullName
, DestPath
);
534 // copy single file...
536 ShellStatus
= CopySingleFile(Node
->FullName
, DestPath
, &Response
, SilentMode
, L
"cp");
537 if (ShellStatus
!= SHELL_SUCCESS
) {
541 if (ShellStatus
== SHELL_SUCCESS
&& Resp
== NULL
) {
542 ShellPrintEx(-1, -1, L
"%s", HiiResultOk
);
545 SHELL_FREE_NON_NULL(DestPath
);
546 SHELL_FREE_NON_NULL(HiiOutput
);
547 SHELL_FREE_NON_NULL(HiiResultOk
);
548 SHELL_FREE_NON_NULL(CleanFilePathStr
);
550 SHELL_FREE_NON_NULL(Response
);
553 return (ShellStatus
);
558 Validate and if successful copy all the files from the list into
559 destination directory.
561 @param[in] FileList The list of files to copy.
562 @param[in] DestDir The directory to copy files to.
563 @param[in] SilentMode TRUE to eliminate screen output.
564 @param[in] RecursiveMode TRUE to copy directories.
566 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
567 @retval SHELL_SUCCESS The operation was successful.
571 ProcessValidateAndCopyFiles(
572 IN EFI_SHELL_FILE_INFO
*FileList
,
573 IN CONST CHAR16
*DestDir
,
574 IN BOOLEAN SilentMode
,
575 IN BOOLEAN RecursiveMode
578 SHELL_STATUS ShellStatus
;
579 EFI_SHELL_FILE_INFO
*List
;
580 EFI_FILE_INFO
*FileInfo
;
587 ShellOpenFileMetaArg((CHAR16
*)DestDir
, EFI_FILE_MODE_READ
, &List
);
588 if (List
!= NULL
&& List
->Link
.ForwardLink
!= List
->Link
.BackLink
) {
589 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_MARG_ERROR
), gShellLevel2HiiHandle
, L
"cp", DestDir
);
590 ShellStatus
= SHELL_INVALID_PARAMETER
;
591 ShellCloseFileMetaArg(&List
);
592 } else if (List
!= NULL
) {
593 ASSERT(((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
) != NULL
);
594 ASSERT(((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
)->FullName
!= NULL
);
595 FileInfo
= gEfiShellProtocol
->GetFileInfo(((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
)->Handle
);
596 ASSERT(FileInfo
!= NULL
);
597 StrnCatGrow(&FullName
, NULL
, ((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
)->FullName
, 0);
598 ShellCloseFileMetaArg(&List
);
599 if ((FileInfo
->Attribute
& EFI_FILE_READ_ONLY
) == 0) {
600 ShellStatus
= ValidateAndCopyFiles(FileList
, FullName
, SilentMode
, RecursiveMode
, NULL
);
602 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DEST_ERROR
), gShellLevel2HiiHandle
, L
"cp");
603 ShellStatus
= SHELL_ACCESS_DENIED
;
606 ShellCloseFileMetaArg(&List
);
607 ShellStatus
= ValidateAndCopyFiles(FileList
, DestDir
, SilentMode
, RecursiveMode
, NULL
);
610 SHELL_FREE_NON_NULL(FileInfo
);
611 SHELL_FREE_NON_NULL(FullName
);
612 return (ShellStatus
);
615 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
622 Function for 'cp' command.
624 @param[in] ImageHandle Handle to the Image (NULL if Internal).
625 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
630 IN EFI_HANDLE ImageHandle
,
631 IN EFI_SYSTEM_TABLE
*SystemTable
636 CHAR16
*ProblemParam
;
637 SHELL_STATUS ShellStatus
;
640 EFI_SHELL_FILE_INFO
*FileList
;
642 BOOLEAN RecursiveMode
;
646 ShellStatus
= SHELL_SUCCESS
;
651 // initialize the shell lib (we must be in non-auto-init...)
653 Status
= ShellInitialize();
654 ASSERT_EFI_ERROR(Status
);
656 Status
= CommandInit();
657 ASSERT_EFI_ERROR(Status
);
660 // parse the command line
662 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
663 if (EFI_ERROR(Status
)) {
664 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
665 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, L
"cp", ProblemParam
);
666 FreePool(ProblemParam
);
667 ShellStatus
= SHELL_INVALID_PARAMETER
;
675 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
680 // Initialize SilentMode and RecursiveMode
682 if (gEfiShellProtocol
->BatchIsActive()) {
685 SilentMode
= ShellCommandLineGetFlag(Package
, L
"-q");
687 RecursiveMode
= ShellCommandLineGetFlag(Package
, L
"-r");
689 switch (ParamCount
= ShellCommandLineGetCount(Package
)) {
693 // we have insufficient parameters
695 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
, L
"cp");
696 ShellStatus
= SHELL_INVALID_PARAMETER
;
700 // must have valid CWD for single parameter...
702 Cwd
= ShellGetCurrentDir(NULL
);
704 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
, L
"cp");
705 ShellStatus
= SHELL_INVALID_PARAMETER
;
707 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, 1), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
708 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
709 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, L
"cp", ShellCommandLineGetRawValue(Package
, 1));
710 ShellStatus
= SHELL_NOT_FOUND
;
712 ShellStatus
= ProcessValidateAndCopyFiles(FileList
, Cwd
, SilentMode
, RecursiveMode
);
719 // Make a big list of all the files...
721 for (ParamCount
--, LoopCounter
= 1 ; LoopCounter
< ParamCount
&& ShellStatus
== SHELL_SUCCESS
; LoopCounter
++) {
722 if (ShellGetExecutionBreakFlag()) {
725 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, LoopCounter
), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
726 if (EFI_ERROR(Status
) || FileList
== NULL
|| IsListEmpty(&FileList
->Link
)) {
727 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, L
"cp", ShellCommandLineGetRawValue(Package
, LoopCounter
));
728 ShellStatus
= SHELL_NOT_FOUND
;
731 if (ShellStatus
!= SHELL_SUCCESS
) {
732 Status
= ShellCloseFileMetaArg(&FileList
);
735 // now copy them all...
737 if (FileList
!= NULL
&& !IsListEmpty(&FileList
->Link
)) {
738 ShellStatus
= ProcessValidateAndCopyFiles(FileList
, PathCleanUpDirectories((CHAR16
*)ShellCommandLineGetRawValue(Package
, ParamCount
)), SilentMode
, RecursiveMode
);
739 Status
= ShellCloseFileMetaArg(&FileList
);
740 if (EFI_ERROR(Status
) && ShellStatus
== SHELL_SUCCESS
) {
741 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_FILE
), gShellLevel2HiiHandle
, L
"cp", ShellCommandLineGetRawValue(Package
, ParamCount
), ShellStatus
|MAX_BIT
);
742 ShellStatus
= SHELL_ACCESS_DENIED
;
747 } // switch on parameter count
749 if (FileList
!= NULL
) {
750 ShellCloseFileMetaArg(&FileList
);
754 // free the command line package
756 ShellCommandLineFreeVarList (Package
);
759 if (ShellGetExecutionBreakFlag()) {
760 return (SHELL_ABORTED
);
763 return (ShellStatus
);