]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
a87e4b1bf1c3f16ce1eb5c69d5941374493353b0
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Mv.c
1 /** @file
2 Main file for mv shell level 2 function.
3
4 (C) Copyright 2013-2014, Hewlett-Packard Development Company, L.P.
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 ( StrCmp(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, 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, 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 EFI_STATUS Status;
295
296 //
297 // First we copy the file
298 //
299 Status = CopySingleFile(Node->FullName, DestPath, Resp, TRUE);
300
301 //
302 // Check our result
303 //
304 if (!EFI_ERROR(Status)) {
305 //
306 // The copy was successful. delete the source file.
307 //
308 CascadeDelete(Node, TRUE);
309 Node->Handle = NULL;
310 }
311
312 return (Status);
313 }
314
315 /**
316 Function to take the destination path and target file name to generate the full destination path.
317
318 @param[in] DestPath A pointer to the destination file path string.
319 @param[out] FullDestPath A pointer to the full destination path string.
320 @param[in] FileName Name string of the targe file.
321
322 @retval SHELL_SUCCESS the files were all moved.
323 @retval SHELL_INVALID_PARAMETER a parameter was invalid
324 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
325 **/
326 EFI_STATUS
327 EFIAPI
328 CreateFullDestPath(
329 IN CONST CHAR16 **DestPath,
330 OUT CHAR16 **FullDestPath,
331 IN CONST CHAR16 *FileName
332 )
333 {
334 UINTN Size;
335 if (FullDestPath == NULL || FileName == NULL || DestPath == NULL || *DestPath == NULL){
336 return (EFI_INVALID_PARAMETER);
337 }
338
339 Size = StrSize(*DestPath) + StrSize(FileName);
340
341 *FullDestPath = AllocateZeroPool(Size);
342 if (*FullDestPath == NULL){
343 return (EFI_OUT_OF_RESOURCES);
344 }
345
346 StrnCpy(*FullDestPath, *DestPath, Size / sizeof(CHAR16) - 1);
347 if ((*FullDestPath)[StrLen(*FullDestPath)-1] != L'\\' && FileName[0] != L'\\') {
348 StrnCat(*FullDestPath, L"\\",Size / sizeof(CHAR16) - 1 - StrLen(*FullDestPath));
349 }
350 StrnCat(*FullDestPath, FileName, Size / sizeof(CHAR16) - 1 - StrLen(*FullDestPath));
351
352 return (EFI_SUCCESS);
353 }
354
355 /**
356 Function to do a move within a file system.
357
358 @param[in] Node A pointer to the file to be removed.
359 @param[in] DestPath A pointer to the destination file path.
360 @param[out] Resp A pointer to response from question. Pass back on looped calling.
361
362 @retval SHELL_SUCCESS The source file was moved to the destination.
363 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
364 **/
365 EFI_STATUS
366 EFIAPI
367 MoveWithinFileSystems(
368 IN EFI_SHELL_FILE_INFO *Node,
369 IN CHAR16 *DestPath,
370 OUT VOID **Resp
371 )
372 {
373 EFI_FILE_INFO *NewFileInfo;
374 CHAR16 *TempLocation;
375 UINTN NewSize;
376 UINTN Length;
377 EFI_STATUS Status;
378
379 //
380 // Chop off map info from DestPath
381 //
382 if ((TempLocation = StrStr(DestPath, L":")) != NULL) {
383 CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1));
384 }
385
386 //
387 // construct the new file info block
388 //
389 NewSize = StrSize(DestPath);
390 NewSize += StrSize(Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);
391 NewFileInfo = AllocateZeroPool(NewSize);
392 if (NewFileInfo == NULL) {
393 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);
394 Status = EFI_OUT_OF_RESOURCES;
395 } else {
396 CopyMem(NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO);
397 if (DestPath[0] != L'\\') {
398 StrCpy(NewFileInfo->FileName, L"\\");
399 StrCat(NewFileInfo->FileName, DestPath);
400 } else {
401 StrCpy(NewFileInfo->FileName, DestPath);
402 }
403 Length = StrLen(NewFileInfo->FileName);
404 if (Length > 0) {
405 Length--;
406 }
407 if (NewFileInfo->FileName[Length] == L'\\') {
408 if (Node->FileName[0] == L'\\') {
409 //
410 // Don't allow for double slashes. Eliminate one of them.
411 //
412 NewFileInfo->FileName[Length] = CHAR_NULL;
413 }
414 StrCat(NewFileInfo->FileName, Node->FileName);
415 }
416 NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize(NewFileInfo->FileName);
417
418 //
419 // Perform the move operation
420 //
421 Status = ShellSetFileInfo(Node->Handle, NewFileInfo);
422
423 //
424 // Free the info object we used...
425 //
426 FreePool(NewFileInfo);
427 }
428
429 return (Status);
430 }
431 /**
432 function to take a list of files to move and a destination location and do
433 the verification and moving of those files to that location. This function
434 will report any errors to the user and continue to move the rest of the files.
435
436 @param[in] FileList A LIST_ENTRY* based list of files to move
437 @param[out] Resp pointer to response from question. Pass back on looped calling
438 @param[in] DestParameter the originally specified destination location
439
440 @retval SHELL_SUCCESS the files were all moved.
441 @retval SHELL_INVALID_PARAMETER a parameter was invalid
442 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
443 @retval SHELL_WRITE_PROTECTED the destination was write protected
444 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
445 **/
446 SHELL_STATUS
447 EFIAPI
448 ValidateAndMoveFiles(
449 IN EFI_SHELL_FILE_INFO *FileList,
450 OUT VOID **Resp,
451 IN CONST CHAR16 *DestParameter
452 )
453 {
454 EFI_STATUS Status;
455 CHAR16 *HiiOutput;
456 CHAR16 *HiiResultOk;
457 CHAR16 *DestPath;
458 CHAR16 *FullDestPath;
459 CONST CHAR16 *Cwd;
460 SHELL_STATUS ShellStatus;
461 EFI_SHELL_FILE_INFO *Node;
462 VOID *Response;
463 UINT64 Attr;
464 CHAR16 *CleanFilePathStr;
465
466 ASSERT(FileList != NULL);
467 ASSERT(DestParameter != NULL);
468
469 DestPath = NULL;
470 FullDestPath = NULL;
471 Cwd = ShellGetCurrentDir(NULL);
472 Response = *Resp;
473 Attr = 0;
474 CleanFilePathStr = NULL;
475
476 Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr);
477 if (EFI_ERROR (Status)) {
478 if (Status == EFI_OUT_OF_RESOURCES) {
479 return SHELL_OUT_OF_RESOURCES;
480 } else {
481 return SHELL_INVALID_PARAMETER;
482 }
483 }
484
485 ASSERT (CleanFilePathStr != NULL);
486
487 //
488 // Get and validate the destination location
489 //
490 ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, Cwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr);
491 FreePool (CleanFilePathStr);
492
493 if (ShellStatus != SHELL_SUCCESS) {
494 return (ShellStatus);
495 }
496 DestPath = PathCleanUpDirectories(DestPath);
497 if (DestPath == NULL) {
498 return (SHELL_OUT_OF_RESOURCES);
499 }
500
501 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);
502 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
503 if (HiiOutput == NULL || HiiResultOk == NULL) {
504 SHELL_FREE_NON_NULL(DestPath);
505 SHELL_FREE_NON_NULL(HiiOutput);
506 SHELL_FREE_NON_NULL(HiiResultOk);
507 return (SHELL_OUT_OF_RESOURCES);
508 }
509
510 //
511 // Go through the list of files and directories to move...
512 //
513 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
514 ; !IsNull(&FileList->Link, &Node->Link)
515 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
516 ){
517 if (ShellGetExecutionBreakFlag()) {
518 break;
519 }
520
521 //
522 // These should never be NULL
523 //
524 ASSERT(Node->FileName != NULL);
525 ASSERT(Node->FullName != NULL);
526 ASSERT(Node->Info != NULL);
527
528 //
529 // skip the directory traversing stuff...
530 //
531 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
532 continue;
533 }
534
535 SHELL_FREE_NON_NULL(FullDestPath);
536 FullDestPath = NULL;
537 if (ShellIsDirectory(DestPath)==EFI_SUCCESS) {
538 CreateFullDestPath((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName);
539 }
540
541 //
542 // Validate that the move is valid
543 //
544 if (!IsValidMove(Node->FullName, Cwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) {
545 ShellStatus = SHELL_INVALID_PARAMETER;
546 continue;
547 }
548
549 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, FullDestPath!=NULL? FullDestPath:DestPath);
550
551 //
552 // See if destination exists
553 //
554 if (!EFI_ERROR(ShellFileExists(FullDestPath!=NULL? FullDestPath:DestPath))) {
555 if (Response == NULL) {
556 ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
557 }
558 switch (*(SHELL_PROMPT_RESPONSE*)Response) {
559 case ShellPromptResponseNo:
560 FreePool(Response);
561 Response = NULL;
562 continue;
563 case ShellPromptResponseCancel:
564 *Resp = Response;
565 //
566 // indicate to stop everything
567 //
568 return (SHELL_ABORTED);
569 case ShellPromptResponseAll:
570 *Resp = Response;
571 break;
572 case ShellPromptResponseYes:
573 FreePool(Response);
574 Response = NULL;
575 break;
576 default:
577 FreePool(Response);
578 return SHELL_ABORTED;
579 }
580 Status = ShellDeleteFileByName(FullDestPath!=NULL? FullDestPath:DestPath);
581 }
582
583 if (IsBetweenFileSystem(Node->FullName, Cwd, DestPath)) {
584 while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen(DestPath) - 1] == L'\\') {
585 DestPath[StrLen(DestPath) - 1] = CHAR_NULL;
586 }
587 Status = MoveBetweenFileSystems(Node, FullDestPath!=NULL? FullDestPath:DestPath, &Response);
588 } else {
589 Status = MoveWithinFileSystems(Node, DestPath, &Response);
590 }
591
592 //
593 // Check our result
594 //
595 if (EFI_ERROR(Status)) {
596 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status);
597 ShellStatus = SHELL_INVALID_PARAMETER;
598 if (Status == EFI_SECURITY_VIOLATION) {
599 ShellStatus = SHELL_SECURITY_VIOLATION;
600 } else if (Status == EFI_WRITE_PROTECTED) {
601 ShellStatus = SHELL_WRITE_PROTECTED;
602 } else if (Status == EFI_OUT_OF_RESOURCES) {
603 ShellStatus = SHELL_OUT_OF_RESOURCES;
604 } else if (Status == EFI_DEVICE_ERROR) {
605 ShellStatus = SHELL_DEVICE_ERROR;
606 } else if (Status == EFI_ACCESS_DENIED) {
607 ShellStatus = SHELL_ACCESS_DENIED;
608 }
609 } else {
610 ShellPrintEx(-1, -1, L"%s", HiiResultOk);
611 }
612
613 } // main for loop
614
615 SHELL_FREE_NON_NULL(FullDestPath);
616 SHELL_FREE_NON_NULL(DestPath);
617 SHELL_FREE_NON_NULL(HiiOutput);
618 SHELL_FREE_NON_NULL(HiiResultOk);
619 return (ShellStatus);
620 }
621
622 /**
623 Function for 'mv' command.
624
625 @param[in] ImageHandle Handle to the Image (NULL if Internal).
626 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
627 **/
628 SHELL_STATUS
629 EFIAPI
630 ShellCommandRunMv (
631 IN EFI_HANDLE ImageHandle,
632 IN EFI_SYSTEM_TABLE *SystemTable
633 )
634 {
635 EFI_STATUS Status;
636 LIST_ENTRY *Package;
637 CHAR16 *ProblemParam;
638 SHELL_STATUS ShellStatus;
639 UINTN ParamCount;
640 UINTN LoopCounter;
641 EFI_SHELL_FILE_INFO *FileList;
642 VOID *Response;
643
644 ProblemParam = NULL;
645 ShellStatus = SHELL_SUCCESS;
646 ParamCount = 0;
647 FileList = NULL;
648 Response = NULL;
649
650 //
651 // initialize the shell lib (we must be in non-auto-init...)
652 //
653 Status = ShellInitialize();
654 ASSERT_EFI_ERROR(Status);
655
656 //
657 // parse the command line
658 //
659 Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);
660 if (EFI_ERROR(Status)) {
661 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
662 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);
663 FreePool(ProblemParam);
664 ShellStatus = SHELL_INVALID_PARAMETER;
665 } else {
666 ASSERT(FALSE);
667 }
668 } else {
669 //
670 // check for "-?"
671 //
672 if (ShellCommandLineGetFlag(Package, L"-?")) {
673 ASSERT(FALSE);
674 }
675
676 switch (ParamCount = ShellCommandLineGetCount(Package)) {
677 case 0:
678 case 1:
679 //
680 // we have insufficient parameters
681 //
682 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle);
683 ShellStatus = SHELL_INVALID_PARAMETER;
684 break;
685 case 2:
686 //
687 // must have valid CWD for single parameter...
688 //
689 if (ShellGetCurrentDir(NULL) == NULL){
690 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
691 ShellStatus = SHELL_INVALID_PARAMETER;
692 } else {
693 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
694 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
695 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));
696 ShellStatus = SHELL_NOT_FOUND;
697 } else {
698 //
699 // ValidateAndMoveFiles will report errors to the screen itself
700 //
701 ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellGetCurrentDir(NULL));
702 }
703 }
704
705 break;
706 default:
707 ///@todo make sure this works with error half way through and continues...
708 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount ; LoopCounter++) {
709 if (ShellGetExecutionBreakFlag()) {
710 break;
711 }
712 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
713 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
714 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, LoopCounter));
715 ShellStatus = SHELL_NOT_FOUND;
716 } else {
717 //
718 // ValidateAndMoveFiles will report errors to the screen itself
719 // Only change ShellStatus if it's sucessful
720 //
721 if (ShellStatus == SHELL_SUCCESS) {
722 ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));
723 } else {
724 ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));
725 }
726 }
727 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
728 Status = ShellCloseFileMetaArg(&FileList);
729 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
730 ShellStatus = SHELL_ACCESS_DENIED;
731 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);
732 }
733 }
734 }
735 break;
736 } // switch on parameter count
737
738 if (FileList != NULL) {
739 ShellCloseFileMetaArg(&FileList);
740 }
741
742 //
743 // free the command line package
744 //
745 ShellCommandLineFreeVarList (Package);
746 }
747
748 SHELL_FREE_NON_NULL(Response);
749
750 if (ShellGetExecutionBreakFlag()) {
751 return (SHELL_ABORTED);
752 }
753
754 return (ShellStatus);
755 }