2 Main file for cp shell level 2 function.
4 Copyright (c) 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
57 @retval SHELL_SUCCESS The source file was copied to the destination
62 IN CONST CHAR16
*Source
,
63 IN CONST CHAR16
*Dest
,
70 SHELL_FILE_HANDLE SourceHandle
;
71 SHELL_FILE_HANDLE DestHandle
;
76 EFI_SHELL_FILE_INFO
*List
;
77 SHELL_STATUS ShellStatus
;
78 UINT64 SourceFileSize
;
80 EFI_FILE_PROTOCOL
*DestVolumeFP
;
81 EFI_FILE_SYSTEM_INFO
*DestVolumeInfo
;
82 UINTN DestVolumeInfoSize
;
90 DestVolumeInfo
= NULL
;
91 ShellStatus
= SHELL_SUCCESS
;
93 ReadSize
= PcdGet32(PcdShellFileOperationSize
);
94 // Why bother copying a file to itself
95 if (StrCmp(Source
, Dest
) == 0) {
96 return (SHELL_SUCCESS
);
100 // if the destination file existed check response and possibly prompt user
102 if (ShellFileExists(Dest
) == EFI_SUCCESS
) {
103 if (Response
== NULL
&& !SilentMode
) {
104 Status
= ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel
, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR
), gShellLevel2HiiHandle
, &Response
);
107 // possibly return based on response
110 switch (*(SHELL_PROMPT_RESPONSE
*)Response
) {
111 case ShellPromptResponseNo
:
113 // return success here so we dont stop the process
115 return (SHELL_SUCCESS
);
116 case ShellPromptResponseCancel
:
119 // indicate to stop everything
121 return (SHELL_ABORTED
);
122 case ShellPromptResponseAll
:
124 case ShellPromptResponseYes
:
127 return SHELL_ABORTED
;
132 if (ShellIsDirectory(Source
) == EFI_SUCCESS
) {
133 Status
= ShellCreateDirectory(Dest
, &DestHandle
);
134 if (EFI_ERROR(Status
)) {
135 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DEST_DIR_FAIL
), gShellLevel2HiiHandle
, L
"cp", Dest
);
136 return (SHELL_ACCESS_DENIED
);
140 // Now copy all the files under the directory...
144 StrnCatGrow(&TempName
, &Size
, Source
, 0);
145 StrnCatGrow(&TempName
, &Size
, L
"\\*", 0);
146 if (TempName
!= NULL
) {
147 ShellOpenFileMetaArg((CHAR16
*)TempName
, EFI_FILE_MODE_READ
, &List
);
148 *TempName
= CHAR_NULL
;
149 StrnCatGrow(&TempName
, &Size
, Dest
, 0);
150 StrnCatGrow(&TempName
, &Size
, L
"\\", 0);
151 ShellStatus
= ValidateAndCopyFiles(List
, TempName
, SilentMode
, TRUE
, Resp
);
152 ShellCloseFileMetaArg(&List
);
153 SHELL_FREE_NON_NULL(TempName
);
157 Status
= ShellDeleteFileByName(Dest
);
160 // open file with create enabled
162 Status
= ShellOpenFileByName(Dest
, &DestHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_CREATE
, 0);
163 if (EFI_ERROR(Status
)) {
164 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL
), gShellLevel2HiiHandle
, L
"cp", Dest
);
165 return (SHELL_ACCESS_DENIED
);
171 Status
= ShellOpenFileByName(Source
, &SourceHandle
, EFI_FILE_MODE_READ
, 0);
172 ASSERT_EFI_ERROR(Status
);
175 //get file size of source file and freespace available on destination volume
177 ShellGetFileSize(SourceHandle
, &SourceFileSize
);
178 ShellGetFileSize(DestHandle
, &DestFileSize
);
181 //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space
183 if(DestFileSize
< SourceFileSize
){
184 SourceFileSize
-= DestFileSize
;
190 //get the system volume info to check the free space
192 DestVolumeFP
= ConvertShellHandleToEfiFileProtocol(DestHandle
);
193 DestVolumeInfo
= NULL
;
194 DestVolumeInfoSize
= 0;
195 Status
= DestVolumeFP
->GetInfo(
197 &gEfiFileSystemInfoGuid
,
202 if (Status
== EFI_BUFFER_TOO_SMALL
) {
203 DestVolumeInfo
= AllocateZeroPool(DestVolumeInfoSize
);
204 Status
= DestVolumeFP
->GetInfo(
206 &gEfiFileSystemInfoGuid
,
213 //check if enough space available on destination drive to complete copy
215 if (DestVolumeInfo
!= NULL
&& (DestVolumeInfo
->FreeSpace
< SourceFileSize
)) {
217 //not enough space on destination directory to copy file
219 SHELL_FREE_NON_NULL(DestVolumeInfo
);
220 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_CPY_FAIL
), gShellLevel2HiiHandle
, L
"cp");
221 return(SHELL_VOLUME_FULL
);
224 // copy data between files
226 Buffer
= AllocateZeroPool(ReadSize
);
227 ASSERT(Buffer
!= NULL
);
228 while (ReadSize
== PcdGet32(PcdShellFileOperationSize
) && !EFI_ERROR(Status
)) {
229 Status
= ShellReadFile(SourceHandle
, &ReadSize
, Buffer
);
230 if (!EFI_ERROR(Status
)) {
231 Status
= ShellWriteFile(DestHandle
, &ReadSize
, Buffer
);
232 if (EFI_ERROR(Status
)) {
233 ShellStatus
= (SHELL_STATUS
) (Status
& (~MAX_BIT
));
234 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR
), gShellLevel2HiiHandle
, L
"cp", Dest
);
238 ShellStatus
= (SHELL_STATUS
) (Status
& (~MAX_BIT
));
239 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_CPY_READ_ERROR
), gShellLevel2HiiHandle
, L
"cp", Source
);
244 SHELL_FREE_NON_NULL(DestVolumeInfo
);
250 if (DestHandle
!= NULL
) {
251 ShellCloseFile(&DestHandle
);
254 if (SourceHandle
!= NULL
) {
255 ShellCloseFile(&SourceHandle
);
266 function to take a list of files to copy and a destination location and do
267 the verification and copying of those files to that location. This function
268 will report any errors to the user and halt.
270 The key is to have this function called ONLY once. this allows for the parameter
271 verification to happen correctly.
273 @param[in] FileList A LIST_ENTRY* based list of files to move.
274 @param[in] DestDir The destination location.
275 @param[in] SilentMode TRUE to eliminate screen output.
276 @param[in] RecursiveMode TRUE to copy directories.
277 @param[in] Resp The response to the overwrite query (if always).
279 @retval SHELL_SUCCESS the files were all moved.
280 @retval SHELL_INVALID_PARAMETER a parameter was invalid
281 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
282 @retval SHELL_WRITE_PROTECTED the destination was write protected
283 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
287 ValidateAndCopyFiles(
288 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
289 IN CONST CHAR16
*DestDir
,
290 IN BOOLEAN SilentMode
,
291 IN BOOLEAN RecursiveMode
,
297 CONST EFI_SHELL_FILE_INFO
*Node
;
298 SHELL_STATUS ShellStatus
;
305 CHAR16
*CleanFilePathStr
;
314 ShellStatus
= SHELL_SUCCESS
;
316 Cwd
= ShellGetCurrentDir(NULL
);
317 CleanFilePathStr
= NULL
;
319 ASSERT(FileList
!= NULL
);
320 ASSERT(DestDir
!= NULL
);
323 Status
= ShellLevel2StripQuotes (DestDir
, &CleanFilePathStr
);
324 if (EFI_ERROR (Status
)) {
325 if (Status
== EFI_OUT_OF_RESOURCES
) {
326 return SHELL_OUT_OF_RESOURCES
;
328 return SHELL_INVALID_PARAMETER
;
332 ASSERT (CleanFilePathStr
!= NULL
);
335 // If we are trying to copy multiple files... make sure we got a directory for the target...
337 if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr
)) && FileList
->Link
.ForwardLink
!= FileList
->Link
.BackLink
) {
339 // Error for destination not a directory
341 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NOT_DIR
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
342 FreePool (CleanFilePathStr
);
343 return (SHELL_INVALID_PARAMETER
);
345 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
346 ; !IsNull(&FileList
->Link
, &Node
->Link
)
347 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
350 // skip the directory traversing stuff...
352 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
356 NewSize
= StrSize(CleanFilePathStr
);
357 NewSize
+= StrSize(Node
->FullName
);
358 NewSize
+= (Cwd
== NULL
)? 0 : StrSize(Cwd
);
359 if (NewSize
> PathSize
) {
364 // Make sure got -r if required
366 if (!RecursiveMode
&& !EFI_ERROR(ShellIsDirectory(Node
->FullName
))) {
367 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DIR_REQ
), gShellLevel2HiiHandle
, L
"cp");
368 FreePool (CleanFilePathStr
);
369 return (SHELL_INVALID_PARAMETER
);
373 // make sure got dest as dir if needed
375 if (!EFI_ERROR(ShellIsDirectory(Node
->FullName
)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr
))) {
377 // Error for destination not a directory
379 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NOT_DIR
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
380 FreePool (CleanFilePathStr
);
381 return (SHELL_INVALID_PARAMETER
);
385 HiiOutput
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_CP_OUTPUT
), NULL
);
386 HiiResultOk
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_GEN_RES_OK
), NULL
);
387 DestPath
= AllocateZeroPool(PathSize
);
389 if (DestPath
== NULL
|| HiiOutput
== NULL
|| HiiResultOk
== NULL
) {
390 SHELL_FREE_NON_NULL(DestPath
);
391 SHELL_FREE_NON_NULL(HiiOutput
);
392 SHELL_FREE_NON_NULL(HiiResultOk
);
393 FreePool (CleanFilePathStr
);
394 return (SHELL_OUT_OF_RESOURCES
);
398 // Go through the list of files to copy...
400 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
401 ; !IsNull(&FileList
->Link
, &Node
->Link
)
402 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
404 if (ShellGetExecutionBreakFlag()) {
407 ASSERT(Node
->FileName
!= NULL
);
408 ASSERT(Node
->FullName
!= NULL
);
411 // skip the directory traversing stuff...
413 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
417 if (FileList
->Link
.ForwardLink
== FileList
->Link
.BackLink
// 1 item
418 && EFI_ERROR(ShellIsDirectory(CleanFilePathStr
)) // not an existing directory
420 if (StrStr(CleanFilePathStr
, L
":") == NULL
) {
422 // simple copy of a single file
425 StrnCpy(DestPath
, Cwd
, PathSize
/sizeof(CHAR16
)-1);
427 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_DIR_NF
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
428 FreePool (CleanFilePathStr
);
429 return (SHELL_INVALID_PARAMETER
);
431 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && CleanFilePathStr
[0] != L
'\\') {
432 StrnCat(DestPath
, L
"\\", PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
433 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && CleanFilePathStr
[0] == L
'\\') {
434 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
436 StrnCat(DestPath
, CleanFilePathStr
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
438 StrnCpy(DestPath
, CleanFilePathStr
, PathSize
/sizeof(CHAR16
) -1);
442 // we have multiple files or a directory in the DestDir
446 // Check for leading slash
448 if (CleanFilePathStr
[0] == L
'\\') {
450 // Copy to the root of CWD
453 StrnCpy(DestPath
, Cwd
, PathSize
/sizeof(CHAR16
) -1);
455 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_DIR_NF
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
456 FreePool(CleanFilePathStr
);
457 return (SHELL_INVALID_PARAMETER
);
459 while (PathRemoveLastItem(DestPath
));
460 StrnCat(DestPath
, CleanFilePathStr
+1, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
461 StrnCat(DestPath
, Node
->FileName
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
462 } else if (StrStr(CleanFilePathStr
, L
":") == NULL
) {
464 StrnCpy(DestPath
, Cwd
, PathSize
/sizeof(CHAR16
) -1);
466 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_DIR_NF
), gShellLevel2HiiHandle
, L
"cp", CleanFilePathStr
);
467 FreePool(CleanFilePathStr
);
468 return (SHELL_INVALID_PARAMETER
);
470 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && CleanFilePathStr
[0] != L
'\\') {
471 StrnCat(DestPath
, L
"\\", PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
472 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && CleanFilePathStr
[0] == L
'\\') {
473 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
475 StrnCat(DestPath
, CleanFilePathStr
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
476 if (CleanFilePathStr
[StrLen(CleanFilePathStr
)-1] != L
'\\' && Node
->FileName
[0] != L
'\\') {
477 StrnCat(DestPath
, L
"\\", PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
478 } else if (CleanFilePathStr
[StrLen(CleanFilePathStr
)-1] == L
'\\' && Node
->FileName
[0] == L
'\\') {
479 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
481 StrnCat(DestPath
, Node
->FileName
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
484 StrnCpy(DestPath
, CleanFilePathStr
, PathSize
/sizeof(CHAR16
) -1);
485 if (CleanFilePathStr
[StrLen(CleanFilePathStr
)-1] != L
'\\' && Node
->FileName
[0] != L
'\\') {
486 StrnCat(DestPath
, L
"\\", PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
487 } else if (CleanFilePathStr
[StrLen(CleanFilePathStr
)-1] == L
'\\' && Node
->FileName
[0] == L
'\\') {
488 ((CHAR16
*)CleanFilePathStr
)[StrLen(CleanFilePathStr
)-1] = CHAR_NULL
;
490 StrnCat(DestPath
, Node
->FileName
, PathSize
/sizeof(CHAR16
) - StrLen(DestPath
) -1);
495 // Make sure the path exists
497 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath
))) {
498 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DIR_WNF
), gShellLevel2HiiHandle
, L
"cp", DestPath
);
499 ShellStatus
= SHELL_DEVICE_ERROR
;
503 if ( !EFI_ERROR(ShellIsDirectory(Node
->FullName
))
504 && !EFI_ERROR(ShellIsDirectory(DestPath
))
505 && StrniCmp(Node
->FullName
, DestPath
, StrLen(DestPath
)) == NULL
507 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_PARENT
), gShellLevel2HiiHandle
, L
"cp");
508 ShellStatus
= SHELL_INVALID_PARAMETER
;
511 if (StringNoCaseCompare(&Node
->FullName
, &DestPath
) == 0) {
512 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_SAME
), gShellLevel2HiiHandle
, L
"cp");
513 ShellStatus
= SHELL_INVALID_PARAMETER
;
517 if ((StrniCmp(Node
->FullName
, DestPath
, StrLen(Node
->FullName
)) == 0)
518 && (DestPath
[StrLen(Node
->FullName
)] == CHAR_NULL
|| DestPath
[StrLen(Node
->FullName
)] == L
'\\')
520 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_SAME
), gShellLevel2HiiHandle
, L
"cp");
521 ShellStatus
= SHELL_INVALID_PARAMETER
;
525 PathCleanUpDirectories(DestPath
);
528 ShellPrintEx(-1, -1, HiiOutput
, Node
->FullName
, DestPath
);
532 // copy single file...
534 ShellStatus
= CopySingleFile(Node
->FullName
, DestPath
, &Response
, SilentMode
);
535 if (ShellStatus
!= SHELL_SUCCESS
) {
539 if (ShellStatus
== SHELL_SUCCESS
&& Resp
== NULL
) {
540 ShellPrintEx(-1, -1, L
"%s", HiiResultOk
);
543 SHELL_FREE_NON_NULL(DestPath
);
544 SHELL_FREE_NON_NULL(HiiOutput
);
545 SHELL_FREE_NON_NULL(HiiResultOk
);
546 SHELL_FREE_NON_NULL(CleanFilePathStr
);
548 SHELL_FREE_NON_NULL(Response
);
551 return (ShellStatus
);
556 Validate and if successful copy all the files from the list into
557 destination directory.
559 @param[in] FileList The list of files to copy.
560 @param[in] DestDir The directory to copy files to.
561 @param[in] SilentMode TRUE to eliminate screen output.
562 @param[in] RecursiveMode TRUE to copy directories.
564 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
565 @retval SHELL_SUCCESS The operation was successful.
569 ProcessValidateAndCopyFiles(
570 IN EFI_SHELL_FILE_INFO
*FileList
,
571 IN CONST CHAR16
*DestDir
,
572 IN BOOLEAN SilentMode
,
573 IN BOOLEAN RecursiveMode
576 SHELL_STATUS ShellStatus
;
577 EFI_SHELL_FILE_INFO
*List
;
578 EFI_FILE_INFO
*FileInfo
;
585 ShellOpenFileMetaArg((CHAR16
*)DestDir
, EFI_FILE_MODE_READ
, &List
);
586 if (List
!= NULL
&& List
->Link
.ForwardLink
!= List
->Link
.BackLink
) {
587 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_MARG_ERROR
), gShellLevel2HiiHandle
, L
"cp", DestDir
);
588 ShellStatus
= SHELL_INVALID_PARAMETER
;
589 ShellCloseFileMetaArg(&List
);
590 } else if (List
!= NULL
) {
591 ASSERT(((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
) != NULL
);
592 ASSERT(((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
)->FullName
!= NULL
);
593 FileInfo
= gEfiShellProtocol
->GetFileInfo(((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
)->Handle
);
594 ASSERT(FileInfo
!= NULL
);
595 StrnCatGrow(&FullName
, NULL
, ((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
)->FullName
, 0);
596 ShellCloseFileMetaArg(&List
);
597 if ((FileInfo
->Attribute
& EFI_FILE_READ_ONLY
) == 0) {
598 ShellStatus
= ValidateAndCopyFiles(FileList
, FullName
, SilentMode
, RecursiveMode
, NULL
);
600 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DEST_ERROR
), gShellLevel2HiiHandle
, L
"cp");
601 ShellStatus
= SHELL_ACCESS_DENIED
;
604 ShellCloseFileMetaArg(&List
);
605 ShellStatus
= ValidateAndCopyFiles(FileList
, DestDir
, SilentMode
, RecursiveMode
, NULL
);
608 SHELL_FREE_NON_NULL(FileInfo
);
609 SHELL_FREE_NON_NULL(FullName
);
610 return (ShellStatus
);
613 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
620 Function for 'cp' command.
622 @param[in] ImageHandle Handle to the Image (NULL if Internal).
623 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
628 IN EFI_HANDLE ImageHandle
,
629 IN EFI_SYSTEM_TABLE
*SystemTable
634 CHAR16
*ProblemParam
;
635 SHELL_STATUS ShellStatus
;
638 EFI_SHELL_FILE_INFO
*FileList
;
640 BOOLEAN RecursiveMode
;
644 ShellStatus
= SHELL_SUCCESS
;
649 // initialize the shell lib (we must be in non-auto-init...)
651 Status
= ShellInitialize();
652 ASSERT_EFI_ERROR(Status
);
654 Status
= CommandInit();
655 ASSERT_EFI_ERROR(Status
);
658 // parse the command line
660 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
661 if (EFI_ERROR(Status
)) {
662 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
663 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, L
"cp", ProblemParam
);
664 FreePool(ProblemParam
);
665 ShellStatus
= SHELL_INVALID_PARAMETER
;
673 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
678 // Initialize SilentMode and RecursiveMode
680 if (gEfiShellProtocol
->BatchIsActive()) {
683 SilentMode
= ShellCommandLineGetFlag(Package
, L
"-q");
685 RecursiveMode
= ShellCommandLineGetFlag(Package
, L
"-r");
687 switch (ParamCount
= ShellCommandLineGetCount(Package
)) {
691 // we have insufficient parameters
693 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
, L
"cp");
694 ShellStatus
= SHELL_INVALID_PARAMETER
;
698 // must have valid CWD for single parameter...
700 Cwd
= ShellGetCurrentDir(NULL
);
702 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
, L
"cp");
703 ShellStatus
= SHELL_INVALID_PARAMETER
;
705 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, 1), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
706 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
707 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, L
"cp", ShellCommandLineGetRawValue(Package
, 1));
708 ShellStatus
= SHELL_NOT_FOUND
;
710 ShellStatus
= ProcessValidateAndCopyFiles(FileList
, Cwd
, SilentMode
, RecursiveMode
);
717 // Make a big list of all the files...
719 for (ParamCount
--, LoopCounter
= 1 ; LoopCounter
< ParamCount
&& ShellStatus
== SHELL_SUCCESS
; LoopCounter
++) {
720 if (ShellGetExecutionBreakFlag()) {
723 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, LoopCounter
), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
724 if (EFI_ERROR(Status
) || FileList
== NULL
|| IsListEmpty(&FileList
->Link
)) {
725 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, L
"cp", ShellCommandLineGetRawValue(Package
, LoopCounter
));
726 ShellStatus
= SHELL_NOT_FOUND
;
729 if (ShellStatus
!= SHELL_SUCCESS
) {
730 Status
= ShellCloseFileMetaArg(&FileList
);
733 // now copy them all...
735 if (FileList
!= NULL
&& !IsListEmpty(&FileList
->Link
)) {
736 ShellStatus
= ProcessValidateAndCopyFiles(FileList
, PathCleanUpDirectories((CHAR16
*)ShellCommandLineGetRawValue(Package
, ParamCount
)), SilentMode
, RecursiveMode
);
737 Status
= ShellCloseFileMetaArg(&FileList
);
738 if (EFI_ERROR(Status
) && ShellStatus
== SHELL_SUCCESS
) {
739 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_FILE
), gShellLevel2HiiHandle
, L
"cp", ShellCommandLineGetRawValue(Package
, ParamCount
), ShellStatus
|MAX_BIT
);
740 ShellStatus
= SHELL_ACCESS_DENIED
;
745 } // switch on parameter count
747 if (FileList
!= NULL
) {
748 ShellCloseFileMetaArg(&FileList
);
752 // free the command line package
754 ShellCommandLineFreeVarList (Package
);
757 if (ShellGetExecutionBreakFlag()) {
758 return (SHELL_ABORTED
);
761 return (ShellStatus
);