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