]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
ShellPkg/Application: Fix various typos
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Mv.c
... / ...
CommitLineData
1/** @file\r
2 Main file for mv shell level 2 function.\r
3\r
4 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>\r
5 Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "UefiShellLevel2CommandsLib.h"\r
11\r
12/**\r
13 function to determine if a move is between file systems.\r
14\r
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
22BOOLEAN\r
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
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
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
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
137\r
138 @retval TRUE The move is valid\r
139 @retval FALSE The move is not\r
140**/\r
141BOOLEAN\r
142IsValidMove(\r
143 IN CONST CHAR16 *SourcePath,\r
144 IN CONST CHAR16 *Cwd,\r
145 IN CONST CHAR16 *DestPath,\r
146 IN CONST UINT64 Attribute,\r
147 IN CONST UINT64 DestAttr,\r
148 IN CONST EFI_STATUS FileStatus\r
149 )\r
150{\r
151 CHAR16 *DestPathCopy;\r
152 CHAR16 *DestPathWalker;\r
153\r
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
162 }\r
163\r
164 //\r
165 // invalid to move read only or move to a read only destination\r
166 //\r
167 if (((Attribute & EFI_FILE_READ_ONLY) != 0)\r
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
173 }\r
174\r
175 DestPathCopy = AllocateCopyPool(StrSize(DestPath), DestPath);\r
176 if (DestPathCopy == NULL) {\r
177 return (FALSE);\r
178 }\r
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
184 }\r
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
192 if ( StringNoCaseCompare (&DestPathWalker, &SourcePath) == 0 ||\r
193 ((StrStr(DestPathWalker, SourcePath) == DestPathWalker) &&\r
194 (DestPathWalker[StrLen(SourcePath)] == '\\')\r
195 )\r
196 ) {\r
197 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);\r
198 FreePool(DestPathCopy);\r
199 return (FALSE);\r
200 }\r
201 FreePool(DestPathCopy);\r
202\r
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
213 @param[in] DestParameter The original path to the destination.\r
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
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
218\r
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
221 @retval SHELL_INVALID_PARAMETER Cwd is required and is NULL.\r
222 @retval SHELL_SUCCESS The operation was sucessful.\r
223**/\r
224SHELL_STATUS\r
225GetDestinationLocation(\r
226 IN CONST CHAR16 *DestParameter,\r
227 IN OUT CHAR16 **DestPathPointer,\r
228 IN CONST CHAR16 *Cwd,\r
229 IN CONST BOOLEAN SingleSource,\r
230 IN OUT UINT64 *DestAttr\r
231 )\r
232{\r
233 EFI_SHELL_FILE_INFO *DestList;\r
234 EFI_SHELL_FILE_INFO *Node;\r
235 CHAR16 *DestPath;\r
236 UINTN NewSize;\r
237 UINTN CurrentSize;\r
238\r
239 DestList = NULL;\r
240 DestPath = NULL;\r
241\r
242 ASSERT(DestAttr != NULL);\r
243\r
244 if (StrStr(DestParameter, L"\\") == DestParameter) {\r
245 if (Cwd == NULL) {\r
246 return SHELL_INVALID_PARAMETER;\r
247 }\r
248 DestPath = AllocateZeroPool(StrSize(Cwd));\r
249 if (DestPath == NULL) {\r
250 return (SHELL_OUT_OF_RESOURCES);\r
251 }\r
252 StrCpyS(DestPath, StrSize(Cwd) / sizeof(CHAR16), Cwd);\r
253 while (PathRemoveLastItem(DestPath)) ;\r
254\r
255 //\r
256 // Append DestParameter beyond '\' which may be present\r
257 //\r
258 CurrentSize = StrSize(DestPath);\r
259 StrnCatGrow(&DestPath, &CurrentSize, &DestParameter[1], 0);\r
260\r
261 *DestPathPointer = DestPath;\r
262 return (SHELL_SUCCESS);\r
263 }\r
264 //\r
265 // get the destination path\r
266 //\r
267 ShellOpenFileMetaArg((CHAR16*)DestParameter, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);\r
268 if (DestList == NULL || IsListEmpty(&DestList->Link)) {\r
269 //\r
270 // Not existing... must be renaming\r
271 //\r
272 if (StrStr(DestParameter, L":") == NULL) {\r
273 if (Cwd == NULL) {\r
274 ShellCloseFileMetaArg(&DestList);\r
275 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);\r
276 return (SHELL_INVALID_PARAMETER);\r
277 }\r
278 NewSize = StrSize(Cwd);\r
279 NewSize += StrSize(DestParameter);\r
280 DestPath = AllocateZeroPool(NewSize);\r
281 if (DestPath == NULL) {\r
282 ShellCloseFileMetaArg(&DestList);\r
283 return (SHELL_OUT_OF_RESOURCES);\r
284 }\r
285 StrCpyS(DestPath, NewSize / sizeof(CHAR16), Cwd);\r
286 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestParameter[0] != L'\\') {\r
287 StrCatS(DestPath, NewSize / sizeof(CHAR16), L"\\");\r
288 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestParameter[0] == L'\\') {\r
289 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
290 }\r
291 StrCatS(DestPath, NewSize / sizeof(CHAR16), DestParameter);\r
292 } else {\r
293 ASSERT(DestPath == NULL);\r
294 DestPath = StrnCatGrow(&DestPath, NULL, DestParameter, 0);\r
295 if (DestPath == NULL) {\r
296 ShellCloseFileMetaArg(&DestList);\r
297 return (SHELL_OUT_OF_RESOURCES);\r
298 }\r
299 }\r
300 } else {\r
301 Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link);\r
302 *DestAttr = Node->Info->Attribute;\r
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
308 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);\r
309 return (SHELL_INVALID_PARAMETER);\r
310 }\r
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
316 DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16));\r
317 if (DestPath == NULL) {\r
318 ShellCloseFileMetaArg(&DestList);\r
319 return (SHELL_OUT_OF_RESOURCES);\r
320 }\r
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
323 } else {\r
324 //\r
325 // cant move multiple files onto a single file.\r
326 //\r
327 ShellCloseFileMetaArg(&DestList);\r
328 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);\r
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
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
348EFI_STATUS\r
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
355 SHELL_STATUS ShellStatus;\r
356\r
357 //\r
358 // First we copy the file\r
359 //\r
360 ShellStatus = CopySingleFile (Node->FullName, DestPath, Resp, TRUE, L"mv");\r
361\r
362 //\r
363 // Check our result\r
364 //\r
365 if (ShellStatus == SHELL_SUCCESS) {\r
366 //\r
367 // The copy was successful. delete the source file.\r
368 //\r
369 CascadeDelete(Node, TRUE);\r
370 Node->Handle = NULL;\r
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
379 }\r
380\r
381 return (EFI_SUCCESS);\r
382}\r
383\r
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
395EFI_STATUS\r
396CreateFullDestPath(\r
397 IN CONST CHAR16 **DestPath,\r
398 OUT CHAR16 **FullDestPath,\r
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
414 StrCpyS(*FullDestPath, Size / sizeof(CHAR16), *DestPath);\r
415 if ((*FullDestPath)[StrLen(*FullDestPath)-1] != L'\\' && FileName[0] != L'\\') {\r
416 StrCatS(*FullDestPath, Size / sizeof(CHAR16), L"\\");\r
417 }\r
418 StrCatS(*FullDestPath, Size / sizeof(CHAR16), FileName);\r
419\r
420 return (EFI_SUCCESS);\r
421}\r
422\r
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
433EFI_STATUS\r
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
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
467 } else {\r
468 StrCpyS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), DestPath);\r
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
481 StrCatS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), Node->FileName);\r
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
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
504 @param[out] Resp pointer to response from question. Pass back on looped calling\r
505 @param[in] DestParameter the originally specified destination location\r
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
514ValidateAndMoveFiles(\r
515 IN EFI_SHELL_FILE_INFO *FileList,\r
516 OUT VOID **Resp,\r
517 IN CONST CHAR16 *DestParameter\r
518 )\r
519{\r
520 EFI_STATUS Status;\r
521 CHAR16 *HiiOutput;\r
522 CHAR16 *HiiResultOk;\r
523 CHAR16 *DestPath;\r
524 CHAR16 *FullDestPath;\r
525 CONST CHAR16 *Cwd;\r
526 CHAR16 *FullCwd;\r
527 SHELL_STATUS ShellStatus;\r
528 EFI_SHELL_FILE_INFO *Node;\r
529 VOID *Response;\r
530 UINT64 Attr;\r
531 CHAR16 *CleanFilePathStr;\r
532\r
533 ASSERT(FileList != NULL);\r
534 ASSERT(DestParameter != NULL);\r
535\r
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
542 FullCwd = NULL;\r
543\r
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
552 }\r
553\r
554 Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr);\r
555 if (EFI_ERROR (Status)) {\r
556 SHELL_FREE_NON_NULL(FullCwd);\r
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
562 }\r
563\r
564 ASSERT (CleanFilePathStr != NULL);\r
565\r
566 //\r
567 // Get and validate the destination location\r
568 //\r
569 ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, FullCwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr);\r
570 FreePool (CleanFilePathStr);\r
571\r
572 if (ShellStatus != SHELL_SUCCESS) {\r
573 SHELL_FREE_NON_NULL (FullCwd);\r
574 return (ShellStatus);\r
575 }\r
576 DestPath = PathCleanUpDirectories(DestPath);\r
577 if (DestPath == NULL) {\r
578 FreePool (FullCwd);\r
579 return (SHELL_OUT_OF_RESOURCES);\r
580 }\r
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
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
588 SHELL_FREE_NON_NULL(FullCwd);\r
589 return (SHELL_OUT_OF_RESOURCES);\r
590 }\r
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
602\r
603 //\r
604 // These should never be NULL\r
605 //\r
606 ASSERT(Node->FileName != NULL);\r
607 ASSERT(Node->FullName != NULL);\r
608 ASSERT(Node->Info != NULL);\r
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
617 SHELL_FREE_NON_NULL(FullDestPath);\r
618 FullDestPath = NULL;\r
619 if (ShellIsDirectory(DestPath)==EFI_SUCCESS) {\r
620 CreateFullDestPath((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName);\r
621 }\r
622\r
623 //\r
624 // Validate that the move is valid\r
625 //\r
626 if (!IsValidMove(Node->FullName, FullCwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) {\r
627 ShellStatus = SHELL_INVALID_PARAMETER;\r
628 continue;\r
629 }\r
630\r
631 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, FullDestPath!=NULL? FullDestPath:DestPath);\r
632\r
633 //\r
634 // See if destination exists\r
635 //\r
636 if (!EFI_ERROR(ShellFileExists(FullDestPath!=NULL? FullDestPath:DestPath))) {\r
637 if (Response == NULL) {\r
638 ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);\r
639 }\r
640 if (Response == NULL) {\r
641 return SHELL_ABORTED;\r
642 }\r
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
650 //\r
651 // indicate to stop everything\r
652 //\r
653 SHELL_FREE_NON_NULL(FullCwd);\r
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
664 SHELL_FREE_NON_NULL(FullCwd);\r
665 return SHELL_ABORTED;\r
666 }\r
667 Status = ShellDeleteFileByName(FullDestPath!=NULL? FullDestPath:DestPath);\r
668 }\r
669\r
670 if (IsBetweenFileSystem(Node->FullName, FullCwd, DestPath)) {\r
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
674 Status = MoveBetweenFileSystems(Node, FullDestPath!=NULL? FullDestPath:DestPath, &Response);\r
675 } else {\r
676 Status = MoveWithinFileSystems(Node, DestPath, &Response);\r
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
683 }\r
684\r
685 //\r
686 // Check our result\r
687 //\r
688 if (EFI_ERROR(Status)) {\r
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
700 }\r
701 } else {\r
702 ShellPrintEx(-1, -1, L"%s", HiiResultOk);\r
703 }\r
704\r
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
711 SHELL_FREE_NON_NULL(FullCwd);\r
712 return (ShellStatus);\r
713}\r
714\r
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
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
731 CHAR16 *Cwd;\r
732 UINTN CwdSize;\r
733 SHELL_STATUS ShellStatus;\r
734 UINTN ParamCount;\r
735 UINTN LoopCounter;\r
736 EFI_SHELL_FILE_INFO *FileList;\r
737 VOID *Response;\r
738\r
739 ProblemParam = NULL;\r
740 ShellStatus = SHELL_SUCCESS;\r
741 ParamCount = 0;\r
742 FileList = NULL;\r
743 Response = NULL;\r
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
757 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"mv", ProblemParam);\r
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
777 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mv");\r
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
785 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"mv");\r
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
790 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1));\r
791 ShellStatus = SHELL_NOT_FOUND;\r
792 } else {\r
793 //\r
794 // ValidateAndMoveFiles will report errors to the screen itself\r
795 //\r
796 CwdSize = StrSize(ShellGetCurrentDir(NULL)) + sizeof(CHAR16);\r
797 Cwd = AllocateZeroPool(CwdSize);\r
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
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
813 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount ; LoopCounter++) {\r
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
819 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, LoopCounter));\r
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
827 ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));\r
828 } else {\r
829 ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));\r
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
836 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);\r
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
853 SHELL_FREE_NON_NULL(Response);\r
854\r
855 if (ShellGetExecutionBreakFlag()) {\r
856 return (SHELL_ABORTED);\r
857 }\r
858\r
859 return (ShellStatus);\r
860}\r