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