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