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