VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 2 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 27.1 KB
Line 
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 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "UefiShellLevel2CommandsLib.h"
11#include <Guid/FileSystemInfo.h>
12#include <Guid/FileSystemVolumeLabelInfo.h>
13
14/**
15 Function to take a list of files to copy and a destination location and do
16 the verification and copying of those files to that location. This function
17 will report any errors to the user and halt.
18
19 @param[in] FileList A LIST_ENTRY* based list of files to move.
20 @param[in] DestDir The destination location.
21 @param[in] SilentMode TRUE to eliminate screen output.
22 @param[in] RecursiveMode TRUE to copy directories.
23 @param[in] Resp The response to the overwrite query (if always).
24
25 @retval SHELL_SUCCESS the files were all moved.
26 @retval SHELL_INVALID_PARAMETER a parameter was invalid
27 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
28 @retval SHELL_WRITE_PROTECTED the destination was write protected
29 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
30**/
31SHELL_STATUS
32ValidateAndCopyFiles (
33 IN CONST EFI_SHELL_FILE_INFO *FileList,
34 IN CONST CHAR16 *DestDir,
35 IN BOOLEAN SilentMode,
36 IN BOOLEAN RecursiveMode,
37 IN VOID **Resp
38 );
39
40/**
41 Function to Copy one file to another location
42
43 If the destination exists the user will be prompted and the result put into *resp
44
45 @param[in] Source pointer to source file name
46 @param[in] Dest pointer to destination file name
47 @param[out] Resp pointer to response from question. Pass back on looped calling
48 @param[in] SilentMode whether to run in quiet mode or not
49 @param[in] CmdName Source command name requesting single file copy
50
51 @retval SHELL_SUCCESS The source file was copied to the destination
52**/
53SHELL_STATUS
54CopySingleFile (
55 IN CONST CHAR16 *Source,
56 IN CONST CHAR16 *Dest,
57 OUT VOID **Resp,
58 IN BOOLEAN SilentMode,
59 IN CONST CHAR16 *CmdName
60 )
61{
62 VOID *Response;
63 UINTN ReadSize;
64 SHELL_FILE_HANDLE SourceHandle;
65 SHELL_FILE_HANDLE DestHandle;
66 EFI_STATUS Status;
67 VOID *Buffer;
68 CHAR16 *TempName;
69 UINTN Size;
70 EFI_SHELL_FILE_INFO *List;
71 SHELL_STATUS ShellStatus;
72 UINT64 SourceFileSize;
73 UINT64 DestFileSize;
74 EFI_FILE_PROTOCOL *DestVolumeFP;
75 EFI_FILE_SYSTEM_INFO *DestVolumeInfo;
76 UINTN DestVolumeInfoSize;
77
78 ASSERT (Resp != NULL);
79
80 SourceHandle = NULL;
81 DestHandle = NULL;
82 Response = *Resp;
83 List = NULL;
84 DestVolumeInfo = NULL;
85 ShellStatus = SHELL_SUCCESS;
86
87 ReadSize = PcdGet32 (PcdShellFileOperationSize);
88 // Why bother copying a file to itself
89 if (StrCmp (Source, Dest) == 0) {
90 return (SHELL_SUCCESS);
91 }
92
93 //
94 // if the destination file existed check response and possibly prompt user
95 //
96 if (ShellFileExists (Dest) == EFI_SUCCESS) {
97 if ((Response == NULL) && !SilentMode) {
98 Status = ShellPromptForResponseHii (ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
99 }
100
101 //
102 // possibly return based on response
103 //
104 if (!SilentMode) {
105 if (Response == NULL) {
106 return SHELL_ABORTED;
107 }
108
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, CmdName, 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, CmdName, 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 if (EFI_ERROR (Status)) {
172 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SRC_OPEN_FAIL), gShellLevel2HiiHandle, CmdName, Source);
173 return (SHELL_ACCESS_DENIED);
174 }
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 if (DestVolumeInfo == NULL) {
207 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cp");
208 ShellStatus = SHELL_OUT_OF_RESOURCES;
209 goto Done;
210 }
211
212 Status = DestVolumeFP->GetInfo (
213 DestVolumeFP,
214 &gEfiFileSystemInfoGuid,
215 &DestVolumeInfoSize,
216 DestVolumeInfo
217 );
218 }
219
220 //
221 // check if enough space available on destination drive to complete copy
222 //
223 if ((DestVolumeInfo != NULL) && (DestVolumeInfo->FreeSpace < SourceFileSize)) {
224 //
225 // not enough space on destination directory to copy file
226 //
227 SHELL_FREE_NON_NULL (DestVolumeInfo);
228 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, CmdName);
229 return (SHELL_VOLUME_FULL);
230 } else {
231 //
232 // copy data between files
233 //
234 Buffer = AllocateZeroPool (ReadSize);
235 if (Buffer == NULL) {
236 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, CmdName);
237 return SHELL_OUT_OF_RESOURCES;
238 }
239
240 while (ReadSize == PcdGet32 (PcdShellFileOperationSize) && !EFI_ERROR (Status)) {
241 Status = ShellReadFile (SourceHandle, &ReadSize, Buffer);
242 if (!EFI_ERROR (Status)) {
243 Status = ShellWriteFile (DestHandle, &ReadSize, Buffer);
244 if (EFI_ERROR (Status)) {
245 ShellStatus = (SHELL_STATUS)(Status & (~MAX_BIT));
246 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, CmdName, Dest);
247 break;
248 }
249 } else {
250 ShellStatus = (SHELL_STATUS)(Status & (~MAX_BIT));
251 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, CmdName, Source);
252 break;
253 }
254 }
255 }
256
257 SHELL_FREE_NON_NULL (DestVolumeInfo);
258 }
259
260Done:
261 //
262 // close files
263 //
264 if (DestHandle != NULL) {
265 ShellCloseFile (&DestHandle);
266 DestHandle = NULL;
267 }
268
269 if (SourceHandle != NULL) {
270 ShellCloseFile (&SourceHandle);
271 SourceHandle = NULL;
272 }
273
274 //
275 // return
276 //
277 return ShellStatus;
278}
279
280/**
281 function to take a list of files to copy and a destination location and do
282 the verification and copying of those files to that location. This function
283 will report any errors to the user and halt.
284
285 The key is to have this function called ONLY once. this allows for the parameter
286 verification to happen correctly.
287
288 @param[in] FileList A LIST_ENTRY* based list of files to move.
289 @param[in] DestDir The destination location.
290 @param[in] SilentMode TRUE to eliminate screen output.
291 @param[in] RecursiveMode TRUE to copy directories.
292 @param[in] Resp The response to the overwrite query (if always).
293
294 @retval SHELL_SUCCESS the files were all moved.
295 @retval SHELL_INVALID_PARAMETER a parameter was invalid
296 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
297 @retval SHELL_WRITE_PROTECTED the destination was write protected
298 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
299**/
300SHELL_STATUS
301ValidateAndCopyFiles (
302 IN CONST EFI_SHELL_FILE_INFO *FileList,
303 IN CONST CHAR16 *DestDir,
304 IN BOOLEAN SilentMode,
305 IN BOOLEAN RecursiveMode,
306 IN VOID **Resp
307 )
308{
309 CHAR16 *HiiOutput;
310 CHAR16 *HiiResultOk;
311 CONST EFI_SHELL_FILE_INFO *Node;
312 SHELL_STATUS ShellStatus;
313 EFI_STATUS Status;
314 CHAR16 *DestPath;
315 VOID *Response;
316 UINTN PathSize;
317 CONST CHAR16 *Cwd;
318 UINTN NewSize;
319 CHAR16 *CleanFilePathStr;
320
321 if (Resp == NULL) {
322 Response = NULL;
323 } else {
324 Response = *Resp;
325 }
326
327 DestPath = NULL;
328 ShellStatus = SHELL_SUCCESS;
329 PathSize = 0;
330 Cwd = ShellGetCurrentDir (NULL);
331 CleanFilePathStr = NULL;
332
333 ASSERT (FileList != NULL);
334 ASSERT (DestDir != NULL);
335
336 Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr);
337 if (EFI_ERROR (Status)) {
338 if (Status == EFI_OUT_OF_RESOURCES) {
339 return SHELL_OUT_OF_RESOURCES;
340 } else {
341 return SHELL_INVALID_PARAMETER;
342 }
343 }
344
345 ASSERT (CleanFilePathStr != NULL);
346
347 //
348 // If we are trying to copy multiple files... make sure we got a directory for the target...
349 //
350 if (EFI_ERROR (ShellIsDirectory (CleanFilePathStr)) && (FileList->Link.ForwardLink != FileList->Link.BackLink)) {
351 //
352 // Error for destination not a directory
353 //
354 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
355 FreePool (CleanFilePathStr);
356 return (SHELL_INVALID_PARAMETER);
357 }
358
359 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link)
360 ; !IsNull (&FileList->Link, &Node->Link)
361 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &Node->Link)
362 )
363 {
364 //
365 // skip the directory traversing stuff...
366 //
367 if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
368 continue;
369 }
370
371 NewSize = StrSize (CleanFilePathStr);
372 NewSize += StrSize (Node->FullName);
373 NewSize += (Cwd == NULL) ? 0 : (StrSize (Cwd) + sizeof (CHAR16));
374 if (NewSize > PathSize) {
375 PathSize = NewSize;
376 }
377
378 //
379 // Make sure got -r if required
380 //
381 if (!RecursiveMode && !EFI_ERROR (ShellIsDirectory (Node->FullName))) {
382 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp");
383 FreePool (CleanFilePathStr);
384 return (SHELL_INVALID_PARAMETER);
385 }
386
387 //
388 // make sure got dest as dir if needed
389 //
390 if (!EFI_ERROR (ShellIsDirectory (Node->FullName)) && EFI_ERROR (ShellIsDirectory (CleanFilePathStr))) {
391 //
392 // Error for destination not a directory
393 //
394 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
395 FreePool (CleanFilePathStr);
396 return (SHELL_INVALID_PARAMETER);
397 }
398 }
399
400 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);
401 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
402 DestPath = AllocateZeroPool (PathSize);
403
404 if ((DestPath == NULL) || (HiiOutput == NULL) || (HiiResultOk == NULL)) {
405 SHELL_FREE_NON_NULL (DestPath);
406 SHELL_FREE_NON_NULL (HiiOutput);
407 SHELL_FREE_NON_NULL (HiiResultOk);
408 FreePool (CleanFilePathStr);
409 return (SHELL_OUT_OF_RESOURCES);
410 }
411
412 //
413 // Go through the list of files to copy...
414 //
415 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link)
416 ; !IsNull (&FileList->Link, &Node->Link)
417 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &Node->Link)
418 )
419 {
420 if (ShellGetExecutionBreakFlag ()) {
421 break;
422 }
423
424 ASSERT (Node->FileName != NULL);
425 ASSERT (Node->FullName != NULL);
426
427 //
428 // skip the directory traversing stuff...
429 //
430 if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {
431 continue;
432 }
433
434 if ( (FileList->Link.ForwardLink == FileList->Link.BackLink) // 1 item
435 && EFI_ERROR (ShellIsDirectory (CleanFilePathStr)) // not an existing directory
436 )
437 {
438 if (StrStr (CleanFilePathStr, L":") == NULL) {
439 //
440 // simple copy of a single file
441 //
442 if (Cwd != NULL) {
443 StrCpyS (DestPath, PathSize / sizeof (CHAR16), Cwd);
444 StrCatS (DestPath, PathSize / sizeof (CHAR16), L"\\");
445 } else {
446 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
447 FreePool (CleanFilePathStr);
448 return (SHELL_INVALID_PARAMETER);
449 }
450
451 if ((DestPath[StrLen (DestPath)-1] != L'\\') && (CleanFilePathStr[0] != L'\\')) {
452 StrCatS (DestPath, PathSize / sizeof (CHAR16), L"\\");
453 } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (CleanFilePathStr[0] == L'\\')) {
454 ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
455 }
456
457 StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
458 } else {
459 StrCpyS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
460 }
461 } else {
462 //
463 // we have multiple files or a directory in the DestDir
464 //
465
466 //
467 // Check for leading slash
468 //
469 if (CleanFilePathStr[0] == L'\\') {
470 //
471 // Copy to the root of CWD
472 //
473 if (Cwd != NULL) {
474 StrCpyS (DestPath, PathSize/sizeof (CHAR16), Cwd);
475 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
476 } else {
477 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
478 FreePool (CleanFilePathStr);
479 return (SHELL_INVALID_PARAMETER);
480 }
481
482 while (PathRemoveLastItem (DestPath)) {
483 }
484
485 StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr+1);
486 StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
487 } else if (StrStr (CleanFilePathStr, L":") == NULL) {
488 if (Cwd != NULL) {
489 StrCpyS (DestPath, PathSize/sizeof (CHAR16), Cwd);
490 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
491 } else {
492 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr);
493 FreePool (CleanFilePathStr);
494 return (SHELL_INVALID_PARAMETER);
495 }
496
497 if ((DestPath[StrLen (DestPath)-1] != L'\\') && (CleanFilePathStr[0] != L'\\')) {
498 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
499 } else if ((DestPath[StrLen (DestPath)-1] == L'\\') && (CleanFilePathStr[0] == L'\\')) {
500 ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
501 }
502
503 StrCatS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
504 if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] != L'\\') && (Node->FileName[0] != L'\\')) {
505 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
506 } else if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] == L'\\') && (Node->FileName[0] == L'\\')) {
507 ((CHAR16 *)DestPath)[StrLen (DestPath)-1] = CHAR_NULL;
508 }
509
510 StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
511 } else {
512 StrCpyS (DestPath, PathSize/sizeof (CHAR16), CleanFilePathStr);
513 if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] != L'\\') && (Node->FileName[0] != L'\\')) {
514 StrCatS (DestPath, PathSize/sizeof (CHAR16), L"\\");
515 } else if ((CleanFilePathStr[StrLen (CleanFilePathStr)-1] == L'\\') && (Node->FileName[0] == L'\\')) {
516 ((CHAR16 *)CleanFilePathStr)[StrLen (CleanFilePathStr)-1] = CHAR_NULL;
517 }
518
519 StrCatS (DestPath, PathSize/sizeof (CHAR16), Node->FileName);
520 }
521 }
522
523 //
524 // Make sure the path exists
525 //
526 if (EFI_ERROR (VerifyIntermediateDirectories (DestPath))) {
527 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath);
528 ShellStatus = SHELL_DEVICE_ERROR;
529 break;
530 }
531
532 if ( !EFI_ERROR (ShellIsDirectory (Node->FullName))
533 && !EFI_ERROR (ShellIsDirectory (DestPath))
534 && (StrniCmp (Node->FullName, DestPath, StrLen (DestPath)) == 0)
535 )
536 {
537 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp");
538 ShellStatus = SHELL_INVALID_PARAMETER;
539 break;
540 }
541
542 if (StringNoCaseCompare (&Node->FullName, &DestPath) == 0) {
543 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
544 ShellStatus = SHELL_INVALID_PARAMETER;
545 break;
546 }
547
548 if ( (StrniCmp (Node->FullName, DestPath, StrLen (Node->FullName)) == 0)
549 && ((DestPath[StrLen (Node->FullName)] == CHAR_NULL) || (DestPath[StrLen (Node->FullName)] == L'\\'))
550 )
551 {
552 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp");
553 ShellStatus = SHELL_INVALID_PARAMETER;
554 break;
555 }
556
557 PathCleanUpDirectories (DestPath);
558
559 if (!SilentMode) {
560 ShellPrintEx (-1, -1, HiiOutput, Node->FullName, DestPath);
561 }
562
563 //
564 // copy single file...
565 //
566 ShellStatus = CopySingleFile (Node->FullName, DestPath, &Response, SilentMode, L"cp");
567 if (ShellStatus != SHELL_SUCCESS) {
568 break;
569 }
570 }
571
572 if ((ShellStatus == SHELL_SUCCESS) && (Resp == NULL)) {
573 ShellPrintEx (-1, -1, L"%s", HiiResultOk);
574 }
575
576 SHELL_FREE_NON_NULL (DestPath);
577 SHELL_FREE_NON_NULL (HiiOutput);
578 SHELL_FREE_NON_NULL (HiiResultOk);
579 SHELL_FREE_NON_NULL (CleanFilePathStr);
580 if (Resp == NULL) {
581 SHELL_FREE_NON_NULL (Response);
582 }
583
584 return (ShellStatus);
585}
586
587/**
588 Validate and if successful copy all the files from the list into
589 destination directory.
590
591 @param[in] FileList The list of files to copy.
592 @param[in] DestDir The directory to copy files to.
593 @param[in] SilentMode TRUE to eliminate screen output.
594 @param[in] RecursiveMode TRUE to copy directories.
595
596 @retval SHELL_INVALID_PARAMETER A parameter was invalid.
597 @retval SHELL_SUCCESS The operation was successful.
598**/
599SHELL_STATUS
600ProcessValidateAndCopyFiles (
601 IN EFI_SHELL_FILE_INFO *FileList,
602 IN CONST CHAR16 *DestDir,
603 IN BOOLEAN SilentMode,
604 IN BOOLEAN RecursiveMode
605 )
606{
607 SHELL_STATUS ShellStatus;
608 EFI_SHELL_FILE_INFO *List;
609 EFI_FILE_INFO *FileInfo;
610 CHAR16 *FullName;
611
612 List = NULL;
613 FullName = NULL;
614 FileInfo = NULL;
615
616 ShellOpenFileMetaArg ((CHAR16 *)DestDir, EFI_FILE_MODE_READ, &List);
617 if ((List != NULL) && (List->Link.ForwardLink != List->Link.BackLink)) {
618 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir);
619 ShellStatus = SHELL_INVALID_PARAMETER;
620 ShellCloseFileMetaArg (&List);
621 } else if (List != NULL) {
622 ASSERT (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
623 ASSERT (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
624 FileInfo = gEfiShellProtocol->GetFileInfo (((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
625 ASSERT (FileInfo != NULL);
626 StrnCatGrow (&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0);
627 ShellCloseFileMetaArg (&List);
628 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
629 ShellStatus = ValidateAndCopyFiles (FileList, FullName, SilentMode, RecursiveMode, NULL);
630 } else {
631 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp");
632 ShellStatus = SHELL_ACCESS_DENIED;
633 }
634 } else {
635 ShellCloseFileMetaArg (&List);
636 ShellStatus = ValidateAndCopyFiles (FileList, DestDir, SilentMode, RecursiveMode, NULL);
637 }
638
639 SHELL_FREE_NON_NULL (FileInfo);
640 SHELL_FREE_NON_NULL (FullName);
641 return (ShellStatus);
642}
643
644STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
645 { L"-r", TypeFlag },
646 { L"-q", TypeFlag },
647 { NULL, TypeMax }
648};
649
650/**
651 Function for 'cp' command.
652
653 @param[in] ImageHandle Handle to the Image (NULL if Internal).
654 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
655**/
656SHELL_STATUS
657EFIAPI
658ShellCommandRunCp (
659 IN EFI_HANDLE ImageHandle,
660 IN EFI_SYSTEM_TABLE *SystemTable
661 )
662{
663 EFI_STATUS Status;
664 LIST_ENTRY *Package;
665 CHAR16 *ProblemParam;
666 SHELL_STATUS ShellStatus;
667 UINTN ParamCount;
668 UINTN LoopCounter;
669 EFI_SHELL_FILE_INFO *FileList;
670 BOOLEAN SilentMode;
671 BOOLEAN RecursiveMode;
672 CONST CHAR16 *Cwd;
673 CHAR16 *FullCwd;
674
675 ProblemParam = NULL;
676 ShellStatus = SHELL_SUCCESS;
677 ParamCount = 0;
678 FileList = NULL;
679
680 //
681 // initialize the shell lib (we must be in non-auto-init...)
682 //
683 Status = ShellInitialize ();
684 ASSERT_EFI_ERROR (Status);
685
686 Status = CommandInit ();
687 ASSERT_EFI_ERROR (Status);
688
689 //
690 // parse the command line
691 //
692 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
693 if (EFI_ERROR (Status)) {
694 if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
695 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam);
696 FreePool (ProblemParam);
697 ShellStatus = SHELL_INVALID_PARAMETER;
698 } else {
699 ASSERT (FALSE);
700 }
701 } else {
702 //
703 // check for "-?"
704 //
705 if (ShellCommandLineGetFlag (Package, L"-?")) {
706 ASSERT (FALSE);
707 }
708
709 //
710 // Initialize SilentMode and RecursiveMode
711 //
712 if (gEfiShellProtocol->BatchIsActive ()) {
713 SilentMode = TRUE;
714 } else {
715 SilentMode = ShellCommandLineGetFlag (Package, L"-q");
716 }
717
718 RecursiveMode = ShellCommandLineGetFlag (Package, L"-r");
719
720 switch (ParamCount = ShellCommandLineGetCount (Package)) {
721 case 0:
722 case 1:
723 //
724 // we have insufficient parameters
725 //
726 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp");
727 ShellStatus = SHELL_INVALID_PARAMETER;
728 break;
729 case 2:
730 //
731 // must have valid CWD for single parameter...
732 //
733 Cwd = ShellGetCurrentDir (NULL);
734 if (Cwd == NULL) {
735 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp");
736 ShellStatus = SHELL_INVALID_PARAMETER;
737 } else {
738 Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
739 if ((FileList == NULL) || IsListEmpty (&FileList->Link) || EFI_ERROR (Status)) {
740 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, 1));
741 ShellStatus = SHELL_NOT_FOUND;
742 } else {
743 FullCwd = AllocateZeroPool (StrSize (Cwd) + sizeof (CHAR16));
744 if (FullCwd == NULL) {
745 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cp");
746 ShellStatus = SHELL_OUT_OF_RESOURCES;
747 } else {
748 StrCpyS (FullCwd, StrSize (Cwd) / sizeof (CHAR16) + 1, Cwd);
749 ShellStatus = ProcessValidateAndCopyFiles (FileList, FullCwd, SilentMode, RecursiveMode);
750 FreePool (FullCwd);
751 }
752 }
753 }
754
755 break;
756 default:
757 //
758 // Make a big list of all the files...
759 //
760 for (ParamCount--, LoopCounter = 1; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS; LoopCounter++) {
761 if (ShellGetExecutionBreakFlag ()) {
762 break;
763 }
764
765 Status = ShellOpenFileMetaArg ((CHAR16 *)ShellCommandLineGetRawValue (Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
766 if (EFI_ERROR (Status) || (FileList == NULL) || IsListEmpty (&FileList->Link)) {
767 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, LoopCounter));
768 ShellStatus = SHELL_NOT_FOUND;
769 }
770 }
771
772 if (ShellStatus != SHELL_SUCCESS) {
773 Status = ShellCloseFileMetaArg (&FileList);
774 } else {
775 //
776 // now copy them all...
777 //
778 if ((FileList != NULL) && !IsListEmpty (&FileList->Link)) {
779 ShellStatus = ProcessValidateAndCopyFiles (FileList, PathCleanUpDirectories ((CHAR16 *)ShellCommandLineGetRawValue (Package, ParamCount)), SilentMode, RecursiveMode);
780 Status = ShellCloseFileMetaArg (&FileList);
781 if (EFI_ERROR (Status) && (ShellStatus == SHELL_SUCCESS)) {
782 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue (Package, ParamCount), ShellStatus|MAX_BIT);
783 ShellStatus = SHELL_ACCESS_DENIED;
784 }
785 }
786 }
787
788 break;
789 } // switch on parameter count
790
791 if (FileList != NULL) {
792 ShellCloseFileMetaArg (&FileList);
793 }
794
795 //
796 // free the command line package
797 //
798 ShellCommandLineFreeVarList (Package);
799 }
800
801 if (ShellGetExecutionBreakFlag ()) {
802 return (SHELL_ABORTED);
803 }
804
805 return (ShellStatus);
806}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette