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