]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
ShellPkg: Follow spec to remove the last '\' char in return name of GetCurDir().
[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 - 2015, 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 if (EFI_ERROR (Status)) {
175 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source);
176 return (SHELL_ACCESS_DENIED);
177 }
178
179 //
180 //get file size of source file and freespace available on destination volume
181 //
182 ShellGetFileSize(SourceHandle, &SourceFileSize);
183 ShellGetFileSize(DestHandle, &DestFileSize);
184
185 //
186 //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space
187 //
188 if(DestFileSize < SourceFileSize){
189 SourceFileSize -= DestFileSize;
190 } else {
191 SourceFileSize = 0;
192 }
193
194 //
195 //get the system volume info to check the free space
196 //
197 DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle);
198 DestVolumeInfo = NULL;
199 DestVolumeInfoSize = 0;
200 Status = DestVolumeFP->GetInfo(
201 DestVolumeFP,
202 &gEfiFileSystemInfoGuid,
203 &DestVolumeInfoSize,
204 DestVolumeInfo
205 );
206
207 if (Status == EFI_BUFFER_TOO_SMALL) {
208 DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize);
209 Status = DestVolumeFP->GetInfo(
210 DestVolumeFP,
211 &gEfiFileSystemInfoGuid,
212 &DestVolumeInfoSize,
213 DestVolumeInfo
214 );
215 }
216
217 //
218 //check if enough space available on destination drive to complete copy
219 //
220 if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) {
221 //
222 //not enough space on destination directory to copy file
223 //
224 SHELL_FREE_NON_NULL(DestVolumeInfo);
225 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName);
226 return(SHELL_VOLUME_FULL);
227 } else {
228 //
229 // copy data between files
230 //
231 Buffer = AllocateZeroPool(ReadSize);
232 ASSERT(Buffer != NULL);
233 while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {
234 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);
235 if (!EFI_ERROR(Status)) {
236 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);
237 if (EFI_ERROR(Status)) {
238 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
239 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest);
240 break;
241 }
242 } else {
243 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT));
244 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source);
245 break;
246 }
247 }
248 }
249 SHELL_FREE_NON_NULL(DestVolumeInfo);
250 }
251
252 //
253 // close files
254 //
255 if (DestHandle != NULL) {
256 ShellCloseFile(&DestHandle);
257 DestHandle = NULL;
258 }
259 if (SourceHandle != NULL) {
260 ShellCloseFile(&SourceHandle);
261 SourceHandle = NULL;
262 }
263
264 //
265 // return
266 //
267 return ShellStatus;
268 }
269
270 /**
271 function to take a list of files to copy and a destination location and do
272 the verification and copying of those files to that location. This function
273 will report any errors to the user and halt.
274
275 The key is to have this function called ONLY once. this allows for the parameter
276 verification to happen correctly.
277
278 @param[in] FileList A LIST_ENTRY* based list of files to move.
279 @param[in] DestDir The destination location.
280 @param[in] SilentMode TRUE to eliminate screen output.
281 @param[in] RecursiveMode TRUE to copy directories.
282 @param[in] Resp The response to the overwrite query (if always).
283
284 @retval SHELL_SUCCESS the files were all moved.
285 @retval SHELL_INVALID_PARAMETER a parameter was invalid
286 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
287 @retval SHELL_WRITE_PROTECTED the destination was write protected
288 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
289 **/
290 SHELL_STATUS
291 EFIAPI
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 EFIAPI
577 ProcessValidateAndCopyFiles(
578 IN EFI_SHELL_FILE_INFO *FileList,
579 IN CONST CHAR16 *DestDir,
580 IN BOOLEAN SilentMode,
581 IN BOOLEAN RecursiveMode
582 )
583 {
584 SHELL_STATUS ShellStatus;
585 EFI_SHELL_FILE_INFO *List;
586 EFI_FILE_INFO *FileInfo;
587 CHAR16 *FullName;
588
589 List = NULL;
590 FullName = NULL;
591 FileInfo = NULL;
592
593 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);
594 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {
595 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir);
596 ShellStatus = SHELL_INVALID_PARAMETER;
597 ShellCloseFileMetaArg(&List);
598 } else if (List != NULL) {
599 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
600 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
601 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
602 ASSERT(FileInfo != NULL);
603 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);
604 ShellCloseFileMetaArg(&List);
605 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
606 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL);
607 } else {
608 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp");
609 ShellStatus = SHELL_ACCESS_DENIED;
610 }
611 } else {
612 ShellCloseFileMetaArg(&List);
613 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);
614 }
615
616 SHELL_FREE_NON_NULL(FileInfo);
617 SHELL_FREE_NON_NULL(FullName);
618 return (ShellStatus);
619 }
620
621 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
622 {L"-r", TypeFlag},
623 {L"-q", TypeFlag},
624 {NULL, TypeMax}
625 };
626
627 /**
628 Function for 'cp' command.
629
630 @param[in] ImageHandle Handle to the Image (NULL if Internal).
631 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
632 **/
633 SHELL_STATUS
634 EFIAPI
635 ShellCommandRunCp (
636 IN EFI_HANDLE ImageHandle,
637 IN EFI_SYSTEM_TABLE *SystemTable
638 )
639 {
640 EFI_STATUS Status;
641 LIST_ENTRY *Package;
642 CHAR16 *ProblemParam;
643 SHELL_STATUS ShellStatus;
644 UINTN ParamCount;
645 UINTN LoopCounter;
646 EFI_SHELL_FILE_INFO *FileList;
647 BOOLEAN SilentMode;
648 BOOLEAN RecursiveMode;
649 CONST CHAR16 *Cwd;
650 CHAR16 *FullCwd;
651
652 ProblemParam = NULL;
653 ShellStatus = SHELL_SUCCESS;
654 ParamCount = 0;
655 FileList = NULL;
656
657 //
658 // initialize the shell lib (we must be in non-auto-init...)
659 //
660 Status = ShellInitialize();
661 ASSERT_EFI_ERROR(Status);
662
663 Status = CommandInit();
664 ASSERT_EFI_ERROR(Status);
665
666 //
667 // parse the command line
668 //
669 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
670 if (EFI_ERROR(Status)) {
671 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
672 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam);
673 FreePool(ProblemParam);
674 ShellStatus = SHELL_INVALID_PARAMETER;
675 } else {
676 ASSERT(FALSE);
677 }
678 } else {
679 //
680 // check for "-?"
681 //
682 if (ShellCommandLineGetFlag(Package, L"-?")) {
683 ASSERT(FALSE);
684 }
685
686 //
687 // Initialize SilentMode and RecursiveMode
688 //
689 if (gEfiShellProtocol->BatchIsActive()) {
690 SilentMode = TRUE;
691 } else {
692 SilentMode = ShellCommandLineGetFlag(Package, L"-q");
693 }
694 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");
695
696 switch (ParamCount = ShellCommandLineGetCount(Package)) {
697 case 0:
698 case 1:
699 //
700 // we have insufficient parameters
701 //
702 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp");
703 ShellStatus = SHELL_INVALID_PARAMETER;
704 break;
705 case 2:
706 //
707 // must have valid CWD for single parameter...
708 //
709 Cwd = ShellGetCurrentDir(NULL);
710 if (Cwd == NULL){
711 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp");
712 ShellStatus = SHELL_INVALID_PARAMETER;
713 } else {
714 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
715 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
716 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1));
717 ShellStatus = SHELL_NOT_FOUND;
718 } else {
719 FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16));
720 ASSERT (FullCwd != NULL);
721 StrCpyS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, Cwd);
722 ShellStatus = ProcessValidateAndCopyFiles(FileList, FullCwd, SilentMode, RecursiveMode);
723 FreePool(FullCwd);
724 }
725 }
726
727 break;
728 default:
729 //
730 // Make a big list of all the files...
731 //
732 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {
733 if (ShellGetExecutionBreakFlag()) {
734 break;
735 }
736 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
737 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {
738 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter));
739 ShellStatus = SHELL_NOT_FOUND;
740 }
741 }
742 if (ShellStatus != SHELL_SUCCESS) {
743 Status = ShellCloseFileMetaArg(&FileList);
744 } else {
745 //
746 // now copy them all...
747 //
748 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
749 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);
750 Status = ShellCloseFileMetaArg(&FileList);
751 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
752 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT);
753 ShellStatus = SHELL_ACCESS_DENIED;
754 }
755 }
756 }
757 break;
758 } // switch on parameter count
759
760 if (FileList != NULL) {
761 ShellCloseFileMetaArg(&FileList);
762 }
763
764 //
765 // free the command line package
766 //
767 ShellCommandLineFreeVarList (Package);
768 }
769
770 if (ShellGetExecutionBreakFlag()) {
771 return (SHELL_ABORTED);
772 }
773
774 return (ShellStatus);
775 }
776