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