2 Main file for cp shell level 2 function.
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "UefiShellLevel2CommandsLib.h"
17 // this is later in the file.
21 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
22 IN CONST CHAR16
*DestDir
,
23 IN BOOLEAN SilentMode
,
24 IN BOOLEAN RecursiveMode
,
29 Function to Copy one file to another location
31 If the destination exists the user will be prompted and the result put into *resp
33 @param[in] Source pointer to source file name
34 @param[in] Dest pointer to destination file name
35 @param[out] Resp pointer to response from question. Pass back on looped calling
36 @param[in] SilentMode whether to run in quiet mode or not
38 @retval SHELL_SUCCESS The source file was copied to the destination
43 IN CONST CHAR16
*Source
,
44 IN CONST CHAR16
*Dest
,
51 SHELL_FILE_HANDLE SourceHandle
;
52 SHELL_FILE_HANDLE DestHandle
;
57 EFI_SHELL_FILE_INFO
*List
;
58 SHELL_STATUS ShellStatus
;
68 ReadSize
= PcdGet16(PcdShellFileOperationSize
);
69 // Why bother copying a file to itself
70 if (StrCmp(Source
, Dest
) == 0) {
71 return (SHELL_SUCCESS
);
75 // Open destination file without create
77 Status
= ShellOpenFileByName(Dest
, &DestHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
, 0);
82 if (DestHandle
!= NULL
) {
83 ShellCloseFile(&DestHandle
);
88 // if the destination file existed check response and possibly prompt user
90 if (!EFI_ERROR(Status
)) {
91 if (Response
== NULL
&& !SilentMode
) {
92 Status
= ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel
, STRING_TOKEN (STR_CP_PROMPT
), gShellLevel2HiiHandle
, &Response
);
95 // possibly return based on response
98 switch (*(SHELL_PROMPT_RESPONSE
*)Response
) {
99 case ShellPromptResponseNo
:
101 // return success here so we dont stop the process
103 return (SHELL_SUCCESS
);
104 case ShellPromptResponseCancel
:
107 // indicate to stop everything
109 return (SHELL_ABORTED
);
110 case ShellPromptResponseAll
:
112 case ShellPromptResponseYes
:
118 if (ShellIsDirectory(Source
) == EFI_SUCCESS
) {
119 Status
= ShellCreateDirectory(Dest
, &DestHandle
);
120 if (EFI_ERROR(Status
)) {
121 return (SHELL_ACCESS_DENIED
);
125 // Now copy all the files under the directory...
129 StrnCatGrow(&TempName
, &Size
, Source
, 0);
130 StrnCatGrow(&TempName
, &Size
, L
"\\*", 0);
131 ShellOpenFileMetaArg((CHAR16
*)TempName
, EFI_FILE_MODE_READ
, &List
);
133 StrnCatGrow(&TempName
, &Size
, Dest
, 0);
134 StrnCatGrow(&TempName
, &Size
, L
"\\", 0);
135 ShellStatus
= ValidateAndCopyFiles(List
, TempName
, SilentMode
, TRUE
, Resp
);
136 ShellCloseFileMetaArg(&List
);
141 // open file with create enabled
143 Status
= ShellOpenFileByName(Dest
, &DestHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_CREATE
, 0);
144 if (EFI_ERROR(Status
)) {
145 return (SHELL_ACCESS_DENIED
);
151 Status
= ShellOpenFileByName(Source
, &SourceHandle
, EFI_FILE_MODE_READ
, 0);
152 ASSERT_EFI_ERROR(Status
);
155 // copy data between files
157 Buffer
= AllocateZeroPool(ReadSize
);
158 ASSERT(Buffer
!= NULL
);
159 while (ReadSize
== PcdGet16(PcdShellFileOperationSize
) && !EFI_ERROR(Status
)) {
160 Status
= ShellReadFile(SourceHandle
, &ReadSize
, Buffer
);
161 ASSERT_EFI_ERROR(Status
);
162 Status
= ShellWriteFile(DestHandle
, &ReadSize
, Buffer
);
169 if (DestHandle
!= NULL
) {
170 ShellCloseFile(&DestHandle
);
173 if (SourceHandle
!= NULL
) {
174 ShellCloseFile(&SourceHandle
);
181 return (SHELL_SUCCESS
);
185 function to take a list of files to copy and a destination location and do
186 the verification and copying of those files to that location. This function
187 will report any errors to the user and halt.
189 The key is to have this function called ONLY once. this allows for the parameter
190 verification to happen correctly.
192 @param[in] FileList A LIST_ENTRY* based list of files to move
193 @param[in] DestDir the destination location
195 @retval SHELL_SUCCESS the files were all moved.
196 @retval SHELL_INVALID_PARAMETER a parameter was invalid
197 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
198 @retval SHELL_WRITE_PROTECTED the destination was write protected
199 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
203 ValidateAndCopyFiles(
204 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
205 IN CONST CHAR16
*DestDir
,
206 IN BOOLEAN SilentMode
,
207 IN BOOLEAN RecursiveMode
,
213 CONST EFI_SHELL_FILE_INFO
*Node
;
214 SHELL_STATUS ShellStatus
;
219 CONST CHAR16
*TempLocation
;
229 ShellStatus
= SHELL_SUCCESS
;
231 Cwd
= ShellGetCurrentDir(NULL
);
233 ASSERT(FileList
!= NULL
);
234 ASSERT(DestDir
!= NULL
);
237 // If we are trying to copy multiple files... make sure we got a directory for the target...
239 if (EFI_ERROR(ShellIsDirectory(DestDir
)) && FileList
->Link
.ForwardLink
!= FileList
->Link
.BackLink
) {
241 // Error for destination not a directory
243 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NOT_DIR
), gShellLevel2HiiHandle
, DestDir
);
244 return (SHELL_INVALID_PARAMETER
);
246 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
247 ; !IsNull(&FileList
->Link
, &Node
->Link
)
248 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
251 // skip the directory traversing stuff...
253 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
257 NewSize
= StrSize(DestDir
);
258 NewSize
+= StrSize(Node
->FileName
);
259 NewSize
+= StrSize(Cwd
);
260 if (NewSize
> PathLen
) {
265 // Make sure got -r if required
267 if (!RecursiveMode
&& !EFI_ERROR(ShellIsDirectory(Node
->FullName
))) {
268 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DIR_REQ
), gShellLevel2HiiHandle
);
269 return (SHELL_INVALID_PARAMETER
);
273 // make sure got dest as dir if needed
275 if (!EFI_ERROR(ShellIsDirectory(Node
->FullName
)) && EFI_ERROR(ShellIsDirectory(DestDir
))) {
277 // Error for destination not a directory
279 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NOT_DIR
), gShellLevel2HiiHandle
, DestDir
);
280 return (SHELL_INVALID_PARAMETER
);
284 HiiOutput
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_CP_OUTPUT
), NULL
);
285 HiiResultOk
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_GEN_RES_OK
), NULL
);
286 DestPath
= AllocatePool(PathLen
);
289 // Go through the list of files to copy...
291 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
292 ; !IsNull(&FileList
->Link
, &Node
->Link
)
293 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
295 if (ShellGetExecutionBreakFlag()) {
298 ASSERT(Node
->FileName
!= NULL
);
299 ASSERT(Node
->FullName
!= NULL
);
302 // skip the directory traversing stuff...
304 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
308 if (FileList
->Link
.ForwardLink
== FileList
->Link
.BackLink
// 1 item
309 && EFI_ERROR(ShellIsDirectory(DestDir
)) // not an existing directory
311 ASSERT(StrStr(DestDir
, L
":") == NULL
);
313 // simple copy of a single file
315 StrCpy(DestPath
, Cwd
);
316 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && DestDir
[0] != L
'\\') {
317 StrCat(DestPath
, L
"\\");
318 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && DestDir
[0] == L
'\\') {
319 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
321 StrCat(DestPath
, DestDir
);
324 // we have multiple files or a directory in the DestDir
326 if (StrStr(DestDir
, L
":") == NULL
) {
327 StrCpy(DestPath
, Cwd
);
328 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && DestDir
[0] != L
'\\') {
329 StrCat(DestPath
, L
"\\");
330 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && DestDir
[0] == L
'\\') {
331 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
333 StrCat(DestPath
, DestDir
);
334 if (DestDir
[StrLen(DestDir
)-1] != L
'\\' && Node
->FileName
[0] != L
'\\') {
335 StrCat(DestPath
, L
"\\");
336 } else if (DestDir
[StrLen(DestDir
)-1] == L
'\\' && Node
->FileName
[0] == L
'\\') {
337 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
339 StrCat(DestPath
, Node
->FileName
);
342 StrCpy(DestPath
, DestDir
);
343 if (DestDir
[StrLen(DestDir
)-1] != L
'\\' && Node
->FileName
[0] != L
'\\') {
344 StrCat(DestPath
, L
"\\");
345 } else if (DestDir
[StrLen(DestDir
)-1] == L
'\\' && Node
->FileName
[0] == L
'\\') {
346 ((CHAR16
*)DestDir
)[StrLen(DestDir
)-1] = CHAR_NULL
;
348 StrCat(DestPath
, Node
->FileName
);
353 // Make sure the path exists
355 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath
))) {
356 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DIR_WNF
), gShellLevel2HiiHandle
);
357 ShellStatus
= SHELL_DEVICE_ERROR
;
361 if ( !EFI_ERROR(ShellIsDirectory(Node
->FullName
))
362 && !EFI_ERROR(ShellIsDirectory(DestPath
))
363 && StrniCmp(Node
->FullName
, DestPath
, StrLen(DestPath
)) == NULL
365 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_PARENT
), gShellLevel2HiiHandle
);
366 ShellStatus
= SHELL_INVALID_PARAMETER
;
369 if (StringNoCaseCompare(&Node
->FullName
, &DestPath
) == 0) {
370 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_SAME
), gShellLevel2HiiHandle
);
371 ShellStatus
= SHELL_INVALID_PARAMETER
;
375 if ((TempLocation
= StrniCmp(Node
->FullName
, DestPath
, StrLen(Node
->FullName
))) == 0
376 && (DestPath
[StrLen(Node
->FullName
)] == CHAR_NULL
|| DestPath
[StrLen(Node
->FullName
)] == L
'\\')
378 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_SD_SAME
), gShellLevel2HiiHandle
);
379 ShellStatus
= SHELL_INVALID_PARAMETER
;
385 ShellPrintEx(-1, -1, HiiOutput
, Node
->FullName
, DestPath
);
388 // copy single file...
390 ShellStatus
= CopySingleFile(Node
->FullName
, DestPath
, &Response
, SilentMode
);
391 if (ShellStatus
!= SHELL_SUCCESS
) {
395 if (ShellStatus
== SHELL_SUCCESS
&& Resp
== NULL
) {
396 ShellPrintEx(-1, -1, L
"%s", HiiResultOk
);
399 SHELL_FREE_NON_NULL(DestPath
);
400 SHELL_FREE_NON_NULL(HiiOutput
);
401 SHELL_FREE_NON_NULL(HiiResultOk
);
403 SHELL_FREE_NON_NULL(Response
);
406 return (ShellStatus
);
411 ProcessValidateAndCopyFiles(
412 IN EFI_SHELL_FILE_INFO
*FileList
,
413 IN CONST CHAR16
*DestDir
,
414 IN BOOLEAN SilentMode
,
415 IN BOOLEAN RecursiveMode
418 SHELL_STATUS ShellStatus
;
419 EFI_SHELL_FILE_INFO
*List
;
421 EFI_FILE_INFO
*FileInfo
;
425 Status
= ShellOpenFileMetaArg((CHAR16
*)DestDir
, EFI_FILE_MODE_READ
, &List
);
426 if (List
!= NULL
&& List
->Link
.ForwardLink
!= List
->Link
.BackLink
) {
427 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_MARG_ERROR
), gShellLevel2HiiHandle
, DestDir
);
428 ShellStatus
= SHELL_INVALID_PARAMETER
;
429 ShellCloseFileMetaArg(&List
);
430 } else if (List
!= NULL
) {
431 ASSERT(List
!= NULL
);
432 ASSERT(((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
) != NULL
);
433 ASSERT(((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
)->FullName
!= NULL
);
435 FileInfo
= gEfiShellProtocol
->GetFileInfo(((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
)->Handle
);
436 ASSERT(FileInfo
!= NULL
);
437 if ((FileInfo
->Attribute
& EFI_FILE_READ_ONLY
) == 0) {
438 ShellStatus
= ValidateAndCopyFiles(FileList
, ((EFI_SHELL_FILE_INFO
*)List
->Link
.ForwardLink
)->FullName
, SilentMode
, RecursiveMode
, NULL
);
440 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_CP_DEST_ERROR
), gShellLevel2HiiHandle
);
441 ShellStatus
= SHELL_ACCESS_DENIED
;
443 SHELL_FREE_NON_NULL(FileInfo
);
444 ShellCloseFileMetaArg(&List
);
446 ShellStatus
= ValidateAndCopyFiles(FileList
, DestDir
, SilentMode
, RecursiveMode
, NULL
);
449 return (ShellStatus
);
452 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
459 Function for 'cp' command.
461 @param[in] ImageHandle Handle to the Image (NULL if Internal).
462 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
467 IN EFI_HANDLE ImageHandle
,
468 IN EFI_SYSTEM_TABLE
*SystemTable
473 CHAR16
*ProblemParam
;
474 SHELL_STATUS ShellStatus
;
477 EFI_SHELL_FILE_INFO
*FileList
;
479 BOOLEAN RecursiveMode
;
483 ShellStatus
= SHELL_SUCCESS
;
488 // initialize the shell lib (we must be in non-auto-init...)
490 Status
= ShellInitialize();
491 ASSERT_EFI_ERROR(Status
);
493 Status
= CommandInit();
494 ASSERT_EFI_ERROR(Status
);
497 // parse the command line
499 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
500 if (EFI_ERROR(Status
)) {
501 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
502 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, ProblemParam
);
503 FreePool(ProblemParam
);
504 ShellStatus
= SHELL_INVALID_PARAMETER
;
512 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
517 // Initialize SilentMode and RecursiveMode
519 if (gEfiShellProtocol
->BatchIsActive()) {
522 SilentMode
= ShellCommandLineGetFlag(Package
, L
"-q");
524 RecursiveMode
= ShellCommandLineGetFlag(Package
, L
"-r");
526 switch (ParamCount
= ShellCommandLineGetCount(Package
)) {
530 // we have insufficient parameters
532 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
);
533 ShellStatus
= SHELL_INVALID_PARAMETER
;
537 // must have valid CWD for single parameter...
539 Cwd
= ShellGetCurrentDir(NULL
);
541 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
542 ShellStatus
= SHELL_INVALID_PARAMETER
;
544 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, 1), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
545 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
546 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1));
547 ShellStatus
= SHELL_NOT_FOUND
;
549 ShellStatus
= ProcessValidateAndCopyFiles(FileList
, Cwd
, SilentMode
, RecursiveMode
);
556 // Make a big list of all the files...
558 for (ParamCount
--, LoopCounter
= 1 ; LoopCounter
< ParamCount
&& ShellStatus
== SHELL_SUCCESS
; LoopCounter
++) {
559 if (ShellGetExecutionBreakFlag()) {
562 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, LoopCounter
), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
563 if (EFI_ERROR(Status
) || FileList
== NULL
|| IsListEmpty(&FileList
->Link
)) {
564 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1));
565 ShellStatus
= SHELL_NOT_FOUND
;
569 // now copy them all...
571 if (FileList
!= NULL
&& !IsListEmpty(&FileList
->Link
)) {
572 ShellStatus
= ProcessValidateAndCopyFiles(FileList
, ShellCommandCleanPath((CHAR16
*)ShellCommandLineGetRawValue(Package
, ParamCount
)), SilentMode
, RecursiveMode
);
573 Status
= ShellCloseFileMetaArg(&FileList
);
574 if (EFI_ERROR(Status
) && ShellStatus
== SHELL_SUCCESS
) {
575 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_FILE
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1), ShellStatus
|MAX_BIT
);
576 ShellStatus
= SHELL_ACCESS_DENIED
;
581 } // switch on parameter count
583 if (FileList
!= NULL
) {
584 ShellCloseFileMetaArg(&FileList
);
588 // free the command line package
590 ShellCommandLineFreeVarList (Package
);
593 if (ShellGetExecutionBreakFlag()) {
594 return (SHELL_ABORTED
);
597 return (ShellStatus
);