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