2 Main file for mv shell level 2 function.
4 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "UefiShellLevel2CommandsLib.h"
13 function to determine if a move is between file systems.
15 @param FullName [in] The name of the file to move.
16 @param Cwd [in] The current working directory
17 @param DestPath [in] The target location to move to
19 @retval TRUE The move is across file system.
20 @retval FALSE The move is within a file system.
24 IN CONST CHAR16
*FullName
,
26 IN CONST CHAR16
*DestPath
33 Test
= StrStr (FullName
, L
":");
34 if ((Test
== NULL
) && (Cwd
!= NULL
)) {
35 Test
= StrStr (Cwd
, L
":");
38 Test1
= StrStr (DestPath
, L
":");
39 if ((Test1
== NULL
) && (Cwd
!= NULL
)) {
40 Test1
= StrStr (Cwd
, L
":");
43 if ((Test1
!= NULL
) && (Test
!= NULL
)) {
46 Result
= StringNoCaseCompare (&FullName
, &DestPath
);
58 function to determine if SrcPath is valid to mv.
60 if SrcPath equal CWD then it's invalid.
61 if SrcPath is the parent path of CWD then it's invalid.
62 is SrcPath is NULL return FALSE.
64 if CwdPath is NULL then ASSERT()
66 @param SrcPath [in] The source path.
67 @param CwdPath [in] The current working directory.
69 @retval TRUE The source path is valid.
70 @retval FALSE The source path is invalid.
74 IN CONST CHAR16
*SrcPath
,
75 IN CONST CHAR16
*CwdPath
78 CHAR16
*SrcPathBuffer
;
79 CHAR16
*CwdPathBuffer
;
82 ASSERT (CwdPath
!= NULL
);
83 if (SrcPath
== NULL
) {
89 SrcPathBuffer
= AllocateCopyPool (StrSize (SrcPath
), SrcPath
);
90 if (SrcPathBuffer
== NULL
) {
94 CwdPathBuffer
= AllocateCopyPool (StrSize (CwdPath
), CwdPath
);
95 if (CwdPathBuffer
== NULL
) {
96 FreePool (SrcPathBuffer
);
100 gUnicodeCollation
->StrUpr (gUnicodeCollation
, SrcPathBuffer
);
101 gUnicodeCollation
->StrUpr (gUnicodeCollation
, CwdPathBuffer
);
103 if (SrcPathBuffer
[StrLen (SrcPathBuffer
) -1] == L
'\\') {
104 SrcPathBuffer
[StrLen (SrcPathBuffer
) - 1] = CHAR_NULL
;
107 if (CwdPathBuffer
[StrLen (CwdPathBuffer
) - 1] == L
'\\') {
108 CwdPathBuffer
[StrLen (CwdPathBuffer
) - 1] = CHAR_NULL
;
111 if ((StrCmp (CwdPathBuffer
, SrcPathBuffer
) == 0) ||
112 ((StrStr (CwdPathBuffer
, SrcPathBuffer
) == CwdPathBuffer
) &&
113 (CwdPathBuffer
[StrLen (SrcPathBuffer
)] == L
'\\'))
119 FreePool (SrcPathBuffer
);
120 FreePool (CwdPathBuffer
);
126 Function to validate that moving a specific file (FileName) to a specific
127 location (DestPath) is valid.
129 This function will verify that the destination is not a subdirectory of
130 FullName, that the Current working Directory is not being moved, and that
131 the directory is not read only.
133 if the move is invalid this function will report the error to StdOut.
135 @param SourcePath [in] The name of the file to move.
136 @param Cwd [in] The current working directory
137 @param DestPath [in] The target location to move to
138 @param Attribute [in] The Attribute of the file
139 @param DestAttr [in] The Attribute of the destination
140 @param FileStatus [in] The Status of the file when opened
142 @retval TRUE The move is valid
143 @retval FALSE The move is not
147 IN CONST CHAR16
*SourcePath
,
148 IN CONST CHAR16
*Cwd
,
149 IN CONST CHAR16
*DestPath
,
150 IN CONST UINT64 Attribute
,
151 IN CONST UINT64 DestAttr
,
152 IN CONST EFI_STATUS FileStatus
155 CHAR16
*DestPathCopy
;
156 CHAR16
*DestPathWalker
;
158 if ((Cwd
!= NULL
) && ((Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
)) {
159 if (!IsSoucePathValid (SourcePath
, Cwd
)) {
163 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_CWD
), gShellLevel2HiiHandle
);
169 // invalid to move read only or move to a read only destination
171 if ( ((Attribute
& EFI_FILE_READ_ONLY
) != 0)
172 || (FileStatus
== EFI_WRITE_PROTECTED
)
173 || ((DestAttr
& EFI_FILE_READ_ONLY
) != 0)
176 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_RO
), gShellLevel2HiiHandle
, SourcePath
);
180 DestPathCopy
= AllocateCopyPool (StrSize (DestPath
), DestPath
);
181 if (DestPathCopy
== NULL
) {
185 for (DestPathWalker
= DestPathCopy
; *DestPathWalker
== L
'\\'; DestPathWalker
++) {
188 while (DestPathWalker
!= NULL
&& DestPathWalker
[StrLen (DestPathWalker
)-1] == L
'\\') {
189 DestPathWalker
[StrLen (DestPathWalker
)-1] = CHAR_NULL
;
192 ASSERT (DestPathWalker
!= NULL
);
193 ASSERT (SourcePath
!= NULL
);
196 // If they're the same, or if source is "above" dest on file path tree
198 if ((StringNoCaseCompare (&DestPathWalker
, &SourcePath
) == 0) ||
199 ((StrStr (DestPathWalker
, SourcePath
) == DestPathWalker
) &&
200 (DestPathWalker
[StrLen (SourcePath
)] == '\\')
204 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_SUB
), gShellLevel2HiiHandle
);
205 FreePool (DestPathCopy
);
209 FreePool (DestPathCopy
);
215 Function to take a destination path that might contain wildcards and verify
216 that there is only a single possible target (IE we cant have wildcards that
217 have 2 possible destination).
219 if the result is sucessful the caller must free *DestPathPointer.
221 @param[in] DestParameter The original path to the destination.
222 @param[in, out] DestPathPointer A pointer to the callee allocated final path.
223 @param[in] Cwd A pointer to the current working directory.
224 @param[in] SingleSource TRUE to have only one source file.
225 @param[in, out] DestAttr A pointer to the destination information attribute.
227 @retval SHELL_INVALID_PARAMETER The DestParameter could not be resolved to a location.
228 @retval SHELL_INVALID_PARAMETER The DestParameter could be resolved to more than 1 location.
229 @retval SHELL_INVALID_PARAMETER Cwd is required and is NULL.
230 @retval SHELL_SUCCESS The operation was sucessful.
233 GetDestinationLocation (
234 IN CONST CHAR16
*DestParameter
,
235 IN OUT CHAR16
**DestPathPointer
,
236 IN CONST CHAR16
*Cwd
,
237 IN CONST BOOLEAN SingleSource
,
238 IN OUT UINT64
*DestAttr
241 EFI_SHELL_FILE_INFO
*DestList
;
242 EFI_SHELL_FILE_INFO
*Node
;
250 ASSERT (DestAttr
!= NULL
);
252 if (StrStr (DestParameter
, L
"\\") == DestParameter
) {
254 return SHELL_INVALID_PARAMETER
;
257 DestPath
= AllocateZeroPool (StrSize (Cwd
));
258 if (DestPath
== NULL
) {
259 return (SHELL_OUT_OF_RESOURCES
);
262 StrCpyS (DestPath
, StrSize (Cwd
) / sizeof (CHAR16
), Cwd
);
263 while (PathRemoveLastItem (DestPath
)) {
267 // Append DestParameter beyond '\' which may be present
269 CurrentSize
= StrSize (DestPath
);
270 StrnCatGrow (&DestPath
, &CurrentSize
, &DestParameter
[1], 0);
272 *DestPathPointer
= DestPath
;
273 return (SHELL_SUCCESS
);
277 // get the destination path
279 ShellOpenFileMetaArg ((CHAR16
*)DestParameter
, EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
|EFI_FILE_MODE_CREATE
, &DestList
);
280 if ((DestList
== NULL
) || IsListEmpty (&DestList
->Link
)) {
282 // Not existing... must be renaming
284 if (StrStr (DestParameter
, L
":") == NULL
) {
286 ShellCloseFileMetaArg (&DestList
);
287 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
288 return (SHELL_INVALID_PARAMETER
);
291 NewSize
= StrSize (Cwd
);
292 NewSize
+= StrSize (DestParameter
);
293 DestPath
= AllocateZeroPool (NewSize
);
294 if (DestPath
== NULL
) {
295 ShellCloseFileMetaArg (&DestList
);
296 return (SHELL_OUT_OF_RESOURCES
);
299 StrCpyS (DestPath
, NewSize
/ sizeof (CHAR16
), Cwd
);
300 if ((DestPath
[StrLen (DestPath
)-1] != L
'\\') && (DestParameter
[0] != L
'\\')) {
301 StrCatS (DestPath
, NewSize
/ sizeof (CHAR16
), L
"\\");
302 } else if ((DestPath
[StrLen (DestPath
)-1] == L
'\\') && (DestParameter
[0] == L
'\\')) {
303 ((CHAR16
*)DestPath
)[StrLen (DestPath
)-1] = CHAR_NULL
;
306 StrCatS (DestPath
, NewSize
/ sizeof (CHAR16
), DestParameter
);
308 ASSERT (DestPath
== NULL
);
309 DestPath
= StrnCatGrow (&DestPath
, NULL
, DestParameter
, 0);
310 if (DestPath
== NULL
) {
311 ShellCloseFileMetaArg (&DestList
);
312 return (SHELL_OUT_OF_RESOURCES
);
316 Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode (&DestList
->Link
);
317 *DestAttr
= Node
->Info
->Attribute
;
319 // Make sure there is only 1 node in the list.
321 if (!IsNodeAtEnd (&DestList
->Link
, &Node
->Link
)) {
322 ShellCloseFileMetaArg (&DestList
);
323 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_MARG_ERROR
), gShellLevel2HiiHandle
, L
"mv", DestParameter
);
324 return (SHELL_INVALID_PARAMETER
);
328 // If we are a directory or a single file, then one node is fine.
330 if ((ShellIsDirectory (Node
->FullName
) == EFI_SUCCESS
) || SingleSource
) {
331 DestPath
= AllocateZeroPool (StrSize (Node
->FullName
)+sizeof (CHAR16
));
332 if (DestPath
== NULL
) {
333 ShellCloseFileMetaArg (&DestList
);
334 return (SHELL_OUT_OF_RESOURCES
);
337 StrCpyS (DestPath
, (StrSize (Node
->FullName
)+sizeof (CHAR16
)) / sizeof (CHAR16
), Node
->FullName
);
338 StrCatS (DestPath
, (StrSize (Node
->FullName
)+sizeof (CHAR16
)) / sizeof (CHAR16
), L
"\\");
341 // cant move multiple files onto a single file.
343 ShellCloseFileMetaArg (&DestList
);
344 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_ERROR
), gShellLevel2HiiHandle
, L
"mv", DestParameter
);
345 return (SHELL_INVALID_PARAMETER
);
349 *DestPathPointer
= DestPath
;
350 ShellCloseFileMetaArg (&DestList
);
352 return (SHELL_SUCCESS
);
356 Function to do a move across file systems.
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
362 @retval SHELL_SUCCESS The source file was moved to the destination.
365 MoveBetweenFileSystems (
366 IN EFI_SHELL_FILE_INFO
*Node
,
367 IN CONST CHAR16
*DestPath
,
371 SHELL_STATUS ShellStatus
;
374 // First we copy the file
376 ShellStatus
= CopySingleFile (Node
->FullName
, DestPath
, Resp
, TRUE
, L
"mv");
381 if (ShellStatus
== SHELL_SUCCESS
) {
383 // The copy was successful. delete the source file.
385 CascadeDelete (Node
, TRUE
);
387 } else if (ShellStatus
== SHELL_ABORTED
) {
389 } else if (ShellStatus
== SHELL_ACCESS_DENIED
) {
390 return EFI_ACCESS_DENIED
;
391 } else if (ShellStatus
== SHELL_VOLUME_FULL
) {
392 return EFI_VOLUME_FULL
;
394 return EFI_UNSUPPORTED
;
397 return (EFI_SUCCESS
);
401 Function to take the destination path and target file name to generate the full destination path.
403 @param[in] DestPath A pointer to the destination file path string.
404 @param[out] FullDestPath A pointer to the full destination path string.
405 @param[in] FileName Name string of the targe file.
407 @retval SHELL_SUCCESS the files were all moved.
408 @retval SHELL_INVALID_PARAMETER a parameter was invalid
409 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
413 IN CONST CHAR16
**DestPath
,
414 OUT CHAR16
**FullDestPath
,
415 IN CONST CHAR16
*FileName
420 if ((FullDestPath
== NULL
) || (FileName
== NULL
) || (DestPath
== NULL
) || (*DestPath
== NULL
)) {
421 return (EFI_INVALID_PARAMETER
);
424 Size
= StrSize (*DestPath
) + StrSize (FileName
);
426 *FullDestPath
= AllocateZeroPool (Size
);
427 if (*FullDestPath
== NULL
) {
428 return (EFI_OUT_OF_RESOURCES
);
431 StrCpyS (*FullDestPath
, Size
/ sizeof (CHAR16
), *DestPath
);
432 if (((*FullDestPath
)[StrLen (*FullDestPath
)-1] != L
'\\') && (FileName
[0] != L
'\\')) {
433 StrCatS (*FullDestPath
, Size
/ sizeof (CHAR16
), L
"\\");
436 StrCatS (*FullDestPath
, Size
/ sizeof (CHAR16
), FileName
);
438 return (EFI_SUCCESS
);
442 Function to do a move within a file system.
444 @param[in] Node A pointer to the file to be removed.
445 @param[in] DestPath A pointer to the destination file path.
446 @param[out] Resp A pointer to response from question. Pass back on looped calling.
448 @retval SHELL_SUCCESS The source file was moved to the destination.
449 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
452 MoveWithinFileSystems (
453 IN EFI_SHELL_FILE_INFO
*Node
,
458 EFI_FILE_INFO
*NewFileInfo
;
459 CHAR16
*TempLocation
;
465 // Chop off map info from DestPath
467 if ((TempLocation
= StrStr (DestPath
, L
":")) != NULL
) {
468 CopyMem (DestPath
, TempLocation
+1, StrSize (TempLocation
+1));
472 // construct the new file info block
474 NewSize
= StrSize (DestPath
);
475 NewSize
+= StrSize (Node
->FileName
) + SIZE_OF_EFI_FILE_INFO
+ sizeof (CHAR16
);
476 NewFileInfo
= AllocateZeroPool (NewSize
);
477 if (NewFileInfo
== NULL
) {
478 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_MEM
), gShellLevel2HiiHandle
);
479 Status
= EFI_OUT_OF_RESOURCES
;
481 CopyMem (NewFileInfo
, Node
->Info
, SIZE_OF_EFI_FILE_INFO
);
482 if (DestPath
[0] != L
'\\') {
483 StrCpyS (NewFileInfo
->FileName
, (NewSize
- SIZE_OF_EFI_FILE_INFO
) / sizeof (CHAR16
), L
"\\");
484 StrCatS (NewFileInfo
->FileName
, (NewSize
- SIZE_OF_EFI_FILE_INFO
) / sizeof (CHAR16
), DestPath
);
486 StrCpyS (NewFileInfo
->FileName
, (NewSize
- SIZE_OF_EFI_FILE_INFO
) / sizeof (CHAR16
), DestPath
);
489 Length
= StrLen (NewFileInfo
->FileName
);
494 if (NewFileInfo
->FileName
[Length
] == L
'\\') {
495 if (Node
->FileName
[0] == L
'\\') {
497 // Don't allow for double slashes. Eliminate one of them.
499 NewFileInfo
->FileName
[Length
] = CHAR_NULL
;
502 StrCatS (NewFileInfo
->FileName
, (NewSize
- SIZE_OF_EFI_FILE_INFO
) / sizeof (CHAR16
), Node
->FileName
);
505 NewFileInfo
->Size
= SIZE_OF_EFI_FILE_INFO
+ StrSize (NewFileInfo
->FileName
);
508 // Perform the move operation
510 Status
= ShellSetFileInfo (Node
->Handle
, NewFileInfo
);
513 // Free the info object we used...
515 FreePool (NewFileInfo
);
522 function to take a list of files to move and a destination location and do
523 the verification and moving of those files to that location. This function
524 will report any errors to the user and continue to move the rest of the files.
526 @param[in] FileList A LIST_ENTRY* based list of files to move
527 @param[out] Resp pointer to response from question. Pass back on looped calling
528 @param[in] DestParameter the originally specified destination location
530 @retval SHELL_SUCCESS the files were all moved.
531 @retval SHELL_INVALID_PARAMETER a parameter was invalid
532 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
533 @retval SHELL_WRITE_PROTECTED the destination was write protected
534 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
537 ValidateAndMoveFiles (
538 IN EFI_SHELL_FILE_INFO
*FileList
,
540 IN CONST CHAR16
*DestParameter
547 CHAR16
*FullDestPath
;
550 SHELL_STATUS ShellStatus
;
551 EFI_SHELL_FILE_INFO
*Node
;
554 CHAR16
*CleanFilePathStr
;
556 ASSERT (FileList
!= NULL
);
557 ASSERT (DestParameter
!= NULL
);
561 Cwd
= ShellGetCurrentDir (NULL
);
564 CleanFilePathStr
= NULL
;
568 FullCwd
= AllocateZeroPool (StrSize (Cwd
) + sizeof (CHAR16
));
569 if (FullCwd
== NULL
) {
570 return SHELL_OUT_OF_RESOURCES
;
572 StrCpyS (FullCwd
, StrSize (Cwd
)/sizeof (CHAR16
)+1, Cwd
);
573 StrCatS (FullCwd
, StrSize (Cwd
)/sizeof (CHAR16
)+1, L
"\\");
577 Status
= ShellLevel2StripQuotes (DestParameter
, &CleanFilePathStr
);
578 if (EFI_ERROR (Status
)) {
579 SHELL_FREE_NON_NULL (FullCwd
);
580 if (Status
== EFI_OUT_OF_RESOURCES
) {
581 return SHELL_OUT_OF_RESOURCES
;
583 return SHELL_INVALID_PARAMETER
;
587 ASSERT (CleanFilePathStr
!= NULL
);
590 // Get and validate the destination location
592 ShellStatus
= GetDestinationLocation (CleanFilePathStr
, &DestPath
, FullCwd
, (BOOLEAN
)(FileList
->Link
.ForwardLink
== FileList
->Link
.BackLink
), &Attr
);
593 FreePool (CleanFilePathStr
);
595 if (ShellStatus
!= SHELL_SUCCESS
) {
596 SHELL_FREE_NON_NULL (FullCwd
);
597 return (ShellStatus
);
600 DestPath
= PathCleanUpDirectories (DestPath
);
601 if (DestPath
== NULL
) {
603 return (SHELL_OUT_OF_RESOURCES
);
606 HiiOutput
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_MV_OUTPUT
), NULL
);
607 HiiResultOk
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_GEN_RES_OK
), NULL
);
608 if ((HiiOutput
== NULL
) || (HiiResultOk
== NULL
)) {
609 SHELL_FREE_NON_NULL (DestPath
);
610 SHELL_FREE_NON_NULL (HiiOutput
);
611 SHELL_FREE_NON_NULL (HiiResultOk
);
612 SHELL_FREE_NON_NULL (FullCwd
);
613 return (SHELL_OUT_OF_RESOURCES
);
617 // Go through the list of files and directories to move...
619 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode (&FileList
->Link
)
620 ; !IsNull (&FileList
->Link
, &Node
->Link
)
621 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode (&FileList
->Link
, &Node
->Link
)
624 if (ShellGetExecutionBreakFlag ()) {
629 // These should never be NULL
631 ASSERT (Node
->FileName
!= NULL
);
632 ASSERT (Node
->FullName
!= NULL
);
633 ASSERT (Node
->Info
!= NULL
);
636 // skip the directory traversing stuff...
638 if ((StrCmp (Node
->FileName
, L
".") == 0) || (StrCmp (Node
->FileName
, L
"..") == 0)) {
642 SHELL_FREE_NON_NULL (FullDestPath
);
644 if (ShellIsDirectory (DestPath
) == EFI_SUCCESS
) {
645 CreateFullDestPath ((CONST CHAR16
**)&DestPath
, &FullDestPath
, Node
->FileName
);
649 // Validate that the move is valid
651 if (!IsValidMove (Node
->FullName
, FullCwd
, (FullDestPath
!= NULL
) ? FullDestPath
: DestPath
, Node
->Info
->Attribute
, Attr
, Node
->Status
)) {
652 ShellStatus
= SHELL_INVALID_PARAMETER
;
656 ShellPrintEx (-1, -1, HiiOutput
, Node
->FullName
, FullDestPath
!= NULL
? FullDestPath
: DestPath
);
659 // See if destination exists
661 if (!EFI_ERROR (ShellFileExists ((FullDestPath
!= NULL
) ? FullDestPath
: DestPath
))) {
662 if (Response
== NULL
) {
663 ShellPromptForResponseHii (ShellPromptResponseTypeYesNoAllCancel
, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR
), gShellLevel2HiiHandle
, &Response
);
666 if (Response
== NULL
) {
667 return SHELL_ABORTED
;
670 switch (*(SHELL_PROMPT_RESPONSE
*)Response
) {
671 case ShellPromptResponseNo
:
675 case ShellPromptResponseCancel
:
678 // indicate to stop everything
680 SHELL_FREE_NON_NULL (FullCwd
);
681 return (SHELL_ABORTED
);
682 case ShellPromptResponseAll
:
685 case ShellPromptResponseYes
:
691 SHELL_FREE_NON_NULL (FullCwd
);
692 return SHELL_ABORTED
;
695 Status
= ShellDeleteFileByName (FullDestPath
!= NULL
? FullDestPath
: DestPath
);
698 if (IsBetweenFileSystem (Node
->FullName
, FullCwd
, DestPath
)) {
699 while (FullDestPath
== NULL
&& DestPath
!= NULL
&& DestPath
[0] != CHAR_NULL
&& DestPath
[StrLen (DestPath
) - 1] == L
'\\') {
700 DestPath
[StrLen (DestPath
) - 1] = CHAR_NULL
;
703 Status
= MoveBetweenFileSystems (Node
, FullDestPath
!= NULL
? FullDestPath
: DestPath
, &Response
);
705 Status
= MoveWithinFileSystems (Node
, DestPath
, &Response
);
707 // Display error status
709 if (EFI_ERROR (Status
)) {
710 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_UK
), gShellLevel2HiiHandle
, L
"mv", Status
);
717 if (EFI_ERROR (Status
)) {
718 ShellStatus
= SHELL_INVALID_PARAMETER
;
719 if (Status
== EFI_SECURITY_VIOLATION
) {
720 ShellStatus
= SHELL_SECURITY_VIOLATION
;
721 } else if (Status
== EFI_WRITE_PROTECTED
) {
722 ShellStatus
= SHELL_WRITE_PROTECTED
;
723 } else if (Status
== EFI_OUT_OF_RESOURCES
) {
724 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
725 } else if (Status
== EFI_DEVICE_ERROR
) {
726 ShellStatus
= SHELL_DEVICE_ERROR
;
727 } else if (Status
== EFI_ACCESS_DENIED
) {
728 ShellStatus
= SHELL_ACCESS_DENIED
;
731 ShellPrintEx (-1, -1, L
"%s", HiiResultOk
);
735 SHELL_FREE_NON_NULL (FullDestPath
);
736 SHELL_FREE_NON_NULL (DestPath
);
737 SHELL_FREE_NON_NULL (HiiOutput
);
738 SHELL_FREE_NON_NULL (HiiResultOk
);
739 SHELL_FREE_NON_NULL (FullCwd
);
740 return (ShellStatus
);
744 Function for 'mv' command.
746 @param[in] ImageHandle Handle to the Image (NULL if Internal).
747 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
752 IN EFI_HANDLE ImageHandle
,
753 IN EFI_SYSTEM_TABLE
*SystemTable
758 CHAR16
*ProblemParam
;
761 SHELL_STATUS ShellStatus
;
764 EFI_SHELL_FILE_INFO
*FileList
;
768 ShellStatus
= SHELL_SUCCESS
;
774 // initialize the shell lib (we must be in non-auto-init...)
776 Status
= ShellInitialize ();
777 ASSERT_EFI_ERROR (Status
);
780 // parse the command line
782 Status
= ShellCommandLineParse (EmptyParamList
, &Package
, &ProblemParam
, TRUE
);
783 if (EFI_ERROR (Status
)) {
784 if ((Status
== EFI_VOLUME_CORRUPTED
) && (ProblemParam
!= NULL
)) {
785 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, L
"mv", ProblemParam
);
786 FreePool (ProblemParam
);
787 ShellStatus
= SHELL_INVALID_PARAMETER
;
795 if (ShellCommandLineGetFlag (Package
, L
"-?")) {
799 switch (ParamCount
= ShellCommandLineGetCount (Package
)) {
803 // we have insufficient parameters
805 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
, L
"mv");
806 ShellStatus
= SHELL_INVALID_PARAMETER
;
810 // must have valid CWD for single parameter...
812 if (ShellGetCurrentDir (NULL
) == NULL
) {
813 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
, L
"mv");
814 ShellStatus
= SHELL_INVALID_PARAMETER
;
816 Status
= ShellOpenFileMetaArg ((CHAR16
*)ShellCommandLineGetRawValue (Package
, 1), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
817 if ((FileList
== NULL
) || IsListEmpty (&FileList
->Link
) || EFI_ERROR (Status
)) {
818 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, L
"mv", ShellCommandLineGetRawValue (Package
, 1));
819 ShellStatus
= SHELL_NOT_FOUND
;
822 // ValidateAndMoveFiles will report errors to the screen itself
824 CwdSize
= StrSize (ShellGetCurrentDir (NULL
)) + sizeof (CHAR16
);
825 Cwd
= AllocateZeroPool (CwdSize
);
827 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_OUT_MEM
), gShellLevel2HiiHandle
, L
"mv");
828 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
830 StrCpyS (Cwd
, CwdSize
/ sizeof (CHAR16
), ShellGetCurrentDir (NULL
));
831 StrCatS (Cwd
, CwdSize
/ sizeof (CHAR16
), L
"\\");
832 ShellStatus
= ValidateAndMoveFiles (FileList
, &Response
, Cwd
);
840 /// @todo make sure this works with error half way through and continues...
841 for (ParamCount
--, LoopCounter
= 1; LoopCounter
< ParamCount
; LoopCounter
++) {
842 if (ShellGetExecutionBreakFlag ()) {
846 Status
= ShellOpenFileMetaArg ((CHAR16
*)ShellCommandLineGetRawValue (Package
, LoopCounter
), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
847 if ((FileList
== NULL
) || IsListEmpty (&FileList
->Link
) || EFI_ERROR (Status
)) {
848 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, L
"mv", ShellCommandLineGetRawValue (Package
, LoopCounter
));
849 ShellStatus
= SHELL_NOT_FOUND
;
852 // ValidateAndMoveFiles will report errors to the screen itself
853 // Only change ShellStatus if it's sucessful
855 if (ShellStatus
== SHELL_SUCCESS
) {
856 ShellStatus
= ValidateAndMoveFiles (FileList
, &Response
, ShellCommandLineGetRawValue (Package
, ParamCount
));
858 ValidateAndMoveFiles (FileList
, &Response
, ShellCommandLineGetRawValue (Package
, ParamCount
));
862 if ((FileList
!= NULL
) && !IsListEmpty (&FileList
->Link
)) {
863 Status
= ShellCloseFileMetaArg (&FileList
);
864 if (EFI_ERROR (Status
) && (ShellStatus
== SHELL_SUCCESS
)) {
865 ShellStatus
= SHELL_ACCESS_DENIED
;
866 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_FILE
), gShellLevel2HiiHandle
, L
"mv", ShellCommandLineGetRawValue (Package
, 1), ShellStatus
|MAX_BIT
);
872 } // switch on parameter count
874 if (FileList
!= NULL
) {
875 ShellCloseFileMetaArg (&FileList
);
879 // free the command line package
881 ShellCommandLineFreeVarList (Package
);
884 SHELL_FREE_NON_NULL (Response
);
886 if (ShellGetExecutionBreakFlag ()) {
887 return (SHELL_ABORTED
);
890 return (ShellStatus
);