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