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