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