]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
ShellPkg: fix mv and cp command related issues
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Cp.c
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 - 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 @param[in] CmdName Source command name requesting single file copy
57
58 @retval SHELL_SUCCESS The source file was copied to the destination
59 **/
60 SHELL_STATUS
61 EFIAPI
62 CopySingleFile(
63 IN CONST CHAR16 *Source,
64 IN CONST CHAR16 *Dest,
65 OUT VOID **Resp,
66 IN BOOLEAN SilentMode,
67 IN CONST CHAR16 *CmdName
68 )
69 {
70 VOID *Response;
71 UINTN ReadSize;
72 SHELL_FILE_HANDLE SourceHandle;
73 SHELL_FILE_HANDLE DestHandle;
74 EFI_STATUS Status;
75 VOID *Buffer;
76 CHAR16 *TempName;
77 UINTN Size;
78 EFI_SHELL_FILE_INFO *List;
79 SHELL_STATUS ShellStatus;
80 UINT64 SourceFileSize;
81 UINT64 DestFileSize;
82 EFI_FILE_PROTOCOL *DestVolumeFP;
83 EFI_FILE_SYSTEM_INFO *DestVolumeInfo;
84 UINTN DestVolumeInfoSize;
85
86 ASSERT(Resp != NULL);
87
88 SourceHandle = NULL;
89 DestHandle = NULL;
90 Response = *Resp;
91 List = NULL;
92 DestVolumeInfo = NULL;
93 ShellStatus = SHELL_SUCCESS;
94
95 ReadSize = PcdGet32(PcdShellFileOperationSize);
96 // Why bother copying a file to itself
97 if (StrCmp(Source, Dest) == 0) {
98 return (SHELL_SUCCESS);
99 }
100
101 //
102 // if the destination file existed check response and possibly prompt user
103 //
104 if (ShellFileExists(Dest) == EFI_SUCCESS) {
105 if (Response == NULL && !SilentMode) {
106 Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
107 }
108 //
109 // possibly return based on response
110 //
111 if (!SilentMode) {
112 switch (*(SHELL_PROMPT_RESPONSE*)Response) {
113 case ShellPromptResponseNo:
114 //
115 // return success here so we dont stop the process
116 //
117 return (SHELL_SUCCESS);
118 case ShellPromptResponseCancel:
119 *Resp = Response;
120 //
121 // indicate to stop everything
122 //
123 return (SHELL_ABORTED);
124 case ShellPromptResponseAll:
125 *Resp = Response;
126 case ShellPromptResponseYes:
127 break;
128 default:
129 return SHELL_ABORTED;
130 }
131 }
132 }
133
134 if (ShellIsDirectory(Source) == EFI_SUCCESS) {
135 Status = ShellCreateDirectory(Dest, &DestHandle);
136 if (EFI_ERROR(Status)) {
137 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
138 return (SHELL_ACCESS_DENIED);
139 }
140
141 //
142 // Now copy all the files under the directory...
143 //
144 TempName = NULL;
145 Size = 0;
146 StrnCatGrow(&TempName, &Size, Source, 0);
147 StrnCatGrow(&TempName, &Size, L"\\*", 0);
148 if (TempName != NULL) {
149 ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List);
150 *TempName = CHAR_NULL;
151 StrnCatGrow(&TempName, &Size, Dest, 0);
152 StrnCatGrow(&TempName, &Size, L"\\", 0);
153 ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp);
154 ShellCloseFileMetaArg(&List);
155 SHELL_FREE_NON_NULL(TempName);
156 Size = 0;
157 }
158 } else {
159 Status = ShellDeleteFileByName(Dest);
160
161 //
162 // open file with create enabled
163 //
164 Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
165 if (EFI_ERROR(Status)) {
166 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Dest);
167 return (SHELL_ACCESS_DENIED);
168 }
169
170 //
171 // open source file
172 //
173 Status = ShellOpenFileByName(Source, &SourceHandle, EFI_FILE_MODE_READ, 0);
174 ASSERT_EFI_ERROR(Status);
175
176 //
177 //get file size of source file and freespace available on destination volume
178 //
179 ShellGetFileSize(SourceHandle, &SourceFileSize);
180 ShellGetFileSize(DestHandle, &DestFileSize);
181
182 //
183 //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space
184 //
185 if(DestFileSize < SourceFileSize){
186 SourceFileSize -= DestFileSize;
187 } else {
188 SourceFileSize = 0;
189 }
190
191 //
192 //get the system volume info to check the free space
193 //
194 DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle);
195 DestVolumeInfo = NULL;
196 DestVolumeInfoSize = 0;
197 Status = DestVolumeFP->GetInfo(
198 DestVolumeFP,
199 &gEfiFileSystemInfoGuid,
200 &DestVolumeInfoSize,
201 DestVolumeInfo
202 );
203
204 if (Status == EFI_BUFFER_TOO_SMALL) {
205 DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize);
206 Status = DestVolumeFP->GetInfo(
207 DestVolumeFP,
208 &gEfiFileSystemInfoGuid,
209 &DestVolumeInfoSize,
210 DestVolumeInfo
211 );
212 }
213
214 //
215 //check if enough space available on destination drive to complete copy
216 //
217 if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) {
218 //
219 //not enough space on destination directory to copy file
220 //
221 SHELL_FREE_NON_NULL(DestVolumeInfo);
222 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName);
223 return(SHELL_VOLUME_FULL);
224 } else {
225 //
226 // copy data between files
227 //
228 Buffer = AllocateZeroPool(ReadSize);
229 ASSERT(Buffer != NULL);
230 while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {
231 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);
232 if (!EFI_ERROR(Status)) {
233 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);
234 if (EFI_ERROR(Status)) {
235 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
236 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest);
237 break;
238 }
239 } else {
240 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
241 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source);
242 break;
243 }
244 }
245 }
246 SHELL_FREE_NON_NULL(DestVolumeInfo);
247 }
248
249 //
250 // close files
251 //
252 if (DestHandle != NULL) {
253 ShellCloseFile(&DestHandle);
254 DestHandle = NULL;
255 }
256 if (SourceHandle != NULL) {
257 ShellCloseFile(&SourceHandle);
258 SourceHandle = NULL;
259 }
260
261 //
262 // return
263 //
264 return ShellStatus;
265 }
266
267 /**
268 function to take a list of files to copy and a destination location and do
269 the verification and copying of those files to that location. This function
270 will report any errors to the user and halt.
271
272 The key is to have this function called ONLY once. this allows for the parameter
273 verification to happen correctly.
274
275 @param[in] FileList A LIST_ENTRY* based list of files to move.
276 @param[in] DestDir The destination location.
277 @param[in] SilentMode TRUE to eliminate screen output.
278 @param[in] RecursiveMode TRUE to copy directories.
279 @param[in] Resp The response to the overwrite query (if always).
280
281 @retval SHELL_SUCCESS the files were all moved.
282 @retval SHELL_INVALID_PARAMETER a parameter was invalid
283 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
284 @retval SHELL_WRITE_PROTECTED the destination was write protected
285 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
286 **/
287 SHELL_STATUS
288 EFIAPI
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);
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 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16)-1);
428 } else {
429 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
430 FreePool (CleanFilePathStr);
431 return (SHELL_INVALID_PARAMETER);
432 }
433 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {
434 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
435 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {
436 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
437 }
438 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
439 } else {
440 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1);
441 }
442 } else {
443 //
444 // we have multiple files or a directory in the DestDir
445 //
446
447 //
448 // Check for leading slash
449 //
450 if (CleanFilePathStr[0] == L'\\') {
451 //
452 // Copy to the root of CWD
453 //
454 if (Cwd != NULL) {
455 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1);
456 } else {
457 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
458 FreePool(CleanFilePathStr);
459 return (SHELL_INVALID_PARAMETER);
460 }
461 while (PathRemoveLastItem(DestPath));
462 StrnCat(DestPath, CleanFilePathStr+1, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
463 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
464 } else if (StrStr(CleanFilePathStr, L":") == NULL) {
465 if (Cwd != NULL) {
466 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1);
467 } else {
468 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
469 FreePool(CleanFilePathStr);
470 return (SHELL_INVALID_PARAMETER);
471 }
472 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') {
473 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
474 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') {
475 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
476 }
477 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
478 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {
479 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
480 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {
481 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
482 }
483 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
484
485 } else {
486 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1);
487 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') {
488 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
489 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') {
490 ((CHAR16*)CleanFilePathStr)[StrLen(CleanFilePathStr)-1] = CHAR_NULL;
491 }
492 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1);
493 }
494 }
495
496 //
497 // Make sure the path exists
498 //
499 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {
500 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath);
501 ShellStatus = SHELL_DEVICE_ERROR;
502 break;
503 }
504
505 if ( !EFI_ERROR(ShellIsDirectory(Node->FullName))
506 && !EFI_ERROR(ShellIsDirectory(DestPath))
507 && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL
508 ){
509 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp");
510 ShellStatus = SHELL_INVALID_PARAMETER;
511 break;
512 }
513 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {
514 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
515 ShellStatus = SHELL_INVALID_PARAMETER;
516 break;
517 }
518
519 if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0)
520 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')
521 ) {
522 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
523 ShellStatus = SHELL_INVALID_PARAMETER;
524 break;
525 }
526
527 PathCleanUpDirectories(DestPath);
528
529 if (!SilentMode) {
530 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);
531 }
532
533 //
534 // copy single file...
535 //
536 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode, L"cp");
537 if (ShellStatus != SHELL_SUCCESS) {
538 break;
539 }
540 }
541 if (ShellStatus == SHELL_SUCCESS && Resp == NULL) {
542 ShellPrintEx(-1, -1, L"%s", HiiResultOk);
543 }
544
545 SHELL_FREE_NON_NULL(DestPath);
546 SHELL_FREE_NON_NULL(HiiOutput);
547 SHELL_FREE_NON_NULL(HiiResultOk);
548 SHELL_FREE_NON_NULL(CleanFilePathStr);
549 if (Resp == NULL) {
550 SHELL_FREE_NON_NULL(Response);
551 }
552
553 return (ShellStatus);
554
555 }
556
557 /**
558 Validate and if successful copy all the files from the list into
559 destination directory.
560
561 @param[in] FileList The list of files to copy.
562 @param[in] DestDir The directory to copy files to.
563 @param[in] SilentMode TRUE to eliminate screen output.
564 @param[in] RecursiveMode TRUE to copy directories.
565
566 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
567 @retval SHELL_SUCCESS The operation was successful.
568 **/
569 SHELL_STATUS
570 EFIAPI
571 ProcessValidateAndCopyFiles(
572 IN EFI_SHELL_FILE_INFO *FileList,
573 IN CONST CHAR16 *DestDir,
574 IN BOOLEAN SilentMode,
575 IN BOOLEAN RecursiveMode
576 )
577 {
578 SHELL_STATUS ShellStatus;
579 EFI_SHELL_FILE_INFO *List;
580 EFI_FILE_INFO *FileInfo;
581 CHAR16 *FullName;
582
583 List = NULL;
584 FullName = NULL;
585 FileInfo = NULL;
586
587 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);
588 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {
589 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir);
590 ShellStatus = SHELL_INVALID_PARAMETER;
591 ShellCloseFileMetaArg(&List);
592 } else if (List != NULL) {
593 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
594 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
595 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
596 ASSERT(FileInfo != NULL);
597 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);
598 ShellCloseFileMetaArg(&List);
599 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
600 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);
601 } else {
602 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp");
603 ShellStatus = SHELL_ACCESS_DENIED;
604 }
605 } else {
606 ShellCloseFileMetaArg(&List);
607 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);
608 }
609
610 SHELL_FREE_NON_NULL(FileInfo);
611 SHELL_FREE_NON_NULL(FullName);
612 return (ShellStatus);
613 }
614
615 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
616 {L"-r", TypeFlag},
617 {L"-q", TypeFlag},
618 {NULL, TypeMax}
619 };
620
621 /**
622 Function for 'cp' command.
623
624 @param[in] ImageHandle Handle to the Image (NULL if Internal).
625 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
626 **/
627 SHELL_STATUS
628 EFIAPI
629 ShellCommandRunCp (
630 IN EFI_HANDLE ImageHandle,
631 IN EFI_SYSTEM_TABLE *SystemTable
632 )
633 {
634 EFI_STATUS Status;
635 LIST_ENTRY *Package;
636 CHAR16 *ProblemParam;
637 SHELL_STATUS ShellStatus;
638 UINTN ParamCount;
639 UINTN LoopCounter;
640 EFI_SHELL_FILE_INFO *FileList;
641 BOOLEAN SilentMode;
642 BOOLEAN RecursiveMode;
643 CONST CHAR16 *Cwd;
644
645 ProblemParam = NULL;
646 ShellStatus = SHELL_SUCCESS;
647 ParamCount = 0;
648 FileList = NULL;
649
650 //
651 // initialize the shell lib (we must be in non-auto-init...)
652 //
653 Status = ShellInitialize();
654 ASSERT_EFI_ERROR(Status);
655
656 Status = CommandInit();
657 ASSERT_EFI_ERROR(Status);
658
659 //
660 // parse the command line
661 //
662 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
663 if (EFI_ERROR(Status)) {
664 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
665 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam);
666 FreePool(ProblemParam);
667 ShellStatus = SHELL_INVALID_PARAMETER;
668 } else {
669 ASSERT(FALSE);
670 }
671 } else {
672 //
673 // check for "-?"
674 //
675 if (ShellCommandLineGetFlag(Package, L"-?")) {
676 ASSERT(FALSE);
677 }
678
679 //
680 // Initialize SilentMode and RecursiveMode
681 //
682 if (gEfiShellProtocol->BatchIsActive()) {
683 SilentMode = TRUE;
684 } else {
685 SilentMode = ShellCommandLineGetFlag(Package, L"-q");
686 }
687 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");
688
689 switch (ParamCount = ShellCommandLineGetCount(Package)) {
690 case 0:
691 case 1:
692 //
693 // we have insufficient parameters
694 //
695 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp");
696 ShellStatus = SHELL_INVALID_PARAMETER;
697 break;
698 case 2:
699 //
700 // must have valid CWD for single parameter...
701 //
702 Cwd = ShellGetCurrentDir(NULL);
703 if (Cwd == NULL){
704 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp");
705 ShellStatus = SHELL_INVALID_PARAMETER;
706 } else {
707 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
708 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
709 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1));
710 ShellStatus = SHELL_NOT_FOUND;
711 } else {
712 ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode);
713 }
714 }
715
716 break;
717 default:
718 //
719 // Make a big list of all the files...
720 //
721 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {
722 if (ShellGetExecutionBreakFlag()) {
723 break;
724 }
725 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
726 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {
727 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter));
728 ShellStatus = SHELL_NOT_FOUND;
729 }
730 }
731 if (ShellStatus != SHELL_SUCCESS) {
732 Status = ShellCloseFileMetaArg(&FileList);
733 } else {
734 //
735 // now copy them all...
736 //
737 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
738 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);
739 Status = ShellCloseFileMetaArg(&FileList);
740 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
741 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT);
742 ShellStatus = SHELL_ACCESS_DENIED;
743 }
744 }
745 }
746 break;
747 } // switch on parameter count
748
749 if (FileList != NULL) {
750 ShellCloseFileMetaArg(&FileList);
751 }
752
753 //
754 // free the command line package
755 //
756 ShellCommandLineFreeVarList (Package);
757 }
758
759 if (ShellGetExecutionBreakFlag()) {
760 return (SHELL_ABORTED);
761 }
762
763 return (ShellStatus);
764 }
765