]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
ShellPkg: Fix buffer overflow issue in 'map' command.
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Mv.c
CommitLineData
a405b86d 1/** @file\r
2 Main file for mv shell level 2 function.\r
3\r
c011b6c9 4 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>\r
83c7a556 5 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
a405b86d 6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "UefiShellLevel2CommandsLib.h"\r
17\r
7fe3fbad
JC
18/**\r
19 function to determine if a move is between file systems.\r
20 \r
21 @param FullName [in] The name of the file to move.\r
22 @param Cwd [in] The current working directory\r
23 @param DestPath [in] The target location to move to\r
24\r
25 @retval TRUE The move is across file system.\r
26 @retval FALSE The move is within a file system.\r
27**/\r
7fe3fbad
JC
28BOOLEAN\r
29EFIAPI\r
30IsBetweenFileSystem(\r
31 IN CONST CHAR16 *FullName,\r
32 IN CONST CHAR16 *Cwd,\r
33 IN CONST CHAR16 *DestPath\r
34 )\r
35{\r
36 CHAR16 *Test;\r
37 CHAR16 *Test1;\r
38 UINTN Result;\r
39\r
40 Test = StrStr(FullName, L":");\r
41 if (Test == NULL && Cwd != NULL) {\r
42 Test = StrStr(Cwd, L":");\r
43 }\r
44 Test1 = StrStr(DestPath, L":");\r
45 if (Test1 == NULL && Cwd != NULL) {\r
46 Test1 = StrStr(Cwd, L":");\r
47 }\r
48 if (Test1 != NULL && Test != NULL) {\r
49 *Test = CHAR_NULL;\r
50 *Test1 = CHAR_NULL;\r
51 Result = StringNoCaseCompare(&FullName, &DestPath);\r
52 *Test = L':';\r
53 *Test1 = L':';\r
54 if (Result != 0) {\r
55 return (TRUE);\r
56 }\r
57 }\r
58 return (FALSE);\r
59}\r
60\r
a405b86d 61/**\r
62 Function to validate that moving a specific file (FileName) to a specific\r
63 location (DestPath) is valid.\r
64\r
65 This function will verify that the destination is not a subdirectory of\r
66 FullName, that the Current working Directory is not being moved, and that\r
67 the directory is not read only.\r
68\r
69 if the move is invalid this function will report the error to StdOut.\r
70\r
4c4d470e
QS
71 @param SourcePath [in] The name of the file to move.\r
72 @param Cwd [in] The current working directory\r
73 @param DestPath [in] The target location to move to\r
74 @param Attribute [in] The Attribute of the file\r
75 @param DestAttr [in] The Attribute of the destination\r
76 @param FileStatus [in] The Status of the file when opened\r
a405b86d 77\r
78 @retval TRUE The move is valid\r
79 @retval FALSE The move is not\r
80**/\r
81BOOLEAN\r
82EFIAPI\r
83IsValidMove(\r
7fe3fbad 84 IN CONST CHAR16 *SourcePath,\r
83c7a556
CP
85 IN CONST CHAR16 *Cwd,\r
86 IN CONST CHAR16 *DestPath,\r
87 IN CONST UINT64 Attribute,\r
7fe3fbad 88 IN CONST UINT64 DestAttr,\r
83c7a556 89 IN CONST EFI_STATUS FileStatus\r
a405b86d 90 )\r
91{\r
7fe3fbad
JC
92 CHAR16 *DestPathCopy;\r
93 CHAR16 *DestPathWalker;\r
94\r
95 if (Cwd != NULL && StrCmp(SourcePath, Cwd) == 0) {\r
a405b86d 96 //\r
97 // Invalid move\r
98 //\r
99 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle);\r
100 return (FALSE);\r
101 }\r
7fe3fbad
JC
102\r
103 //\r
104 // invalid to move read only or move to a read only destination\r
105 //\r
106 if (((Attribute & EFI_FILE_READ_ONLY) != 0) \r
107 || (FileStatus == EFI_WRITE_PROTECTED)\r
108 || ((DestAttr & EFI_FILE_READ_ONLY) != 0)\r
109 ) {\r
110 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle, SourcePath);\r
111 return (FALSE);\r
112 } \r
113 \r
114 DestPathCopy = AllocateCopyPool(StrSize(DestPath), DestPath);\r
115 if (DestPathCopy == NULL) {\r
116 return (FALSE);\r
a405b86d 117 }\r
7fe3fbad
JC
118\r
119 for (DestPathWalker = DestPathCopy; *DestPathWalker == L'\\'; DestPathWalker++) ;\r
120\r
121 while(DestPathWalker != NULL && DestPathWalker[StrLen(DestPathWalker)-1] == L'\\') {\r
122 DestPathWalker[StrLen(DestPathWalker)-1] = CHAR_NULL;\r
a405b86d 123 }\r
7fe3fbad
JC
124\r
125 ASSERT(DestPathWalker != NULL);\r
126 ASSERT(SourcePath != NULL);\r
127\r
128 //\r
129 // If they're the same, or if source is "above" dest on file path tree\r
130 //\r
bf6bbc21 131 if ( StringNoCaseCompare (&DestPathWalker, &SourcePath) == 0 \r
7fe3fbad
JC
132 || StrStr(DestPathWalker, SourcePath) == DestPathWalker \r
133 ) {\r
a405b86d 134 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);\r
7fe3fbad 135 FreePool(DestPathCopy);\r
a405b86d 136 return (FALSE);\r
137 }\r
7fe3fbad
JC
138 FreePool(DestPathCopy);\r
139\r
a405b86d 140 return (TRUE);\r
141}\r
142\r
143/**\r
144 Function to take a destination path that might contain wildcards and verify\r
145 that there is only a single possible target (IE we cant have wildcards that\r
146 have 2 possible destination).\r
147\r
148 if the result is sucessful the caller must free *DestPathPointer.\r
149\r
7fe3fbad 150 @param[in] DestParameter The original path to the destination.\r
4ff7e37b
ED
151 @param[in, out] DestPathPointer A pointer to the callee allocated final path.\r
152 @param[in] Cwd A pointer to the current working directory.\r
4c4d470e
QS
153 @param[in] SingleSource TRUE to have only one source file.\r
154 @param[in, out] DestAttr A pointer to the destination information attribute.\r
a405b86d 155\r
7fe3fbad
JC
156 @retval SHELL_INVALID_PARAMETER The DestParameter could not be resolved to a location.\r
157 @retval SHELL_INVALID_PARAMETER The DestParameter could be resolved to more than 1 location.\r
beab0fc5 158 @retval SHELL_INVALID_PARAMETER Cwd is required and is NULL.\r
159 @retval SHELL_SUCCESS The operation was sucessful.\r
a405b86d 160**/\r
161SHELL_STATUS\r
162EFIAPI\r
163GetDestinationLocation(\r
7fe3fbad 164 IN CONST CHAR16 *DestParameter,\r
a405b86d 165 IN OUT CHAR16 **DestPathPointer,\r
7fe3fbad
JC
166 IN CONST CHAR16 *Cwd,\r
167 IN CONST BOOLEAN SingleSource,\r
168 IN OUT UINT64 *DestAttr\r
a405b86d 169 )\r
170{\r
171 EFI_SHELL_FILE_INFO *DestList;\r
172 EFI_SHELL_FILE_INFO *Node;\r
a405b86d 173 CHAR16 *DestPath;\r
a405b86d 174 UINTN NewSize;\r
c32ad351 175 UINTN CurrentSize;\r
a405b86d 176\r
177 DestList = NULL;\r
178 DestPath = NULL;\r
b54fd049 179\r
7fe3fbad
JC
180 ASSERT(DestAttr != NULL);\r
181\r
182 if (StrStr(DestParameter, L"\\") == DestParameter) {\r
beab0fc5 183 if (Cwd == NULL) {\r
184 return SHELL_INVALID_PARAMETER;\r
185 }\r
b54fd049 186 DestPath = AllocateZeroPool(StrSize(Cwd));\r
187 if (DestPath == NULL) {\r
188 return (SHELL_OUT_OF_RESOURCES);\r
189 }\r
190 StrCpy(DestPath, Cwd);\r
ab94587a 191 while (PathRemoveLastItem(DestPath)) ;\r
c32ad351
CP
192\r
193 //\r
7fe3fbad 194 // Append DestParameter beyond '\' which may be present\r
c32ad351
CP
195 //\r
196 CurrentSize = StrSize(DestPath);\r
7fe3fbad 197 StrnCatGrow(&DestPath, &CurrentSize, &DestParameter[1], 0);\r
c32ad351 198\r
b54fd049 199 *DestPathPointer = DestPath;\r
200 return (SHELL_SUCCESS);\r
201 }\r
a405b86d 202 //\r
203 // get the destination path\r
204 //\r
7fe3fbad 205 ShellOpenFileMetaArg((CHAR16*)DestParameter, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);\r
a405b86d 206 if (DestList == NULL || IsListEmpty(&DestList->Link)) {\r
207 //\r
208 // Not existing... must be renaming\r
209 //\r
7fe3fbad 210 if (StrStr(DestParameter, L":") == NULL) {\r
beab0fc5 211 if (Cwd == NULL) {\r
212 ShellCloseFileMetaArg(&DestList);\r
7fe3fbad 213 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);\r
beab0fc5 214 return (SHELL_INVALID_PARAMETER);\r
215 }\r
a405b86d 216 NewSize = StrSize(Cwd);\r
7fe3fbad 217 NewSize += StrSize(DestParameter);\r
a405b86d 218 DestPath = AllocateZeroPool(NewSize);\r
9ea69f8a 219 if (DestPath == NULL) {\r
220 ShellCloseFileMetaArg(&DestList);\r
221 return (SHELL_OUT_OF_RESOURCES);\r
222 }\r
a405b86d 223 StrCpy(DestPath, Cwd);\r
7fe3fbad 224 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestParameter[0] != L'\\') {\r
a405b86d 225 StrCat(DestPath, L"\\");\r
7fe3fbad 226 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestParameter[0] == L'\\') {\r
a405b86d 227 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
228 }\r
7fe3fbad 229 StrCat(DestPath, DestParameter);\r
a405b86d 230 } else {\r
231 ASSERT(DestPath == NULL);\r
7fe3fbad 232 DestPath = StrnCatGrow(&DestPath, NULL, DestParameter, 0);\r
9ea69f8a 233 if (DestPath == NULL) {\r
234 ShellCloseFileMetaArg(&DestList);\r
235 return (SHELL_OUT_OF_RESOURCES);\r
236 }\r
a405b86d 237 }\r
238 } else {\r
239 Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link);\r
7fe3fbad 240 *DestAttr = Node->Info->Attribute;\r
a405b86d 241 //\r
242 // Make sure there is only 1 node in the list.\r
243 //\r
244 if (!IsNodeAtEnd(&DestList->Link, &Node->Link)) {\r
245 ShellCloseFileMetaArg(&DestList);\r
099e8ff5 246 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter); \r
a405b86d 247 return (SHELL_INVALID_PARAMETER);\r
248 }\r
7fe3fbad
JC
249\r
250 //\r
251 // If we are a directory or a single file, then one node is fine.\r
252 //\r
253 if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS || SingleSource) {\r
a405b86d 254 DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16));\r
9ea69f8a 255 if (DestPath == NULL) {\r
256 ShellCloseFileMetaArg(&DestList);\r
257 return (SHELL_OUT_OF_RESOURCES);\r
258 }\r
a405b86d 259 StrCpy(DestPath, Node->FullName);\r
260 StrCat(DestPath, L"\\");\r
261 } else {\r
262 //\r
7fe3fbad 263 // cant move multiple files onto a single file.\r
a405b86d 264 //\r
265 ShellCloseFileMetaArg(&DestList);\r
099e8ff5 266 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter); \r
a405b86d 267 return (SHELL_INVALID_PARAMETER);\r
268 }\r
269 }\r
270\r
271 *DestPathPointer = DestPath;\r
272 ShellCloseFileMetaArg(&DestList);\r
273\r
274 return (SHELL_SUCCESS);\r
275}\r
276\r
4c4d470e
QS
277/**\r
278 Function to do a move across file systems.\r
279\r
280 @param[in] Node A pointer to the file to be removed.\r
281 @param[in] DestPath A pointer to the destination file path.\r
282 @param[out] Resp A pointer to response from question. Pass back on looped calling\r
283\r
284 @retval SHELL_SUCCESS The source file was moved to the destination.\r
285**/\r
7fe3fbad
JC
286EFI_STATUS\r
287EFIAPI\r
288MoveBetweenFileSystems(\r
289 IN EFI_SHELL_FILE_INFO *Node,\r
290 IN CONST CHAR16 *DestPath,\r
291 OUT VOID **Resp\r
292 )\r
293{\r
bf6bbc21 294 SHELL_STATUS ShellStatus;\r
7fe3fbad
JC
295\r
296 //\r
297 // First we copy the file\r
298 //\r
bf6bbc21 299 ShellStatus = CopySingleFile (Node->FullName, DestPath, Resp, TRUE, L"mv");\r
7fe3fbad
JC
300\r
301 //\r
302 // Check our result\r
303 //\r
bf6bbc21 304 if (ShellStatus == SHELL_SUCCESS) {\r
7fe3fbad
JC
305 //\r
306 // The copy was successful. delete the source file.\r
307 //\r
308 CascadeDelete(Node, TRUE);\r
309 Node->Handle = NULL;\r
bf6bbc21
TS
310 } else if (ShellStatus == SHELL_ABORTED) {\r
311 return EFI_ABORTED;\r
312 } else if (ShellStatus == SHELL_ACCESS_DENIED) {\r
313 return EFI_ACCESS_DENIED;\r
314 } else if (ShellStatus == SHELL_VOLUME_FULL) {\r
315 return EFI_VOLUME_FULL;\r
316 } else {\r
317 return EFI_UNSUPPORTED;\r
7fe3fbad
JC
318 }\r
319\r
bf6bbc21 320 return (EFI_SUCCESS);\r
7fe3fbad
JC
321}\r
322\r
4c4d470e
QS
323/**\r
324 Function to take the destination path and target file name to generate the full destination path.\r
325\r
326 @param[in] DestPath A pointer to the destination file path string.\r
327 @param[out] FullDestPath A pointer to the full destination path string.\r
328 @param[in] FileName Name string of the targe file.\r
329\r
330 @retval SHELL_SUCCESS the files were all moved.\r
331 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
332 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
333**/\r
7fe3fbad
JC
334EFI_STATUS\r
335EFIAPI\r
336CreateFullDestPath(\r
337 IN CONST CHAR16 **DestPath,\r
338 OUT CHAR16 **FullDestPath, \r
339 IN CONST CHAR16 *FileName\r
340 )\r
341{\r
342 UINTN Size;\r
343 if (FullDestPath == NULL || FileName == NULL || DestPath == NULL || *DestPath == NULL){\r
344 return (EFI_INVALID_PARAMETER);\r
345 }\r
346\r
347 Size = StrSize(*DestPath) + StrSize(FileName);\r
348\r
349 *FullDestPath = AllocateZeroPool(Size);\r
350 if (*FullDestPath == NULL){\r
351 return (EFI_OUT_OF_RESOURCES);\r
352 }\r
353\r
354 StrnCpy(*FullDestPath, *DestPath, Size / sizeof(CHAR16) - 1);\r
355 if ((*FullDestPath)[StrLen(*FullDestPath)-1] != L'\\' && FileName[0] != L'\\') {\r
356 StrnCat(*FullDestPath, L"\\",Size / sizeof(CHAR16) - 1 - StrLen(*FullDestPath));\r
357 }\r
358 StrnCat(*FullDestPath, FileName, Size / sizeof(CHAR16) - 1 - StrLen(*FullDestPath));\r
359\r
360 return (EFI_SUCCESS);\r
361}\r
362\r
4c4d470e
QS
363/**\r
364 Function to do a move within a file system.\r
365\r
366 @param[in] Node A pointer to the file to be removed.\r
367 @param[in] DestPath A pointer to the destination file path.\r
368 @param[out] Resp A pointer to response from question. Pass back on looped calling.\r
369\r
370 @retval SHELL_SUCCESS The source file was moved to the destination.\r
371 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.\r
372**/\r
7fe3fbad
JC
373EFI_STATUS\r
374EFIAPI\r
375MoveWithinFileSystems(\r
376 IN EFI_SHELL_FILE_INFO *Node,\r
377 IN CHAR16 *DestPath,\r
378 OUT VOID **Resp\r
379 )\r
380{\r
381 EFI_FILE_INFO *NewFileInfo;\r
382 CHAR16 *TempLocation;\r
383 UINTN NewSize;\r
384 UINTN Length;\r
385 EFI_STATUS Status;\r
386\r
387 //\r
388 // Chop off map info from DestPath\r
389 //\r
390 if ((TempLocation = StrStr(DestPath, L":")) != NULL) {\r
391 CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1));\r
392 }\r
393\r
394 //\r
395 // construct the new file info block\r
396 //\r
397 NewSize = StrSize(DestPath);\r
398 NewSize += StrSize(Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);\r
399 NewFileInfo = AllocateZeroPool(NewSize);\r
400 if (NewFileInfo == NULL) {\r
401 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);\r
402 Status = EFI_OUT_OF_RESOURCES;\r
403 } else {\r
404 CopyMem(NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO);\r
405 if (DestPath[0] != L'\\') {\r
406 StrCpy(NewFileInfo->FileName, L"\\");\r
407 StrCat(NewFileInfo->FileName, DestPath);\r
408 } else {\r
409 StrCpy(NewFileInfo->FileName, DestPath);\r
410 }\r
411 Length = StrLen(NewFileInfo->FileName);\r
412 if (Length > 0) {\r
413 Length--;\r
414 }\r
415 if (NewFileInfo->FileName[Length] == L'\\') {\r
416 if (Node->FileName[0] == L'\\') {\r
417 //\r
418 // Don't allow for double slashes. Eliminate one of them.\r
419 //\r
420 NewFileInfo->FileName[Length] = CHAR_NULL;\r
421 }\r
422 StrCat(NewFileInfo->FileName, Node->FileName);\r
423 }\r
424 NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize(NewFileInfo->FileName);\r
425\r
426 //\r
427 // Perform the move operation\r
428 //\r
429 Status = ShellSetFileInfo(Node->Handle, NewFileInfo);\r
430\r
431 //\r
432 // Free the info object we used...\r
433 //\r
434 FreePool(NewFileInfo);\r
435 }\r
436\r
437 return (Status);\r
438}\r
a405b86d 439/**\r
440 function to take a list of files to move and a destination location and do\r
441 the verification and moving of those files to that location. This function\r
442 will report any errors to the user and continue to move the rest of the files.\r
443\r
444 @param[in] FileList A LIST_ENTRY* based list of files to move\r
b54fd049 445 @param[out] Resp pointer to response from question. Pass back on looped calling\r
7fe3fbad 446 @param[in] DestParameter the originally specified destination location\r
a405b86d 447\r
448 @retval SHELL_SUCCESS the files were all moved.\r
449 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
450 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
451 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
452 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
453**/\r
454SHELL_STATUS\r
455EFIAPI\r
456ValidateAndMoveFiles(\r
7fe3fbad 457 IN EFI_SHELL_FILE_INFO *FileList,\r
b54fd049 458 OUT VOID **Resp,\r
7fe3fbad 459 IN CONST CHAR16 *DestParameter\r
a405b86d 460 )\r
461{\r
462 EFI_STATUS Status;\r
463 CHAR16 *HiiOutput;\r
464 CHAR16 *HiiResultOk;\r
465 CHAR16 *DestPath;\r
7fe3fbad 466 CHAR16 *FullDestPath;\r
a405b86d 467 CONST CHAR16 *Cwd;\r
468 SHELL_STATUS ShellStatus;\r
7fe3fbad 469 EFI_SHELL_FILE_INFO *Node;\r
b54fd049 470 VOID *Response;\r
7fe3fbad 471 UINT64 Attr;\r
0960ba17 472 CHAR16 *CleanFilePathStr;\r
a405b86d 473\r
474 ASSERT(FileList != NULL);\r
7fe3fbad 475 ASSERT(DestParameter != NULL);\r
a405b86d 476\r
7fe3fbad
JC
477 DestPath = NULL;\r
478 FullDestPath = NULL;\r
479 Cwd = ShellGetCurrentDir(NULL);\r
480 Response = *Resp;\r
481 Attr = 0;\r
482 CleanFilePathStr = NULL;\r
a405b86d 483\r
7fe3fbad 484 Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr);\r
0960ba17
QS
485 if (EFI_ERROR (Status)) {\r
486 if (Status == EFI_OUT_OF_RESOURCES) {\r
487 return SHELL_OUT_OF_RESOURCES;\r
488 } else {\r
489 return SHELL_INVALID_PARAMETER;\r
490 }\r
7fe3fbad 491 }\r
0960ba17 492\r
427d61ad
QS
493 ASSERT (CleanFilePathStr != NULL);\r
494\r
a405b86d 495 //\r
496 // Get and validate the destination location\r
497 //\r
65ef0b0d 498 ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, Cwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr);\r
0960ba17 499 FreePool (CleanFilePathStr);\r
7fe3fbad 500\r
a405b86d 501 if (ShellStatus != SHELL_SUCCESS) {\r
502 return (ShellStatus);\r
503 }\r
ab94587a 504 DestPath = PathCleanUpDirectories(DestPath);\r
7fe3fbad
JC
505 if (DestPath == NULL) {\r
506 return (SHELL_OUT_OF_RESOURCES);\r
507 }\r
a405b86d 508\r
509 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);\r
510 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);\r
7fe3fbad
JC
511 if (HiiOutput == NULL || HiiResultOk == NULL) {\r
512 SHELL_FREE_NON_NULL(DestPath);\r
513 SHELL_FREE_NON_NULL(HiiOutput);\r
514 SHELL_FREE_NON_NULL(HiiResultOk);\r
515 return (SHELL_OUT_OF_RESOURCES);\r
516 }\r
a405b86d 517\r
518 //\r
519 // Go through the list of files and directories to move...\r
520 //\r
521 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
522 ; !IsNull(&FileList->Link, &Node->Link)\r
523 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
524 ){\r
525 if (ShellGetExecutionBreakFlag()) {\r
526 break;\r
527 }\r
83c7a556
CP
528\r
529 //\r
530 // These should never be NULL\r
531 //\r
a405b86d 532 ASSERT(Node->FileName != NULL);\r
533 ASSERT(Node->FullName != NULL);\r
83c7a556 534 ASSERT(Node->Info != NULL);\r
a405b86d 535\r
536 //\r
537 // skip the directory traversing stuff...\r
538 //\r
539 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
540 continue;\r
541 }\r
542\r
7fe3fbad
JC
543 SHELL_FREE_NON_NULL(FullDestPath);\r
544 FullDestPath = NULL;\r
545 if (ShellIsDirectory(DestPath)==EFI_SUCCESS) {\r
e456bb84 546 CreateFullDestPath((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName);\r
7fe3fbad
JC
547 }\r
548\r
a405b86d 549 //\r
550 // Validate that the move is valid\r
551 //\r
4c4d470e 552 if (!IsValidMove(Node->FullName, Cwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) {\r
a405b86d 553 ShellStatus = SHELL_INVALID_PARAMETER;\r
554 continue;\r
555 }\r
556\r
4c4d470e 557 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, FullDestPath!=NULL? FullDestPath:DestPath);\r
a405b86d 558\r
559 //\r
7fe3fbad 560 // See if destination exists\r
a405b86d 561 //\r
4c4d470e 562 if (!EFI_ERROR(ShellFileExists(FullDestPath!=NULL? FullDestPath:DestPath))) {\r
7fe3fbad
JC
563 if (Response == NULL) {\r
564 ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
a405b86d 565 }\r
7fe3fbad
JC
566 switch (*(SHELL_PROMPT_RESPONSE*)Response) {\r
567 case ShellPromptResponseNo:\r
568 FreePool(Response);\r
569 Response = NULL;\r
570 continue;\r
571 case ShellPromptResponseCancel:\r
572 *Resp = Response;\r
9ea69f8a 573 //\r
7fe3fbad 574 // indicate to stop everything\r
9ea69f8a 575 //\r
7fe3fbad
JC
576 return (SHELL_ABORTED);\r
577 case ShellPromptResponseAll:\r
578 *Resp = Response;\r
579 break;\r
580 case ShellPromptResponseYes:\r
581 FreePool(Response);\r
582 Response = NULL;\r
583 break;\r
584 default:\r
585 FreePool(Response);\r
586 return SHELL_ABORTED;\r
b54fd049 587 }\r
4c4d470e 588 Status = ShellDeleteFileByName(FullDestPath!=NULL? FullDestPath:DestPath);\r
7fe3fbad 589 }\r
b54fd049 590\r
7fe3fbad
JC
591 if (IsBetweenFileSystem(Node->FullName, Cwd, DestPath)) {\r
592 while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen(DestPath) - 1] == L'\\') {\r
593 DestPath[StrLen(DestPath) - 1] = CHAR_NULL;\r
594 }\r
4c4d470e 595 Status = MoveBetweenFileSystems(Node, FullDestPath!=NULL? FullDestPath:DestPath, &Response);\r
7fe3fbad
JC
596 } else {\r
597 Status = MoveWithinFileSystems(Node, DestPath, &Response);\r
bf6bbc21
TS
598 //\r
599 // Display error status\r
600 //\r
601 if (EFI_ERROR(Status)) {\r
602 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"mv", Status);\r
603 }\r
7fe3fbad 604 }\r
b54fd049 605\r
7fe3fbad
JC
606 //\r
607 // Check our result\r
608 //\r
609 if (EFI_ERROR(Status)) {\r
7fe3fbad
JC
610 ShellStatus = SHELL_INVALID_PARAMETER;\r
611 if (Status == EFI_SECURITY_VIOLATION) {\r
612 ShellStatus = SHELL_SECURITY_VIOLATION;\r
613 } else if (Status == EFI_WRITE_PROTECTED) {\r
614 ShellStatus = SHELL_WRITE_PROTECTED;\r
615 } else if (Status == EFI_OUT_OF_RESOURCES) {\r
616 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
617 } else if (Status == EFI_DEVICE_ERROR) {\r
618 ShellStatus = SHELL_DEVICE_ERROR;\r
619 } else if (Status == EFI_ACCESS_DENIED) {\r
620 ShellStatus = SHELL_ACCESS_DENIED;\r
9ea69f8a 621 }\r
7fe3fbad
JC
622 } else {\r
623 ShellPrintEx(-1, -1, L"%s", HiiResultOk);\r
a405b86d 624 }\r
a405b86d 625\r
7fe3fbad
JC
626 } // main for loop\r
627\r
628 SHELL_FREE_NON_NULL(FullDestPath);\r
629 SHELL_FREE_NON_NULL(DestPath);\r
630 SHELL_FREE_NON_NULL(HiiOutput);\r
631 SHELL_FREE_NON_NULL(HiiResultOk);\r
a405b86d 632 return (ShellStatus);\r
633}\r
634\r
b54fd049 635/**\r
636 Function for 'mv' command.\r
637\r
638 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
639 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
640**/\r
a405b86d 641SHELL_STATUS\r
642EFIAPI\r
643ShellCommandRunMv (\r
644 IN EFI_HANDLE ImageHandle,\r
645 IN EFI_SYSTEM_TABLE *SystemTable\r
646 )\r
647{\r
648 EFI_STATUS Status;\r
649 LIST_ENTRY *Package;\r
650 CHAR16 *ProblemParam;\r
651 SHELL_STATUS ShellStatus;\r
652 UINTN ParamCount;\r
653 UINTN LoopCounter;\r
654 EFI_SHELL_FILE_INFO *FileList;\r
b54fd049 655 VOID *Response;\r
a405b86d 656\r
657 ProblemParam = NULL;\r
658 ShellStatus = SHELL_SUCCESS;\r
659 ParamCount = 0;\r
660 FileList = NULL;\r
b54fd049 661 Response = NULL;\r
a405b86d 662\r
663 //\r
664 // initialize the shell lib (we must be in non-auto-init...)\r
665 //\r
666 Status = ShellInitialize();\r
667 ASSERT_EFI_ERROR(Status);\r
668\r
669 //\r
670 // parse the command line\r
671 //\r
672 Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);\r
673 if (EFI_ERROR(Status)) {\r
674 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
099e8ff5 675 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"mv", ProblemParam); \r
a405b86d 676 FreePool(ProblemParam);\r
677 ShellStatus = SHELL_INVALID_PARAMETER;\r
678 } else {\r
679 ASSERT(FALSE);\r
680 }\r
681 } else {\r
682 //\r
683 // check for "-?"\r
684 //\r
685 if (ShellCommandLineGetFlag(Package, L"-?")) {\r
686 ASSERT(FALSE);\r
687 }\r
688\r
689 switch (ParamCount = ShellCommandLineGetCount(Package)) {\r
690 case 0:\r
691 case 1:\r
692 //\r
693 // we have insufficient parameters\r
694 //\r
099e8ff5 695 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mv"); \r
a405b86d 696 ShellStatus = SHELL_INVALID_PARAMETER;\r
697 break;\r
698 case 2:\r
699 //\r
700 // must have valid CWD for single parameter...\r
701 //\r
702 if (ShellGetCurrentDir(NULL) == NULL){\r
099e8ff5 703 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"mv"); \r
a405b86d 704 ShellStatus = SHELL_INVALID_PARAMETER;\r
705 } else {\r
706 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
707 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
099e8ff5 708 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1)); \r
a405b86d 709 ShellStatus = SHELL_NOT_FOUND;\r
710 } else {\r
711 //\r
712 // ValidateAndMoveFiles will report errors to the screen itself\r
713 //\r
b54fd049 714 ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellGetCurrentDir(NULL));\r
a405b86d 715 }\r
716 }\r
717\r
718 break;\r
719 default:\r
720 ///@todo make sure this works with error half way through and continues...\r
b54fd049 721 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount ; LoopCounter++) {\r
a405b86d 722 if (ShellGetExecutionBreakFlag()) {\r
723 break;\r
724 }\r
725 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
726 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
099e8ff5 727 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, LoopCounter)); \r
a405b86d 728 ShellStatus = SHELL_NOT_FOUND;\r
729 } else {\r
730 //\r
731 // ValidateAndMoveFiles will report errors to the screen itself\r
732 // Only change ShellStatus if it's sucessful\r
733 //\r
734 if (ShellStatus == SHELL_SUCCESS) {\r
b54fd049 735 ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));\r
a405b86d 736 } else {\r
b54fd049 737 ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));\r
a405b86d 738 }\r
739 }\r
740 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
741 Status = ShellCloseFileMetaArg(&FileList);\r
742 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
743 ShellStatus = SHELL_ACCESS_DENIED;\r
099e8ff5 744 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT); \r
a405b86d 745 }\r
746 }\r
747 }\r
748 break;\r
749 } // switch on parameter count\r
750\r
751 if (FileList != NULL) {\r
752 ShellCloseFileMetaArg(&FileList);\r
753 }\r
754\r
755 //\r
756 // free the command line package\r
757 //\r
758 ShellCommandLineFreeVarList (Package);\r
759 }\r
760\r
b54fd049 761 SHELL_FREE_NON_NULL(Response);\r
762\r
a405b86d 763 if (ShellGetExecutionBreakFlag()) {\r
764 return (SHELL_ABORTED);\r
765 }\r
766\r
767 return (ShellStatus);\r
768}\r