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