]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
ShellPkg: Fixed build errors related to variable declarations
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Mv.c
1 /** @file
2 Main file for mv shell level 2 function.
3
4 Copyright (c) 2009 - 2013, 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 UINTN NewSize;
140
141 DestList = NULL;
142 DestPath = NULL;
143
144 if (StrStr(DestDir, L"\\") == DestDir) {
145 if (Cwd == NULL) {
146 return SHELL_INVALID_PARAMETER;
147 }
148 DestPath = AllocateZeroPool(StrSize(Cwd));
149 if (DestPath == NULL) {
150 return (SHELL_OUT_OF_RESOURCES);
151 }
152 StrCpy(DestPath, Cwd);
153 while (PathRemoveLastItem(DestPath)) ;
154 *DestPathPointer = DestPath;
155 return (SHELL_SUCCESS);
156 }
157 //
158 // get the destination path
159 //
160 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);
161 if (DestList == NULL || IsListEmpty(&DestList->Link)) {
162 //
163 // Not existing... must be renaming
164 //
165 if (StrStr(DestDir, L":") == NULL) {
166 if (Cwd == NULL) {
167 ShellCloseFileMetaArg(&DestList);
168 return (SHELL_INVALID_PARAMETER);
169 }
170 NewSize = StrSize(Cwd);
171 NewSize += StrSize(DestDir);
172 DestPath = AllocateZeroPool(NewSize);
173 if (DestPath == NULL) {
174 ShellCloseFileMetaArg(&DestList);
175 return (SHELL_OUT_OF_RESOURCES);
176 }
177 StrCpy(DestPath, Cwd);
178 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {
179 StrCat(DestPath, L"\\");
180 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {
181 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
182 }
183 StrCat(DestPath, DestDir);
184 } else {
185 ASSERT(DestPath == NULL);
186 DestPath = StrnCatGrow(&DestPath, NULL, DestDir, 0);
187 if (DestPath == NULL) {
188 ShellCloseFileMetaArg(&DestList);
189 return (SHELL_OUT_OF_RESOURCES);
190 }
191 }
192 } else {
193 Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link);
194 //
195 // Make sure there is only 1 node in the list.
196 //
197 if (!IsNodeAtEnd(&DestList->Link, &Node->Link)) {
198 ShellCloseFileMetaArg(&DestList);
199 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir);
200 return (SHELL_INVALID_PARAMETER);
201 }
202 if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS) {
203 DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16));
204 if (DestPath == NULL) {
205 ShellCloseFileMetaArg(&DestList);
206 return (SHELL_OUT_OF_RESOURCES);
207 }
208 StrCpy(DestPath, Node->FullName);
209 StrCat(DestPath, L"\\");
210 } else {
211 //
212 // cant move onto another file.
213 //
214 ShellCloseFileMetaArg(&DestList);
215 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, DestDir);
216 return (SHELL_INVALID_PARAMETER);
217 }
218 }
219
220 *DestPathPointer = DestPath;
221 ShellCloseFileMetaArg(&DestList);
222
223 return (SHELL_SUCCESS);
224 }
225
226 /**
227 function to take a list of files to move and a destination location and do
228 the verification and moving of those files to that location. This function
229 will report any errors to the user and continue to move the rest of the files.
230
231 @param[in] FileList A LIST_ENTRY* based list of files to move
232 @param[out] Resp pointer to response from question. Pass back on looped calling
233 @param[in] DestDir the destination location
234
235 @retval SHELL_SUCCESS the files were all moved.
236 @retval SHELL_INVALID_PARAMETER a parameter was invalid
237 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
238 @retval SHELL_WRITE_PROTECTED the destination was write protected
239 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
240 **/
241 SHELL_STATUS
242 EFIAPI
243 ValidateAndMoveFiles(
244 IN CONST EFI_SHELL_FILE_INFO *FileList,
245 OUT VOID **Resp,
246 IN CONST CHAR16 *DestDir
247 )
248 {
249 EFI_STATUS Status;
250 CHAR16 *HiiOutput;
251 CHAR16 *HiiResultOk;
252 CHAR16 *DestPath;
253 CONST CHAR16 *Cwd;
254 SHELL_STATUS ShellStatus;
255 CONST EFI_SHELL_FILE_INFO *Node;
256 EFI_FILE_INFO *NewFileInfo;
257 CHAR16 *TempLocation;
258 UINTN NewSize;
259 UINTN Length;
260 VOID *Response;
261 SHELL_FILE_HANDLE DestHandle;
262
263 ASSERT(FileList != NULL);
264 ASSERT(DestDir != NULL);
265
266 DestPath = NULL;
267 Cwd = ShellGetCurrentDir(NULL);
268 Response = *Resp;
269
270 //
271 // Get and validate the destination location
272 //
273 ShellStatus = GetDestinationLocation(DestDir, &DestPath, Cwd);
274 if (ShellStatus != SHELL_SUCCESS) {
275 return (ShellStatus);
276 }
277 DestPath = PathCleanUpDirectories(DestPath);
278
279 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);
280 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
281 ASSERT (DestPath != NULL);
282 ASSERT (HiiResultOk != NULL);
283 ASSERT (HiiOutput != NULL);
284 // ASSERT (Cwd != NULL);
285
286 //
287 // Go through the list of files and directories to move...
288 //
289 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
290 ; !IsNull(&FileList->Link, &Node->Link)
291 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
292 ){
293 if (ShellGetExecutionBreakFlag()) {
294 break;
295 }
296 ASSERT(Node->FileName != NULL);
297 ASSERT(Node->FullName != NULL);
298
299 //
300 // skip the directory traversing stuff...
301 //
302 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
303 continue;
304 }
305
306 //
307 // Validate that the move is valid
308 //
309 if (!IsValidMove(Node->FullName, Cwd, DestPath, Node->Info->Attribute)) {
310 ShellStatus = SHELL_INVALID_PARAMETER;
311 continue;
312 }
313
314 //
315 // Chop off map info from "DestPath"
316 //
317 if ((TempLocation = StrStr(DestPath, L":")) != NULL) {
318 CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1));
319 }
320
321 //
322 // construct the new file info block
323 //
324 NewSize = StrSize(DestPath);
325 NewSize += StrSize(Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);
326 NewFileInfo = AllocateZeroPool(NewSize);
327 if (NewFileInfo == NULL) {
328 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);
329 ShellStatus = SHELL_OUT_OF_RESOURCES;
330 } else {
331 CopyMem(NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO);
332 if (DestPath[0] != L'\\') {
333 StrCpy(NewFileInfo->FileName, L"\\");
334 StrCat(NewFileInfo->FileName, DestPath);
335 } else {
336 StrCpy(NewFileInfo->FileName, DestPath);
337 }
338 Length = StrLen(NewFileInfo->FileName);
339 if (Length > 0) {
340 Length--;
341 }
342 if (NewFileInfo->FileName[Length] == L'\\') {
343 if (Node->FileName[0] == L'\\') {
344 //
345 // Don't allow for double slashes. Eliminate one of them.
346 //
347 NewFileInfo->FileName[Length] = CHAR_NULL;
348 }
349 StrCat(NewFileInfo->FileName, Node->FileName);
350 }
351 NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize(NewFileInfo->FileName);
352 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, NewFileInfo->FileName);
353
354 if (!EFI_ERROR(ShellFileExists(NewFileInfo->FileName))) {
355 if (Response == NULL) {
356 ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
357 }
358 switch (*(SHELL_PROMPT_RESPONSE*)Response) {
359 case ShellPromptResponseNo:
360 FreePool(NewFileInfo);
361 continue;
362 case ShellPromptResponseCancel:
363 *Resp = Response;
364 //
365 // indicate to stop everything
366 //
367 FreePool(NewFileInfo);
368 FreePool(DestPath);
369 FreePool(HiiOutput);
370 FreePool(HiiResultOk);
371 return (SHELL_ABORTED);
372 case ShellPromptResponseAll:
373 *Resp = Response;
374 break;
375 case ShellPromptResponseYes:
376 FreePool(Response);
377 break;
378 default:
379 FreePool(Response);
380 FreePool(NewFileInfo);
381 FreePool(DestPath);
382 FreePool(HiiOutput);
383 FreePool(HiiResultOk);
384 return SHELL_ABORTED;
385 }
386 Status = ShellOpenFileByName(NewFileInfo->FileName, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0);
387 ShellDeleteFile(&DestHandle);
388 }
389
390
391 //
392 // Perform the move operation
393 //
394 Status = ShellSetFileInfo(Node->Handle, NewFileInfo);
395
396 //
397 // Free the info object we used...
398 //
399 FreePool(NewFileInfo);
400
401 //
402 // Check our result
403 //
404 if (EFI_ERROR(Status)) {
405 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status);
406 ShellStatus = SHELL_INVALID_PARAMETER;
407 if (Status == EFI_SECURITY_VIOLATION) {
408 ShellStatus = SHELL_SECURITY_VIOLATION;
409 } else if (Status == EFI_WRITE_PROTECTED) {
410 ShellStatus = SHELL_WRITE_PROTECTED;
411 } else if (Status == EFI_OUT_OF_RESOURCES) {
412 ShellStatus = SHELL_OUT_OF_RESOURCES;
413 } else if (Status == EFI_DEVICE_ERROR) {
414 ShellStatus = SHELL_DEVICE_ERROR;
415 } else if (Status == EFI_ACCESS_DENIED) {
416 ShellStatus = SHELL_ACCESS_DENIED;
417 }
418 } else {
419 ShellPrintEx(-1, -1, L"%s", HiiResultOk);
420 }
421 }
422 } // for loop
423
424 FreePool(DestPath);
425 FreePool(HiiOutput);
426 FreePool(HiiResultOk);
427 return (ShellStatus);
428 }
429
430 /**
431 Function for 'mv' command.
432
433 @param[in] ImageHandle Handle to the Image (NULL if Internal).
434 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
435 **/
436 SHELL_STATUS
437 EFIAPI
438 ShellCommandRunMv (
439 IN EFI_HANDLE ImageHandle,
440 IN EFI_SYSTEM_TABLE *SystemTable
441 )
442 {
443 EFI_STATUS Status;
444 LIST_ENTRY *Package;
445 CHAR16 *ProblemParam;
446 SHELL_STATUS ShellStatus;
447 UINTN ParamCount;
448 UINTN LoopCounter;
449 EFI_SHELL_FILE_INFO *FileList;
450 VOID *Response;
451
452 ProblemParam = NULL;
453 ShellStatus = SHELL_SUCCESS;
454 ParamCount = 0;
455 FileList = NULL;
456 Response = NULL;
457
458 //
459 // initialize the shell lib (we must be in non-auto-init...)
460 //
461 Status = ShellInitialize();
462 ASSERT_EFI_ERROR(Status);
463
464 //
465 // parse the command line
466 //
467 Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);
468 if (EFI_ERROR(Status)) {
469 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
470 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);
471 FreePool(ProblemParam);
472 ShellStatus = SHELL_INVALID_PARAMETER;
473 } else {
474 ASSERT(FALSE);
475 }
476 } else {
477 //
478 // check for "-?"
479 //
480 if (ShellCommandLineGetFlag(Package, L"-?")) {
481 ASSERT(FALSE);
482 }
483
484 switch (ParamCount = ShellCommandLineGetCount(Package)) {
485 case 0:
486 case 1:
487 //
488 // we have insufficient parameters
489 //
490 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle);
491 ShellStatus = SHELL_INVALID_PARAMETER;
492 break;
493 case 2:
494 //
495 // must have valid CWD for single parameter...
496 //
497 if (ShellGetCurrentDir(NULL) == NULL){
498 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
499 ShellStatus = SHELL_INVALID_PARAMETER;
500 } else {
501 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
502 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
503 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));
504 ShellStatus = SHELL_NOT_FOUND;
505 } else {
506 //
507 // ValidateAndMoveFiles will report errors to the screen itself
508 //
509 ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellGetCurrentDir(NULL));
510 }
511 }
512
513 break;
514 default:
515 ///@todo make sure this works with error half way through and continues...
516 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount ; LoopCounter++) {
517 if (ShellGetExecutionBreakFlag()) {
518 break;
519 }
520 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
521 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
522 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, LoopCounter));
523 ShellStatus = SHELL_NOT_FOUND;
524 } else {
525 //
526 // ValidateAndMoveFiles will report errors to the screen itself
527 // Only change ShellStatus if it's sucessful
528 //
529 if (ShellStatus == SHELL_SUCCESS) {
530 ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));
531 } else {
532 ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));
533 }
534 }
535 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
536 Status = ShellCloseFileMetaArg(&FileList);
537 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
538 ShellStatus = SHELL_ACCESS_DENIED;
539 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);
540 }
541 }
542 }
543 break;
544 } // switch on parameter count
545
546 if (FileList != NULL) {
547 ShellCloseFileMetaArg(&FileList);
548 }
549
550 //
551 // free the command line package
552 //
553 ShellCommandLineFreeVarList (Package);
554 }
555
556 SHELL_FREE_NON_NULL(Response);
557
558 if (ShellGetExecutionBreakFlag()) {
559 return (SHELL_ABORTED);
560 }
561
562 return (ShellStatus);
563 }