2 Main file for mv shell level 2 function.
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
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.
15 #include "UefiShellLevel2CommandsLib.h"
18 Function to validate that moving a specific file (FileName) to a specific
19 location (DestPath) is valid.
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.
25 if the move is invalid this function will report the error to StdOut.
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
32 @retval TRUE The move is valid
33 @retval FALSE The move is not
38 IN CONST CHAR16
*FullName
,
40 IN CONST CHAR16
*DestPath
,
41 IN CONST UINT64 Attribute
49 if (Cwd
!= NULL
&& StrCmp(FullName
, Cwd
) == 0) {
53 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_CWD
), gShellLevel2HiiHandle
);
57 Test
= StrnCatGrow(&Test
, NULL
, DestPath
, 0);
59 ASSERT(TestWalker
!= NULL
);
60 while(*TestWalker
== L
'\\') {
63 while(TestWalker
!= NULL
&& TestWalker
[StrLen(TestWalker
)-1] == L
'\\') {
64 TestWalker
[StrLen(TestWalker
)-1] = CHAR_NULL
;
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
) {
76 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_SUB
), gShellLevel2HiiHandle
);
82 if (StrStr(DestPath
, FullName
) != 0 && StrStr(DestPath
, FullName
) != DestPath
) {
86 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_SUB
), gShellLevel2HiiHandle
);
89 if ((Attribute
& EFI_FILE_READ_ONLY
) != 0) {
91 // invalid to move read only
93 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_RO
), gShellLevel2HiiHandle
);
96 Test
= StrStr(FullName
, L
":");
97 Test1
= StrStr(DestPath
, L
":");
98 if (Test1
!= NULL
&& Test
!= NULL
) {
101 Result
= StringNoCaseCompare(&FullName
, &DestPath
);
105 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_FS
), gShellLevel2HiiHandle
);
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).
117 if the result is sucessful the caller must free *DestPathPointer.
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.
123 @retval EFI_INVALID_PARAMETR The DestDir could not be resolved to a location.
124 @retval EFI_INVALID_PARAMETR The DestDir could be resolved to more than 1 location.
125 @retval EFI_SUCCESS The operation was sucessful.
129 GetDestinationLocation(
130 IN CONST CHAR16
*DestDir
,
131 IN OUT CHAR16
**DestPathPointer
,
135 EFI_SHELL_FILE_INFO
*DestList
;
136 EFI_SHELL_FILE_INFO
*Node
;
139 CHAR16
*TempLocation
;
145 if (StrStr(DestDir
, L
"\\") == DestDir
) {
146 DestPath
= AllocateZeroPool(StrSize(Cwd
));
147 if (DestPath
== NULL
) {
148 return (SHELL_OUT_OF_RESOURCES
);
150 StrCpy(DestPath
, Cwd
);
151 while (ChopLastSlash(DestPath
)) ;
152 *DestPathPointer
= DestPath
;
153 return (SHELL_SUCCESS
);
156 // get the destination path
158 Status
= ShellOpenFileMetaArg((CHAR16
*)DestDir
, EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
|EFI_FILE_MODE_CREATE
, &DestList
);
159 if (DestList
== NULL
|| IsListEmpty(&DestList
->Link
)) {
161 // Not existing... must be renaming
163 if ((TempLocation
= StrStr(DestDir
, L
":")) == NULL
) {
164 NewSize
= StrSize(Cwd
);
165 NewSize
+= StrSize(DestDir
);
166 DestPath
= AllocateZeroPool(NewSize
);
167 if (DestPath
== NULL
) {
168 ShellCloseFileMetaArg(&DestList
);
169 return (SHELL_OUT_OF_RESOURCES
);
171 StrCpy(DestPath
, Cwd
);
172 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && DestDir
[0] != L
'\\') {
173 StrCat(DestPath
, L
"\\");
174 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && DestDir
[0] == L
'\\') {
175 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
177 StrCat(DestPath
, DestDir
);
179 ASSERT(DestPath
== NULL
);
180 DestPath
= StrnCatGrow(&DestPath
, NULL
, DestDir
, 0);
181 if (DestPath
== NULL
) {
182 ShellCloseFileMetaArg(&DestList
);
183 return (SHELL_OUT_OF_RESOURCES
);
187 Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&DestList
->Link
);
189 // Make sure there is only 1 node in the list.
191 if (!IsNodeAtEnd(&DestList
->Link
, &Node
->Link
)) {
192 ShellCloseFileMetaArg(&DestList
);
193 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_MARG_ERROR
), gShellLevel2HiiHandle
, DestDir
);
194 return (SHELL_INVALID_PARAMETER
);
196 if (ShellIsDirectory(Node
->FullName
)==EFI_SUCCESS
) {
197 DestPath
= AllocateZeroPool(StrSize(Node
->FullName
)+sizeof(CHAR16
));
198 if (DestPath
== NULL
) {
199 ShellCloseFileMetaArg(&DestList
);
200 return (SHELL_OUT_OF_RESOURCES
);
202 StrCpy(DestPath
, Node
->FullName
);
203 StrCat(DestPath
, L
"\\");
206 // cant move onto another file.
208 ShellCloseFileMetaArg(&DestList
);
209 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_ERROR
), gShellLevel2HiiHandle
, DestDir
);
210 return (SHELL_INVALID_PARAMETER
);
214 *DestPathPointer
= DestPath
;
215 ShellCloseFileMetaArg(&DestList
);
217 return (SHELL_SUCCESS
);
221 function to take a list of files to move and a destination location and do
222 the verification and moving of those files to that location. This function
223 will report any errors to the user and continue to move the rest of the files.
225 @param[in] FileList A LIST_ENTRY* based list of files to move
226 @param[out] Resp pointer to response from question. Pass back on looped calling
227 @param[in] DestDir the destination location
229 @retval SHELL_SUCCESS the files were all moved.
230 @retval SHELL_INVALID_PARAMETER a parameter was invalid
231 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
232 @retval SHELL_WRITE_PROTECTED the destination was write protected
233 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
237 ValidateAndMoveFiles(
238 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
240 IN CONST CHAR16
*DestDir
248 SHELL_STATUS ShellStatus
;
249 CONST EFI_SHELL_FILE_INFO
*Node
;
250 EFI_FILE_INFO
*NewFileInfo
;
251 CHAR16
*TempLocation
;
255 SHELL_FILE_HANDLE DestHandle
;
257 ASSERT(FileList
!= NULL
);
258 ASSERT(DestDir
!= NULL
);
261 Cwd
= ShellGetCurrentDir(NULL
);
265 // Get and validate the destination location
267 ShellStatus
= GetDestinationLocation(DestDir
, &DestPath
, Cwd
);
268 if (ShellStatus
!= SHELL_SUCCESS
) {
269 return (ShellStatus
);
271 DestPath
= CleanPath(DestPath
);
273 HiiOutput
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_MV_OUTPUT
), NULL
);
274 HiiResultOk
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_GEN_RES_OK
), NULL
);
275 ASSERT (DestPath
!= NULL
);
276 ASSERT (HiiResultOk
!= NULL
);
277 ASSERT (HiiOutput
!= NULL
);
278 // ASSERT (Cwd != NULL);
281 // Go through the list of files and directories to move...
283 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
284 ; !IsNull(&FileList
->Link
, &Node
->Link
)
285 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
287 if (ShellGetExecutionBreakFlag()) {
290 ASSERT(Node
->FileName
!= NULL
);
291 ASSERT(Node
->FullName
!= NULL
);
294 // skip the directory traversing stuff...
296 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
301 // Validate that the move is valid
303 if (!IsValidMove(Node
->FullName
, Cwd
, DestPath
, Node
->Info
->Attribute
)) {
304 ShellStatus
= SHELL_INVALID_PARAMETER
;
309 // Chop off map info from "DestPath"
311 if ((TempLocation
= StrStr(DestPath
, L
":")) != NULL
) {
312 CopyMem(DestPath
, TempLocation
+1, StrSize(TempLocation
+1));
316 // construct the new file info block
318 NewSize
= StrSize(DestPath
);
319 NewSize
+= StrSize(Node
->FileName
) + sizeof(EFI_FILE_INFO
) + sizeof(CHAR16
);
320 NewFileInfo
= AllocateZeroPool(NewSize
);
321 if (NewFileInfo
== NULL
) {
322 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_MEM
), gShellLevel2HiiHandle
);
323 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
325 CopyMem(NewFileInfo
, Node
->Info
, sizeof(EFI_FILE_INFO
));
326 if (DestPath
[0] != L
'\\') {
327 StrCpy(NewFileInfo
->FileName
, L
"\\");
328 StrCat(NewFileInfo
->FileName
, DestPath
);
330 StrCpy(NewFileInfo
->FileName
, DestPath
);
332 Length
= StrLen(NewFileInfo
->FileName
);
336 if (NewFileInfo
->FileName
[Length
] == L
'\\') {
337 if (Node
->FileName
[0] == L
'\\') {
339 // Don't allow for double slashes. Eliminate one of them.
341 NewFileInfo
->FileName
[Length
] = CHAR_NULL
;
343 StrCat(NewFileInfo
->FileName
, Node
->FileName
);
345 NewFileInfo
->Size
= sizeof(EFI_FILE_INFO
) + StrSize(NewFileInfo
->FileName
);
346 ShellPrintEx(-1, -1, HiiOutput
, Node
->FullName
, NewFileInfo
->FileName
);
348 if (!EFI_ERROR(ShellFileExists(NewFileInfo
->FileName
))) {
349 if (Response
== NULL
) {
350 ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel
, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR
), gShellLevel2HiiHandle
, &Response
);
352 switch (*(SHELL_PROMPT_RESPONSE
*)Response
) {
353 case ShellPromptResponseNo
:
354 FreePool(NewFileInfo
);
356 case ShellPromptResponseCancel
:
359 // indicate to stop everything
361 FreePool(NewFileInfo
);
364 FreePool(HiiResultOk
);
365 return (SHELL_ABORTED
);
366 case ShellPromptResponseAll
:
369 case ShellPromptResponseYes
:
374 FreePool(NewFileInfo
);
377 FreePool(HiiResultOk
);
378 return SHELL_ABORTED
;
380 Status
= ShellOpenFileByName(NewFileInfo
->FileName
, &DestHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
, 0);
381 ShellDeleteFile(&DestHandle
);
386 // Perform the move operation
388 Status
= ShellSetFileInfo(Node
->Handle
, NewFileInfo
);
391 // Free the info object we used...
393 FreePool(NewFileInfo
);
398 if (EFI_ERROR(Status
)) {
399 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_UK
), gShellLevel2HiiHandle
, Status
);
405 ShellStatus
= SHELL_INVALID_PARAMETER
;
406 case EFI_SECURITY_VIOLATION
:
407 ShellStatus
= SHELL_SECURITY_VIOLATION
;
408 case EFI_WRITE_PROTECTED
:
409 ShellStatus
= SHELL_WRITE_PROTECTED
;
410 case EFI_OUT_OF_RESOURCES
:
411 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
412 case EFI_DEVICE_ERROR
:
413 ShellStatus
= SHELL_DEVICE_ERROR
;
414 case EFI_ACCESS_DENIED
:
415 ShellStatus
= SHELL_ACCESS_DENIED
;
418 ShellPrintEx(-1, -1, L
"%s", HiiResultOk
);
425 FreePool(HiiResultOk
);
426 return (ShellStatus
);
430 Function for 'mv' command.
432 @param[in] ImageHandle Handle to the Image (NULL if Internal).
433 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
438 IN EFI_HANDLE ImageHandle
,
439 IN EFI_SYSTEM_TABLE
*SystemTable
444 CHAR16
*ProblemParam
;
445 SHELL_STATUS ShellStatus
;
448 EFI_SHELL_FILE_INFO
*FileList
;
452 ShellStatus
= SHELL_SUCCESS
;
458 // initialize the shell lib (we must be in non-auto-init...)
460 Status
= ShellInitialize();
461 ASSERT_EFI_ERROR(Status
);
464 // parse the command line
466 Status
= ShellCommandLineParse (EmptyParamList
, &Package
, &ProblemParam
, TRUE
);
467 if (EFI_ERROR(Status
)) {
468 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
469 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, ProblemParam
);
470 FreePool(ProblemParam
);
471 ShellStatus
= SHELL_INVALID_PARAMETER
;
479 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
483 switch (ParamCount
= ShellCommandLineGetCount(Package
)) {
487 // we have insufficient parameters
489 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
);
490 ShellStatus
= SHELL_INVALID_PARAMETER
;
494 // must have valid CWD for single parameter...
496 if (ShellGetCurrentDir(NULL
) == NULL
){
497 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
498 ShellStatus
= SHELL_INVALID_PARAMETER
;
500 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, 1), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
501 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
502 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1));
503 ShellStatus
= SHELL_NOT_FOUND
;
506 // ValidateAndMoveFiles will report errors to the screen itself
508 ShellStatus
= ValidateAndMoveFiles(FileList
, &Response
, ShellGetCurrentDir(NULL
));
514 ///@todo make sure this works with error half way through and continues...
515 for (ParamCount
--, LoopCounter
= 1 ; LoopCounter
< ParamCount
; LoopCounter
++) {
516 if (ShellGetExecutionBreakFlag()) {
519 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, LoopCounter
), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
520 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
521 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, LoopCounter
));
522 ShellStatus
= SHELL_NOT_FOUND
;
525 // ValidateAndMoveFiles will report errors to the screen itself
526 // Only change ShellStatus if it's sucessful
528 if (ShellStatus
== SHELL_SUCCESS
) {
529 ShellStatus
= ValidateAndMoveFiles(FileList
, &Response
, ShellCommandLineGetRawValue(Package
, ParamCount
));
531 ValidateAndMoveFiles(FileList
, &Response
, ShellCommandLineGetRawValue(Package
, ParamCount
));
534 if (FileList
!= NULL
&& !IsListEmpty(&FileList
->Link
)) {
535 Status
= ShellCloseFileMetaArg(&FileList
);
536 if (EFI_ERROR(Status
) && ShellStatus
== SHELL_SUCCESS
) {
537 ShellStatus
= SHELL_ACCESS_DENIED
;
538 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_FILE
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1), ShellStatus
|MAX_BIT
);
543 } // switch on parameter count
545 if (FileList
!= NULL
) {
546 ShellCloseFileMetaArg(&FileList
);
550 // free the command line package
552 ShellCommandLineFreeVarList (Package
);
555 SHELL_FREE_NON_NULL(Response
);
557 if (ShellGetExecutionBreakFlag()) {
558 return (SHELL_ABORTED
);
561 return (ShellStatus
);