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