]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Cp.c
e35bf18824a69532035a767474503a4c4830f106
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Cp.c
1 /** @file
2 Main file for cp shell level 2 function.
3
4 Copyright (c) 2009 - 2010, 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
17 // this is later in the file.
18 SHELL_STATUS
19 EFIAPI
20 ValidateAndCopyFiles(
21 IN CONST EFI_SHELL_FILE_INFO *FileList,
22 IN CONST CHAR16 *DestDir,
23 IN BOOLEAN SilentMode,
24 IN BOOLEAN RecursiveMode,
25 IN VOID **Resp
26 );
27
28 /**
29 Function to Copy one file to another location
30
31 If the destination exists the user will be prompted and the result put into *resp
32
33 @param[in] Source pointer to source file name
34 @param[in] Dest pointer to destination file name
35 @param[out] Resp pointer to response from question. Pass back on looped calling
36 @param[in] SilentMode whether to run in quiet mode or not
37
38 @retval SHELL_SUCCESS The source file was copied to the destination
39 **/
40 SHELL_STATUS
41 EFIAPI
42 CopySingleFile(
43 IN CONST CHAR16 *Source,
44 IN CONST CHAR16 *Dest,
45 OUT VOID **Resp,
46 IN BOOLEAN SilentMode
47 )
48 {
49 VOID *Response;
50 UINTN ReadSize;
51 SHELL_FILE_HANDLE SourceHandle;
52 SHELL_FILE_HANDLE DestHandle;
53 EFI_STATUS Status;
54 VOID *Buffer;
55 CHAR16 *TempName;
56 UINTN Size;
57 EFI_SHELL_FILE_INFO *List;
58 SHELL_STATUS ShellStatus;
59
60
61 ASSERT(Resp != NULL);
62
63 SourceHandle = NULL;
64 DestHandle = NULL;
65 Response = *Resp;
66 List = NULL;
67
68 ReadSize = PcdGet16(PcdShellFileOperationSize);
69 // Why bother copying a file to itself
70 if (StrCmp(Source, Dest) == 0) {
71 return (SHELL_SUCCESS);
72 }
73
74 //
75 // Open destination file without create
76 //
77 Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);
78
79 //
80 // close file
81 //
82 if (DestHandle != NULL) {
83 ShellCloseFile(&DestHandle);
84 DestHandle = NULL;
85 }
86
87 //
88 // if the destination file existed check response and possibly prompt user
89 //
90 if (!EFI_ERROR(Status)) {
91 if (Response == NULL && !SilentMode) {
92 Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_CP_PROMPT), gShellLevel2HiiHandle, &Response);
93 }
94 //
95 // possibly return based on response
96 //
97 if (!SilentMode) {
98 switch (*(SHELL_PROMPT_RESPONSE*)Response) {
99 case ShellPromptResponseNo:
100 //
101 // return success here so we dont stop the process
102 //
103 return (SHELL_SUCCESS);
104 case ShellPromptResponseCancel:
105 *Resp = Response;
106 //
107 // indicate to stop everything
108 //
109 return (SHELL_ABORTED);
110 case ShellPromptResponseAll:
111 *Resp = Response;
112 case ShellPromptResponseYes:
113 break;
114 }
115 }
116 }
117
118 if (ShellIsDirectory(Source) == EFI_SUCCESS) {
119 Status = ShellCreateDirectory(Dest, &DestHandle);
120 if (EFI_ERROR(Status)) {
121 return (SHELL_ACCESS_DENIED);
122 }
123
124 //
125 // Now copy all the files under the directory...
126 //
127 TempName = NULL;
128 Size = 0;
129 StrnCatGrow(&TempName, &Size, Source, 0);
130 StrnCatGrow(&TempName, &Size, L"\\*", 0);
131 ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List);
132 TempName = NULL;
133 StrnCatGrow(&TempName, &Size, Dest, 0);
134 StrnCatGrow(&TempName, &Size, L"\\", 0);
135 ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp);
136 ShellCloseFileMetaArg(&List);
137 FreePool(TempName);
138 Size = 0;
139 } else {
140 //
141 // open file with create enabled
142 //
143 Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0);
144 if (EFI_ERROR(Status)) {
145 return (SHELL_ACCESS_DENIED);
146 }
147
148 //
149 // open source file
150 //
151 Status = ShellOpenFileByName(Source, &SourceHandle, EFI_FILE_MODE_READ, 0);
152 ASSERT_EFI_ERROR(Status);
153
154 //
155 // copy data between files
156 //
157 Buffer = AllocateZeroPool(ReadSize);
158 ASSERT(Buffer != NULL);
159 while (ReadSize == PcdGet16(PcdShellFileOperationSize) && !EFI_ERROR(Status)) {
160 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer);
161 ASSERT_EFI_ERROR(Status);
162 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer);
163 }
164 }
165
166 //
167 // close files
168 //
169 if (DestHandle != NULL) {
170 ShellCloseFile(&DestHandle);
171 DestHandle = NULL;
172 }
173 if (SourceHandle != NULL) {
174 ShellCloseFile(&SourceHandle);
175 SourceHandle = NULL;
176 }
177
178 //
179 // return
180 //
181 return (SHELL_SUCCESS);
182 }
183
184 /**
185 function to take a list of files to copy and a destination location and do
186 the verification and copying of those files to that location. This function
187 will report any errors to the user and halt.
188
189 The key is to have this function called ONLY once. this allows for the parameter
190 verification to happen correctly.
191
192 @param[in] FileList A LIST_ENTRY* based list of files to move
193 @param[in] DestDir the destination location
194
195 @retval SHELL_SUCCESS the files were all moved.
196 @retval SHELL_INVALID_PARAMETER a parameter was invalid
197 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
198 @retval SHELL_WRITE_PROTECTED the destination was write protected
199 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
200 **/
201 SHELL_STATUS
202 EFIAPI
203 ValidateAndCopyFiles(
204 IN CONST EFI_SHELL_FILE_INFO *FileList,
205 IN CONST CHAR16 *DestDir,
206 IN BOOLEAN SilentMode,
207 IN BOOLEAN RecursiveMode,
208 IN VOID **Resp
209 )
210 {
211 CHAR16 *HiiOutput;
212 CHAR16 *HiiResultOk;
213 CONST EFI_SHELL_FILE_INFO *Node;
214 SHELL_STATUS ShellStatus;
215 CHAR16 *DestPath;
216 VOID *Response;
217 UINTN PathLen;
218 CONST CHAR16 *Cwd;
219 CONST CHAR16 *TempLocation;
220 UINTN NewSize;
221
222 if (Resp == NULL) {
223 Response = NULL;
224 } else {
225 Response = *Resp;
226 }
227
228 DestPath = NULL;
229 ShellStatus = SHELL_SUCCESS;
230 PathLen = 0;
231 Cwd = ShellGetCurrentDir(NULL);
232
233 ASSERT(FileList != NULL);
234 ASSERT(DestDir != NULL);
235
236 //
237 // If we are trying to copy multiple files... make sure we got a directory for the target...
238 //
239 if (EFI_ERROR(ShellIsDirectory(DestDir)) && FileList->Link.ForwardLink != FileList->Link.BackLink) {
240 //
241 // Error for destination not a directory
242 //
243 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir);
244 return (SHELL_INVALID_PARAMETER);
245 }
246 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
247 ; !IsNull(&FileList->Link, &Node->Link)
248 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
249 ){
250 //
251 // skip the directory traversing stuff...
252 //
253 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
254 continue;
255 }
256
257 NewSize = StrSize(DestDir);
258 NewSize += StrSize(Node->FileName);
259 NewSize += StrSize(Cwd);
260 if (NewSize > PathLen) {
261 PathLen = NewSize;
262 }
263
264 //
265 // Make sure got -r if required
266 //
267 if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) {
268 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle);
269 return (SHELL_INVALID_PARAMETER);
270 }
271
272 //
273 // make sure got dest as dir if needed
274 //
275 if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(DestDir))) {
276 //
277 // Error for destination not a directory
278 //
279 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, DestDir);
280 return (SHELL_INVALID_PARAMETER);
281 }
282 }
283
284 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL);
285 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
286 DestPath = AllocatePool(PathLen);
287
288 //
289 // Go through the list of files to copy...
290 //
291 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
292 ; !IsNull(&FileList->Link, &Node->Link)
293 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
294 ){
295 if (ShellGetExecutionBreakFlag()) {
296 break;
297 }
298 ASSERT(Node->FileName != NULL);
299 ASSERT(Node->FullName != NULL);
300
301 //
302 // skip the directory traversing stuff...
303 //
304 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
305 continue;
306 }
307
308 if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item
309 && EFI_ERROR(ShellIsDirectory(DestDir)) // not an existing directory
310 ) {
311 ASSERT(StrStr(DestDir, L":") == NULL);
312 //
313 // simple copy of a single file
314 //
315 StrCpy(DestPath, Cwd);
316 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {
317 StrCat(DestPath, L"\\");
318 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {
319 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
320 }
321 StrCat(DestPath, DestDir);
322 } else {
323 //
324 // we have multiple files or a directory in the DestDir
325 //
326 if (StrStr(DestDir, L":") == NULL) {
327 StrCpy(DestPath, Cwd);
328 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {
329 StrCat(DestPath, L"\\");
330 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {
331 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
332 }
333 StrCat(DestPath, DestDir);
334 if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') {
335 StrCat(DestPath, L"\\");
336 } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') {
337 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
338 }
339 StrCat(DestPath, Node->FileName);
340
341 } else {
342 StrCpy(DestPath, DestDir);
343 if (DestDir[StrLen(DestDir)-1] != L'\\' && Node->FileName[0] != L'\\') {
344 StrCat(DestPath, L"\\");
345 } else if (DestDir[StrLen(DestDir)-1] == L'\\' && Node->FileName[0] == L'\\') {
346 ((CHAR16*)DestDir)[StrLen(DestDir)-1] = CHAR_NULL;
347 }
348 StrCat(DestPath, Node->FileName);
349 }
350 }
351
352 //
353 // Make sure the path exists
354 //
355 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) {
356 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle);
357 ShellStatus = SHELL_DEVICE_ERROR;
358 break;
359 }
360
361 if ( !EFI_ERROR(ShellIsDirectory(Node->FullName))
362 && !EFI_ERROR(ShellIsDirectory(DestPath))
363 && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL
364 ){
365 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle);
366 ShellStatus = SHELL_INVALID_PARAMETER;
367 break;
368 }
369 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) {
370 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle);
371 ShellStatus = SHELL_INVALID_PARAMETER;
372 break;
373 }
374
375 if ((TempLocation = StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName))) == 0
376 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\')
377 ) {
378 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle);
379 ShellStatus = SHELL_INVALID_PARAMETER;
380 break;
381 }
382
383 CleanPath(DestPath);
384
385 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath);
386
387 //
388 // copy single file...
389 //
390 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode);
391 if (ShellStatus != SHELL_SUCCESS) {
392 break;
393 }
394 }
395 if (ShellStatus == SHELL_SUCCESS && Resp == NULL) {
396 ShellPrintEx(-1, -1, L"%s", HiiResultOk);
397 }
398
399 SHELL_FREE_NON_NULL(DestPath);
400 SHELL_FREE_NON_NULL(HiiOutput);
401 SHELL_FREE_NON_NULL(HiiResultOk);
402 if (Resp != NULL) {
403 SHELL_FREE_NON_NULL(Response);
404 }
405
406 return (ShellStatus);
407 }
408
409 SHELL_STATUS
410 EFIAPI
411 ProcessValidateAndCopyFiles(
412 IN EFI_SHELL_FILE_INFO *FileList,
413 IN CONST CHAR16 *DestDir,
414 IN BOOLEAN SilentMode,
415 IN BOOLEAN RecursiveMode
416 )
417 {
418 SHELL_STATUS ShellStatus;
419 EFI_SHELL_FILE_INFO *List;
420 EFI_STATUS Status;
421 EFI_FILE_INFO *FileInfo;
422
423 List = NULL;
424
425 Status = ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List);
426 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) {
427 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir);
428 ShellStatus = SHELL_INVALID_PARAMETER;
429 ShellCloseFileMetaArg(&List);
430 } else if (List != NULL) {
431 ASSERT(List != NULL);
432 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL);
433 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL);
434 FileInfo = NULL;
435 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle);
436 ASSERT(FileInfo != NULL);
437 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) {
438 ShellStatus = ValidateAndCopyFiles(FileList, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, SilentMode, RecursiveMode, NULL);
439 } else {
440 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle);
441 ShellStatus = SHELL_ACCESS_DENIED;
442 }
443 SHELL_FREE_NON_NULL(FileInfo);
444 ShellCloseFileMetaArg(&List);
445 } else {
446 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL);
447 }
448
449 return (ShellStatus);
450 }
451
452 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
453 {L"-r", TypeFlag},
454 {L"-q", TypeFlag},
455 {NULL, TypeMax}
456 };
457
458 /**
459 Function for 'cp' command.
460
461 @param[in] ImageHandle Handle to the Image (NULL if Internal).
462 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
463 **/
464 SHELL_STATUS
465 EFIAPI
466 ShellCommandRunCp (
467 IN EFI_HANDLE ImageHandle,
468 IN EFI_SYSTEM_TABLE *SystemTable
469 )
470 {
471 EFI_STATUS Status;
472 LIST_ENTRY *Package;
473 CHAR16 *ProblemParam;
474 SHELL_STATUS ShellStatus;
475 UINTN ParamCount;
476 UINTN LoopCounter;
477 EFI_SHELL_FILE_INFO *FileList;
478 BOOLEAN SilentMode;
479 BOOLEAN RecursiveMode;
480 CONST CHAR16 *Cwd;
481
482 ProblemParam = NULL;
483 ShellStatus = SHELL_SUCCESS;
484 ParamCount = 0;
485 FileList = NULL;
486
487 //
488 // initialize the shell lib (we must be in non-auto-init...)
489 //
490 Status = ShellInitialize();
491 ASSERT_EFI_ERROR(Status);
492
493 Status = CommandInit();
494 ASSERT_EFI_ERROR(Status);
495
496 //
497 // parse the command line
498 //
499 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
500 if (EFI_ERROR(Status)) {
501 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
502 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);
503 FreePool(ProblemParam);
504 ShellStatus = SHELL_INVALID_PARAMETER;
505 } else {
506 ASSERT(FALSE);
507 }
508 } else {
509 //
510 // check for "-?"
511 //
512 if (ShellCommandLineGetFlag(Package, L"-?")) {
513 ASSERT(FALSE);
514 }
515
516 //
517 // Initialize SilentMode and RecursiveMode
518 //
519 if (gEfiShellProtocol->BatchIsActive()) {
520 SilentMode = TRUE;
521 } else {
522 SilentMode = ShellCommandLineGetFlag(Package, L"-q");
523 }
524 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r");
525
526 switch (ParamCount = ShellCommandLineGetCount(Package)) {
527 case 0:
528 case 1:
529 //
530 // we have insufficient parameters
531 //
532 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle);
533 ShellStatus = SHELL_INVALID_PARAMETER;
534 break;
535 case 2:
536 //
537 // must have valid CWD for single parameter...
538 //
539 Cwd = ShellGetCurrentDir(NULL);
540 if (Cwd == NULL){
541 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
542 ShellStatus = SHELL_INVALID_PARAMETER;
543 } else {
544 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
545 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
546 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));
547 ShellStatus = SHELL_NOT_FOUND;
548 } else {
549 ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode);
550 }
551 }
552
553 break;
554 default:
555 //
556 // Make a big list of all the files...
557 //
558 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {
559 if (ShellGetExecutionBreakFlag()) {
560 break;
561 }
562 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
563 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) {
564 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));
565 ShellStatus = SHELL_NOT_FOUND;
566 }
567 }
568 //
569 // now copy them all...
570 //
571 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
572 ShellStatus = ProcessValidateAndCopyFiles(FileList, ShellCommandCleanPath((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode);
573 Status = ShellCloseFileMetaArg(&FileList);
574 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
575 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);
576 ShellStatus = SHELL_ACCESS_DENIED;
577 }
578 }
579
580 break;
581 } // switch on parameter count
582
583 if (FileList != NULL) {
584 ShellCloseFileMetaArg(&FileList);
585 }
586
587 //
588 // free the command line package
589 //
590 ShellCommandLineFreeVarList (Package);
591 }
592
593 if (ShellGetExecutionBreakFlag()) {
594 return (SHELL_ABORTED);
595 }
596
597 return (ShellStatus);
598 }
599