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