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