]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
Add code to check whether the pointer 'CorrectedPath' and 'FullPath' are NULL before...
[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 if (!EFI_ERROR(Status)) {
228 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);
229 if (EFI_ERROR(Status)) {
230 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
231 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, Dest);
232 break;
233 }
234 } else {
235 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
236 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, Source);
237 break;
238 }
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 UINTN NewSize;
301
302 if (Resp == NULL) {
303 Response = NULL;
304 } else {
305 Response = *Resp;
306 }
307
308 DestPath = NULL;
309 ShellStatus = SHELL_SUCCESS;
310 PathLen = 0;
311 Cwd = ShellGetCurrentDir(NULL);
312
313 ASSERT(FileList != NULL);
314 ASSERT(DestDir != NULL);
315
316 //
317 // If we are trying to copy multiple files... make sure we got a directory for the target...
318 //
319 if (EFI_ERROR(ShellIsDirectory(DestDir)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {
320 //
321 // Error for destination not a directory
322 //
323 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir);
324 return (SHELL_INVALID_PARAMETER);
325 }
326 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
327 ; !IsNull(&FileList->Link, &Node->Link)
328 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
329 ){
330 //
331 // skip the directory traversing stuff...
332 //
333 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
334 continue;
335 }
336
337 NewSize = StrSize(DestDir);
338 NewSize += StrSize(Node->FullName);
339 NewSize += (Cwd == NULL)? 0 : StrSize(Cwd);
340 if (NewSize > PathLen) {
341 PathLen = NewSize;
342 }
343
344 //
345 // Make sure got -r if required
346 //
347 if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) {
348 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle);
349 return (SHELL_INVALID_PARAMETER);
350 }
351
352 //
353 // make sure got dest as dir if needed
354 //
355 if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(DestDir))) {
356 //
357 // Error for destination not a directory
358 //
359 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir);
360 return (SHELL_INVALID_PARAMETER);
361 }
362 }
363
364 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);
365 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
366 DestPath = AllocateZeroPool(PathLen);
367
368 if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) {
369 SHELL_FREE_NON_NULL(DestPath);
370 SHELL_FREE_NON_NULL(HiiOutput);
371 SHELL_FREE_NON_NULL(HiiResultOk);
372 return (SHELL_OUT_OF_RESOURCES);
373 }
374
375 //
376 // Go through the list of files to copy...
377 //
378 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
379 ; !IsNull(&FileList->Link, &Node->Link)
380 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
381 ){
382 if (ShellGetExecutionBreakFlag()) {
383 break;
384 }
385 ASSERT(Node->FileName != NULL);
386 ASSERT(Node->FullName != NULL);
387
388 //
389 // skip the directory traversing stuff...
390 //
391 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
392 continue;
393 }
394
395 if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item
396 && EFI_ERROR(ShellIsDirectory(DestDir)) // not an existing directory
397 ) {
398 if (StrStr(DestDir, L":") == NULL) {
399 //
400 // simple copy of a single file
401 //
402 if (Cwd != NULL) {
403 StrCpy(DestPath, Cwd);
404 } else {
405 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, DestDir);
406 return (SHELL_INVALID_PARAMETER);
407 }
408 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {
409 StrCat(DestPath, L"\\");
410 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {
411 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
412 }
413 StrCat(DestPath, DestDir);
414 } else {
415 StrCpy(DestPath, DestDir);
416 }
417 } else {
418 //
419 // we have multiple files or a directory in the DestDir
420 //
421
422 //
423 // Check for leading slash
424 //
425 if (DestDir[0] == L'\\') {
426 //
427 // Copy to the root of CWD
428 //
429 if (Cwd != NULL) {
430 StrCpy(DestPath, Cwd);
431 } else {
432 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, DestDir);
433 return (SHELL_INVALID_PARAMETER);
434 }
435 while (PathRemoveLastItem(DestPath));
436 StrCat(DestPath, DestDir+1);
437 StrCat(DestPath, Node->FileName);
438 } else if (StrStr(DestDir, L":") == NULL) {
439 if (Cwd != NULL) {
440 StrCpy(DestPath, Cwd);
441 } else {
442 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, DestDir);
443 return (SHELL_INVALID_PARAMETER);
444 }
445 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {
446 StrCat(DestPath, L"\\");
447 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {
448 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
449 }
450 StrCat(DestPath, DestDir);
451 if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') {
452 StrCat(DestPath, L"\\");
453 } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') {
454 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
455 }
456 StrCat(DestPath, Node->FileName);
457
458 } else {
459 StrCpy(DestPath, DestDir);
460 if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') {
461 StrCat(DestPath, L"\\");
462 } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') {
463 ((CHAR16*)DestDir)[StrLen(DestDir)-1] = CHAR_NULL;
464 }
465 StrCat(DestPath, Node->FileName);
466 }
467 }
468
469 //
470 // Make sure the path exists
471 //
472 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {
473 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle);
474 ShellStatus = SHELL_DEVICE_ERROR;
475 break;
476 }
477
478 if ( !EFI_ERROR(ShellIsDirectory(Node->FullName))
479 && !EFI_ERROR(ShellIsDirectory(DestPath))
480 && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL
481 ){
482 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle);
483 ShellStatus = SHELL_INVALID_PARAMETER;
484 break;
485 }
486 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {
487 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle);
488 ShellStatus = SHELL_INVALID_PARAMETER;
489 break;
490 }
491
492 if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0)
493 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')
494 ) {
495 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle);
496 ShellStatus = SHELL_INVALID_PARAMETER;
497 break;
498 }
499
500 PathCleanUpDirectories(DestPath);
501
502 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);
503
504 //
505 // copy single file...
506 //
507 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode);
508 if (ShellStatus != SHELL_SUCCESS) {
509 break;
510 }
511 }
512 if (ShellStatus == SHELL_SUCCESS && Resp == NULL) {
513 ShellPrintEx(-1, -1, L"%s", HiiResultOk);
514 }
515
516 SHELL_FREE_NON_NULL(DestPath);
517 SHELL_FREE_NON_NULL(HiiOutput);
518 SHELL_FREE_NON_NULL(HiiResultOk);
519 if (Resp == NULL) {
520 SHELL_FREE_NON_NULL(Response);
521 }
522
523 return (ShellStatus);
524
525 }
526
527 /**
528 Validate and if successful copy all the files from the list into
529 destination directory.
530
531 @param[in] FileList The list of files to copy.
532 @param[in] DestDir The directory to copy files to.
533 @param[in] SilentMode TRUE to eliminate screen output.
534 @param[in] RecursiveMode TRUE to copy directories.
535
536 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
537 @retval SHELL_SUCCESS The operation was successful.
538 **/
539 SHELL_STATUS
540 EFIAPI
541 ProcessValidateAndCopyFiles(
542 IN EFI_SHELL_FILE_INFO *FileList,
543 IN CONST CHAR16 *DestDir,
544 IN BOOLEAN SilentMode,
545 IN BOOLEAN RecursiveMode
546 )
547 {
548 SHELL_STATUS ShellStatus;
549 EFI_SHELL_FILE_INFO *List;
550 EFI_FILE_INFO *FileInfo;
551 CHAR16 *FullName;
552
553 List = NULL;
554 FullName = NULL;
555 FileInfo = NULL;
556
557 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);
558 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {
559 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir);
560 ShellStatus = SHELL_INVALID_PARAMETER;
561 ShellCloseFileMetaArg(&List);
562 } else if (List != NULL) {
563 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
564 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
565 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
566 ASSERT(FileInfo != NULL);
567 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);
568 ShellCloseFileMetaArg(&List);
569 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
570 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);
571 } else {
572 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle);
573 ShellStatus = SHELL_ACCESS_DENIED;
574 }
575 } else {
576 ShellCloseFileMetaArg(&List);
577 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);
578 }
579
580 SHELL_FREE_NON_NULL(FileInfo);
581 SHELL_FREE_NON_NULL(FullName);
582 return (ShellStatus);
583 }
584
585 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
586 {L"-r", TypeFlag},
587 {L"-q", TypeFlag},
588 {NULL, TypeMax}
589 };
590
591 /**
592 Function for 'cp' command.
593
594 @param[in] ImageHandle Handle to the Image (NULL if Internal).
595 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
596 **/
597 SHELL_STATUS
598 EFIAPI
599 ShellCommandRunCp (
600 IN EFI_HANDLE ImageHandle,
601 IN EFI_SYSTEM_TABLE *SystemTable
602 )
603 {
604 EFI_STATUS Status;
605 LIST_ENTRY *Package;
606 CHAR16 *ProblemParam;
607 SHELL_STATUS ShellStatus;
608 UINTN ParamCount;
609 UINTN LoopCounter;
610 EFI_SHELL_FILE_INFO *FileList;
611 BOOLEAN SilentMode;
612 BOOLEAN RecursiveMode;
613 CONST CHAR16 *Cwd;
614
615 ProblemParam = NULL;
616 ShellStatus = SHELL_SUCCESS;
617 ParamCount = 0;
618 FileList = NULL;
619
620 //
621 // initialize the shell lib (we must be in non-auto-init...)
622 //
623 Status = ShellInitialize();
624 ASSERT_EFI_ERROR(Status);
625
626 Status = CommandInit();
627 ASSERT_EFI_ERROR(Status);
628
629 //
630 // parse the command line
631 //
632 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
633 if (EFI_ERROR(Status)) {
634 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
635 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);
636 FreePool(ProblemParam);
637 ShellStatus = SHELL_INVALID_PARAMETER;
638 } else {
639 ASSERT(FALSE);
640 }
641 } else {
642 //
643 // check for "-?"
644 //
645 if (ShellCommandLineGetFlag(Package, L"-?")) {
646 ASSERT(FALSE);
647 }
648
649 //
650 // Initialize SilentMode and RecursiveMode
651 //
652 if (gEfiShellProtocol->BatchIsActive()) {
653 SilentMode = TRUE;
654 } else {
655 SilentMode = ShellCommandLineGetFlag(Package, L"-q");
656 }
657 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");
658
659 switch (ParamCount = ShellCommandLineGetCount(Package)) {
660 case 0:
661 case 1:
662 //
663 // we have insufficient parameters
664 //
665 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle);
666 ShellStatus = SHELL_INVALID_PARAMETER;
667 break;
668 case 2:
669 //
670 // must have valid CWD for single parameter...
671 //
672 Cwd = ShellGetCurrentDir(NULL);
673 if (Cwd == NULL){
674 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
675 ShellStatus = SHELL_INVALID_PARAMETER;
676 } else {
677 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
678 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
679 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));
680 ShellStatus = SHELL_NOT_FOUND;
681 } else {
682 ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode);
683 }
684 }
685
686 break;
687 default:
688 //
689 // Make a big list of all the files...
690 //
691 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {
692 if (ShellGetExecutionBreakFlag()) {
693 break;
694 }
695 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
696 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {
697 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, LoopCounter));
698 ShellStatus = SHELL_NOT_FOUND;
699 }
700 }
701 if (ShellStatus != SHELL_SUCCESS) {
702 Status = ShellCloseFileMetaArg(&FileList);
703 } else {
704 //
705 // now copy them all...
706 //
707 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
708 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);
709 Status = ShellCloseFileMetaArg(&FileList);
710 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
711 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT);
712 ShellStatus = SHELL_ACCESS_DENIED;
713 }
714 }
715 }
716 break;
717 } // switch on parameter count
718
719 if (FileList != NULL) {
720 ShellCloseFileMetaArg(&FileList);
721 }
722
723 //
724 // free the command line package
725 //
726 ShellCommandLineFreeVarList (Package);
727 }
728
729 if (ShellGetExecutionBreakFlag()) {
730 return (SHELL_ABORTED);
731 }
732
733 return (ShellStatus);
734 }
735