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