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