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