]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
udk2010.up2.shell initial release.
[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
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "UefiShellLevel2CommandsLib.h"\r
16\r
17/**\r
18 Function to validate that moving a specific file (FileName) to a specific\r
19 location (DestPath) is valid.\r
20\r
21 This function will verify that the destination is not a subdirectory of\r
22 FullName, that the Current working Directory is not being moved, and that\r
23 the directory is not read only.\r
24\r
25 if the move is invalid this function will report the error to StdOut.\r
26\r
27 @param FullName [in] The name of the file to move.\r
28 @param Cwd [in] The current working directory\r
29 @param DestPath [in] The target location to move to\r
30 @param Attribute[in] The Attribute of the file\r
31\r
32 @retval TRUE The move is valid\r
33 @retval FALSE The move is not\r
34**/\r
35BOOLEAN\r
36EFIAPI\r
37IsValidMove(\r
38 IN CONST CHAR16 *FullName,\r
39 IN CONST CHAR16 *Cwd,\r
40 IN CONST CHAR16 *DestPath,\r
41 IN CONST UINT64 Attribute\r
42 )\r
43{\r
44 CHAR16 *Test;\r
45 CHAR16 *Test1;\r
46 CHAR16 *TestWalker;\r
47 UINTN Result;\r
48 UINTN TempLen;\r
49 if (Cwd != NULL && StrCmp(FullName, Cwd) == 0) {\r
50 //\r
51 // Invalid move\r
52 //\r
53 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle);\r
54 return (FALSE);\r
55 }\r
56 Test = NULL;\r
57 Test = StrnCatGrow(&Test, NULL, DestPath, 0);\r
58 TestWalker = Test;\r
59 ASSERT(TestWalker != NULL);\r
60 while(*TestWalker == L'\\') {\r
61 TestWalker++;\r
62 }\r
63 while(TestWalker != NULL && TestWalker[StrLen(TestWalker)-1] == L'\\') {\r
64 TestWalker[StrLen(TestWalker)-1] = CHAR_NULL;\r
65 }\r
66 ASSERT(TestWalker != NULL);\r
67 ASSERT(FullName != NULL);\r
68 if (StrStr(FullName, TestWalker) != 0) {\r
69 TempLen = StrLen(FullName);\r
70 if (StrStr(FullName, TestWalker) != FullName // not the first items... (could below it)\r
71 && TempLen <= (StrLen(TestWalker) + 1)\r
72 && StrStr(FullName+StrLen(TestWalker) + 1, L"\\") == NULL) {\r
73 //\r
74 // Invalid move\r
75 //\r
76 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);\r
77 FreePool(Test);\r
78 return (FALSE);\r
79 }\r
80 }\r
81 FreePool(Test);\r
82 if (StrStr(DestPath, FullName) != 0 && StrStr(DestPath, FullName) != DestPath) {\r
83 //\r
84 // Invalid move\r
85 //\r
86 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);\r
87 return (FALSE);\r
88 }\r
89 if ((Attribute & EFI_FILE_READ_ONLY) != 0) {\r
90 //\r
91 // invalid to move read only\r
92 //\r
93 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle);\r
94 return (FALSE);\r
95 }\r
96 Test = StrStr(FullName, L":");\r
97 Test1 = StrStr(DestPath, L":");\r
98 if (Test1 != NULL && Test != NULL) {\r
99 *Test = CHAR_NULL;\r
100 *Test1 = CHAR_NULL;\r
101 Result = StringNoCaseCompare(&FullName, &DestPath);\r
102 *Test = L':';\r
103 *Test1 = L':';\r
104 if (Result != 0) {\r
105 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_FS), gShellLevel2HiiHandle);\r
106 return (FALSE);\r
107 }\r
108 }\r
109 return (TRUE);\r
110}\r
111\r
112/**\r
113 Function to take a destination path that might contain wildcards and verify\r
114 that there is only a single possible target (IE we cant have wildcards that\r
115 have 2 possible destination).\r
116\r
117 if the result is sucessful the caller must free *DestPathPointer.\r
118\r
119 @param[in] DestDir The original path to the destination\r
120 @param[in,out] DestPathPointer a pointer to the callee allocated final path.\r
121\r
122 @retval EFI_INVALID_PARAMETR the DestDir could not be resolved to a location\r
123 @retval EFI_INVALID_PARAMETR the DestDir could be resolved to more than 1 location\r
124 @retval EFI_SUCCESS the operation was sucessful\r
125**/\r
126SHELL_STATUS\r
127EFIAPI\r
128GetDestinationLocation(\r
129 IN CONST CHAR16 *DestDir,\r
130 IN OUT CHAR16 **DestPathPointer,\r
131 IN CONST CHAR16 *Cwd\r
132 )\r
133{\r
134 EFI_SHELL_FILE_INFO *DestList;\r
135 EFI_SHELL_FILE_INFO *Node;\r
136 EFI_STATUS Status;\r
137 CHAR16 *DestPath;\r
138 CHAR16 *TempLocation;\r
139 UINTN NewSize;\r
140\r
141 DestList = NULL;\r
142 DestPath = NULL;\r
143 //\r
144 // get the destination path\r
145 //\r
146 Status = ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);\r
147 if (DestList == NULL || IsListEmpty(&DestList->Link)) {\r
148 //\r
149 // Not existing... must be renaming\r
150 //\r
151 if ((TempLocation = StrStr(DestDir, L":")) == NULL) {\r
152 NewSize = StrSize(Cwd);\r
153 NewSize += StrSize(DestDir);\r
154 DestPath = AllocateZeroPool(NewSize);\r
155 StrCpy(DestPath, Cwd);\r
156 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {\r
157 StrCat(DestPath, L"\\");\r
158 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {\r
159 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;\r
160 }\r
161 StrCat(DestPath, DestDir);\r
162 } else {\r
163 ASSERT(DestPath == NULL);\r
164 DestPath = StrnCatGrow(&DestPath, NULL, DestDir, 0);\r
165 }\r
166 } else {\r
167 Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link);\r
168 //\r
169 // Make sure there is only 1 node in the list.\r
170 //\r
171 if (!IsNodeAtEnd(&DestList->Link, &Node->Link)) {\r
172 ShellCloseFileMetaArg(&DestList);\r
173 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir);\r
174 return (SHELL_INVALID_PARAMETER);\r
175 }\r
176 if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS) {\r
177 DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16));\r
178 StrCpy(DestPath, Node->FullName);\r
179 StrCat(DestPath, L"\\");\r
180 } else {\r
181 //\r
182 // cant move onto another file.\r
183 //\r
184 ShellCloseFileMetaArg(&DestList);\r
185 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, DestDir);\r
186 return (SHELL_INVALID_PARAMETER);\r
187 }\r
188 }\r
189\r
190 *DestPathPointer = DestPath;\r
191 ShellCloseFileMetaArg(&DestList);\r
192\r
193 return (SHELL_SUCCESS);\r
194}\r
195\r
196/**\r
197 function to take a list of files to move and a destination location and do\r
198 the verification and moving of those files to that location. This function\r
199 will report any errors to the user and continue to move the rest of the files.\r
200\r
201 @param[in] FileList A LIST_ENTRY* based list of files to move\r
202 @param[in] DestDir the destination location\r
203\r
204 @retval SHELL_SUCCESS the files were all moved.\r
205 @retval SHELL_INVALID_PARAMETER a parameter was invalid\r
206 @retval SHELL_SECURITY_VIOLATION a security violation ocurred\r
207 @retval SHELL_WRITE_PROTECTED the destination was write protected\r
208 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed\r
209**/\r
210SHELL_STATUS\r
211EFIAPI\r
212ValidateAndMoveFiles(\r
213 IN CONST EFI_SHELL_FILE_INFO *FileList,\r
214 IN CONST CHAR16 *DestDir\r
215 )\r
216{\r
217 EFI_STATUS Status;\r
218 CHAR16 *HiiOutput;\r
219 CHAR16 *HiiResultOk;\r
220 CHAR16 *DestPath;\r
221 CONST CHAR16 *Cwd;\r
222 SHELL_STATUS ShellStatus;\r
223 CONST EFI_SHELL_FILE_INFO *Node;\r
224 EFI_FILE_INFO *NewFileInfo;\r
225 CHAR16 *TempLocation;\r
226 UINTN NewSize;\r
227\r
228 ASSERT(FileList != NULL);\r
229 ASSERT(DestDir != NULL);\r
230\r
231 DestPath = NULL;\r
232 Cwd = ShellGetCurrentDir(NULL);\r
233\r
234 //\r
235 // Get and validate the destination location\r
236 //\r
237 ShellStatus = GetDestinationLocation(DestDir, &DestPath, Cwd);\r
238 if (ShellStatus != SHELL_SUCCESS) {\r
239 return (ShellStatus);\r
240 }\r
241\r
242 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);\r
243 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);\r
244 ASSERT (DestPath != NULL);\r
245 ASSERT (HiiResultOk != NULL);\r
246 ASSERT (HiiOutput != NULL);\r
247// ASSERT (Cwd != NULL);\r
248\r
249 //\r
250 // Go through the list of files and directories to move...\r
251 //\r
252 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)\r
253 ; !IsNull(&FileList->Link, &Node->Link)\r
254 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)\r
255 ){\r
256 if (ShellGetExecutionBreakFlag()) {\r
257 break;\r
258 }\r
259 ASSERT(Node->FileName != NULL);\r
260 ASSERT(Node->FullName != NULL);\r
261\r
262 //\r
263 // skip the directory traversing stuff...\r
264 //\r
265 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {\r
266 continue;\r
267 }\r
268\r
269 //\r
270 // Validate that the move is valid\r
271 //\r
272 if (!IsValidMove(Node->FullName, Cwd, DestPath, Node->Info->Attribute)) {\r
273 ShellStatus = SHELL_INVALID_PARAMETER;\r
274 continue;\r
275 }\r
276\r
277 //\r
278 // Chop off map info from "DestPath"\r
279 //\r
280 if ((TempLocation = StrStr(DestPath, L":")) != NULL) {\r
281 CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1));\r
282 }\r
283\r
284 //\r
285 // construct the new file info block\r
286 //\r
287 NewSize = StrSize(DestPath);\r
288 NewSize += StrSize(Node->FileName) + sizeof(EFI_FILE_INFO) + sizeof(CHAR16);\r
289 NewFileInfo = AllocateZeroPool(NewSize);\r
290 ASSERT(NewFileInfo != NULL);\r
291 CopyMem(NewFileInfo, Node->Info, sizeof(EFI_FILE_INFO));\r
292 if (DestPath[0] != L'\\') {\r
293 StrCpy(NewFileInfo->FileName, L"\\");\r
294 StrCat(NewFileInfo->FileName, DestPath);\r
295 } else {\r
296 StrCpy(NewFileInfo->FileName, DestPath);\r
297 }\r
298 if (NewFileInfo->FileName[StrLen(NewFileInfo->FileName)-1] == L'\\') {\r
299 if (Node->FileName[0] == L'\\') {\r
300 //\r
301 // Don't allow for double slashes. Eliminate one of them.\r
302 //\r
303 NewFileInfo->FileName[StrLen(NewFileInfo->FileName)-1] = CHAR_NULL;\r
304 }\r
305 StrCat(NewFileInfo->FileName, Node->FileName);\r
306 }\r
307 NewFileInfo->Size = sizeof(EFI_FILE_INFO) + StrSize(NewFileInfo->FileName);\r
308\r
309 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, NewFileInfo->FileName);\r
310\r
311 //\r
312 // Perform the move operation\r
313 //\r
314 Status = ShellSetFileInfo(Node->Handle, NewFileInfo);\r
315\r
316 //\r
317 // Free the info object we used...\r
318 //\r
319 ASSERT (NewFileInfo != NULL);\r
320 FreePool(NewFileInfo);\r
321\r
322 //\r
323 // Check our result\r
324 //\r
325 if (EFI_ERROR(Status)) {\r
326 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status);\r
327 //\r
328 // move failed\r
329 //\r
330 switch(Status){\r
331 default:\r
332 ShellStatus = SHELL_INVALID_PARAMETER;\r
333 case EFI_SECURITY_VIOLATION:\r
334 ShellStatus = SHELL_SECURITY_VIOLATION;\r
335 case EFI_WRITE_PROTECTED:\r
336 ShellStatus = SHELL_WRITE_PROTECTED;\r
337 case EFI_OUT_OF_RESOURCES:\r
338 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
339 case EFI_DEVICE_ERROR:\r
340 ShellStatus = SHELL_DEVICE_ERROR;\r
341 case EFI_ACCESS_DENIED:\r
342 ShellStatus = SHELL_ACCESS_DENIED;\r
343 } // switch\r
344 } else {\r
345 ShellPrintEx(-1, -1, L"%s", HiiResultOk);\r
346 }\r
347 } // for loop\r
348\r
349 FreePool(DestPath);\r
350 FreePool(HiiOutput);\r
351 FreePool(HiiResultOk);\r
352 return (ShellStatus);\r
353}\r
354\r
355SHELL_STATUS\r
356EFIAPI\r
357ShellCommandRunMv (\r
358 IN EFI_HANDLE ImageHandle,\r
359 IN EFI_SYSTEM_TABLE *SystemTable\r
360 )\r
361{\r
362 EFI_STATUS Status;\r
363 LIST_ENTRY *Package;\r
364 CHAR16 *ProblemParam;\r
365 SHELL_STATUS ShellStatus;\r
366 UINTN ParamCount;\r
367 UINTN LoopCounter;\r
368 EFI_SHELL_FILE_INFO *FileList;\r
369\r
370 ProblemParam = NULL;\r
371 ShellStatus = SHELL_SUCCESS;\r
372 ParamCount = 0;\r
373 FileList = NULL;\r
374\r
375 //\r
376 // initialize the shell lib (we must be in non-auto-init...)\r
377 //\r
378 Status = ShellInitialize();\r
379 ASSERT_EFI_ERROR(Status);\r
380\r
381 //\r
382 // parse the command line\r
383 //\r
384 Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);\r
385 if (EFI_ERROR(Status)) {\r
386 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
387 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);\r
388 FreePool(ProblemParam);\r
389 ShellStatus = SHELL_INVALID_PARAMETER;\r
390 } else {\r
391 ASSERT(FALSE);\r
392 }\r
393 } else {\r
394 //\r
395 // check for "-?"\r
396 //\r
397 if (ShellCommandLineGetFlag(Package, L"-?")) {\r
398 ASSERT(FALSE);\r
399 }\r
400\r
401 switch (ParamCount = ShellCommandLineGetCount(Package)) {\r
402 case 0:\r
403 case 1:\r
404 //\r
405 // we have insufficient parameters\r
406 //\r
407 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle);\r
408 ShellStatus = SHELL_INVALID_PARAMETER;\r
409 break;\r
410 case 2:\r
411 //\r
412 // must have valid CWD for single parameter...\r
413 //\r
414 if (ShellGetCurrentDir(NULL) == NULL){\r
415 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);\r
416 ShellStatus = SHELL_INVALID_PARAMETER;\r
417 } else {\r
418 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
419 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
420 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));\r
421 ShellStatus = SHELL_NOT_FOUND;\r
422 } else {\r
423 //\r
424 // ValidateAndMoveFiles will report errors to the screen itself\r
425 //\r
426 ShellStatus = ValidateAndMoveFiles(FileList, ShellGetCurrentDir(NULL));\r
427 }\r
428 }\r
429\r
430 break;\r
431 default:\r
432 ///@todo make sure this works with error half way through and continues...\r
433 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {\r
434 if (ShellGetExecutionBreakFlag()) {\r
435 break;\r
436 }\r
437 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
438 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {\r
439 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));\r
440 ShellStatus = SHELL_NOT_FOUND;\r
441 } else {\r
442 //\r
443 // ValidateAndMoveFiles will report errors to the screen itself\r
444 // Only change ShellStatus if it's sucessful\r
445 //\r
446 if (ShellStatus == SHELL_SUCCESS) {\r
447 ShellStatus = ValidateAndMoveFiles(FileList, ShellCommandLineGetRawValue(Package, ParamCount));\r
448 } else {\r
449 ValidateAndMoveFiles(FileList, ShellCommandLineGetRawValue(Package, ParamCount));\r
450 }\r
451 }\r
452 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {\r
453 Status = ShellCloseFileMetaArg(&FileList);\r
454 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {\r
455 ShellStatus = SHELL_ACCESS_DENIED;\r
456 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);\r
457 }\r
458 }\r
459 }\r
460 break;\r
461 } // switch on parameter count\r
462\r
463 if (FileList != NULL) {\r
464 ShellCloseFileMetaArg(&FileList);\r
465 }\r
466\r
467 //\r
468 // free the command line package\r
469 //\r
470 ShellCommandLineFreeVarList (Package);\r
471 }\r
472\r
473 if (ShellGetExecutionBreakFlag()) {\r
474 return (SHELL_ABORTED);\r
475 }\r
476\r
477 return (ShellStatus);\r
478}\r