2 Main file for mv shell level 2 function.
4 Copyright (c) 2009 - 2010, 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.
122 @retval EFI_INVALID_PARAMETR the DestDir could not be resolved to a location
123 @retval EFI_INVALID_PARAMETR the DestDir could be resolved to more than 1 location
124 @retval EFI_SUCCESS the operation was sucessful
128 GetDestinationLocation(
129 IN CONST CHAR16
*DestDir
,
130 IN OUT CHAR16
**DestPathPointer
,
134 EFI_SHELL_FILE_INFO
*DestList
;
135 EFI_SHELL_FILE_INFO
*Node
;
138 CHAR16
*TempLocation
;
144 // get the destination path
146 Status
= ShellOpenFileMetaArg((CHAR16
*)DestDir
, EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
|EFI_FILE_MODE_CREATE
, &DestList
);
147 if (DestList
== NULL
|| IsListEmpty(&DestList
->Link
)) {
149 // Not existing... must be renaming
151 if ((TempLocation
= StrStr(DestDir
, L
":")) == NULL
) {
152 NewSize
= StrSize(Cwd
);
153 NewSize
+= StrSize(DestDir
);
154 DestPath
= AllocateZeroPool(NewSize
);
155 if (DestPath
== NULL
) {
156 ShellCloseFileMetaArg(&DestList
);
157 return (SHELL_OUT_OF_RESOURCES
);
159 StrCpy(DestPath
, Cwd
);
160 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && DestDir
[0] != L
'\\') {
161 StrCat(DestPath
, L
"\\");
162 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && DestDir
[0] == L
'\\') {
163 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
165 StrCat(DestPath
, DestDir
);
167 ASSERT(DestPath
== NULL
);
168 DestPath
= StrnCatGrow(&DestPath
, NULL
, DestDir
, 0);
169 if (DestPath
== NULL
) {
170 ShellCloseFileMetaArg(&DestList
);
171 return (SHELL_OUT_OF_RESOURCES
);
175 Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&DestList
->Link
);
177 // Make sure there is only 1 node in the list.
179 if (!IsNodeAtEnd(&DestList
->Link
, &Node
->Link
)) {
180 ShellCloseFileMetaArg(&DestList
);
181 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_MARG_ERROR
), gShellLevel2HiiHandle
, DestDir
);
182 return (SHELL_INVALID_PARAMETER
);
184 if (ShellIsDirectory(Node
->FullName
)==EFI_SUCCESS
) {
185 DestPath
= AllocateZeroPool(StrSize(Node
->FullName
)+sizeof(CHAR16
));
186 if (DestPath
== NULL
) {
187 ShellCloseFileMetaArg(&DestList
);
188 return (SHELL_OUT_OF_RESOURCES
);
190 StrCpy(DestPath
, Node
->FullName
);
191 StrCat(DestPath
, L
"\\");
194 // cant move onto another file.
196 ShellCloseFileMetaArg(&DestList
);
197 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_ERROR
), gShellLevel2HiiHandle
, DestDir
);
198 return (SHELL_INVALID_PARAMETER
);
202 *DestPathPointer
= DestPath
;
203 ShellCloseFileMetaArg(&DestList
);
205 return (SHELL_SUCCESS
);
209 function to take a list of files to move and a destination location and do
210 the verification and moving of those files to that location. This function
211 will report any errors to the user and continue to move the rest of the files.
213 @param[in] FileList A LIST_ENTRY* based list of files to move
214 @param[in] DestDir the destination location
216 @retval SHELL_SUCCESS the files were all moved.
217 @retval SHELL_INVALID_PARAMETER a parameter was invalid
218 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
219 @retval SHELL_WRITE_PROTECTED the destination was write protected
220 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
224 ValidateAndMoveFiles(
225 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
226 IN CONST CHAR16
*DestDir
234 SHELL_STATUS ShellStatus
;
235 CONST EFI_SHELL_FILE_INFO
*Node
;
236 EFI_FILE_INFO
*NewFileInfo
;
237 CHAR16
*TempLocation
;
240 ASSERT(FileList
!= NULL
);
241 ASSERT(DestDir
!= NULL
);
244 Cwd
= ShellGetCurrentDir(NULL
);
247 // Get and validate the destination location
249 ShellStatus
= GetDestinationLocation(DestDir
, &DestPath
, Cwd
);
250 if (ShellStatus
!= SHELL_SUCCESS
) {
251 return (ShellStatus
);
254 HiiOutput
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_MV_OUTPUT
), NULL
);
255 HiiResultOk
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_GEN_RES_OK
), NULL
);
256 ASSERT (DestPath
!= NULL
);
257 ASSERT (HiiResultOk
!= NULL
);
258 ASSERT (HiiOutput
!= NULL
);
259 // ASSERT (Cwd != NULL);
262 // Go through the list of files and directories to move...
264 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
265 ; !IsNull(&FileList
->Link
, &Node
->Link
)
266 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
268 if (ShellGetExecutionBreakFlag()) {
271 ASSERT(Node
->FileName
!= NULL
);
272 ASSERT(Node
->FullName
!= NULL
);
275 // skip the directory traversing stuff...
277 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
282 // Validate that the move is valid
284 if (!IsValidMove(Node
->FullName
, Cwd
, DestPath
, Node
->Info
->Attribute
)) {
285 ShellStatus
= SHELL_INVALID_PARAMETER
;
290 // Chop off map info from "DestPath"
292 if ((TempLocation
= StrStr(DestPath
, L
":")) != NULL
) {
293 CopyMem(DestPath
, TempLocation
+1, StrSize(TempLocation
+1));
297 // construct the new file info block
299 NewSize
= StrSize(DestPath
);
300 NewSize
+= StrSize(Node
->FileName
) + sizeof(EFI_FILE_INFO
) + sizeof(CHAR16
);
301 NewFileInfo
= AllocateZeroPool(NewSize
);
302 if (NewFileInfo
== NULL
) {
303 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_MEM
), gShellLevel2HiiHandle
);
304 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
306 CopyMem(NewFileInfo
, Node
->Info
, sizeof(EFI_FILE_INFO
));
307 if (DestPath
[0] != L
'\\') {
308 StrCpy(NewFileInfo
->FileName
, L
"\\");
309 StrCat(NewFileInfo
->FileName
, DestPath
);
311 StrCpy(NewFileInfo
->FileName
, DestPath
);
313 if (NewFileInfo
->FileName
[StrLen(NewFileInfo
->FileName
)-1] == L
'\\') {
314 if (Node
->FileName
[0] == L
'\\') {
316 // Don't allow for double slashes. Eliminate one of them.
318 NewFileInfo
->FileName
[StrLen(NewFileInfo
->FileName
)-1] = CHAR_NULL
;
320 StrCat(NewFileInfo
->FileName
, Node
->FileName
);
322 NewFileInfo
->Size
= sizeof(EFI_FILE_INFO
) + StrSize(NewFileInfo
->FileName
);
324 ShellPrintEx(-1, -1, HiiOutput
, Node
->FullName
, NewFileInfo
->FileName
);
327 // Perform the move operation
329 Status
= ShellSetFileInfo(Node
->Handle
, NewFileInfo
);
332 // Free the info object we used...
334 ASSERT (NewFileInfo
!= NULL
);
335 FreePool(NewFileInfo
);
340 if (EFI_ERROR(Status
)) {
341 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_UK
), gShellLevel2HiiHandle
, Status
);
347 ShellStatus
= SHELL_INVALID_PARAMETER
;
348 case EFI_SECURITY_VIOLATION
:
349 ShellStatus
= SHELL_SECURITY_VIOLATION
;
350 case EFI_WRITE_PROTECTED
:
351 ShellStatus
= SHELL_WRITE_PROTECTED
;
352 case EFI_OUT_OF_RESOURCES
:
353 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
354 case EFI_DEVICE_ERROR
:
355 ShellStatus
= SHELL_DEVICE_ERROR
;
356 case EFI_ACCESS_DENIED
:
357 ShellStatus
= SHELL_ACCESS_DENIED
;
360 ShellPrintEx(-1, -1, L
"%s", HiiResultOk
);
367 FreePool(HiiResultOk
);
368 return (ShellStatus
);
374 IN EFI_HANDLE ImageHandle
,
375 IN EFI_SYSTEM_TABLE
*SystemTable
380 CHAR16
*ProblemParam
;
381 SHELL_STATUS ShellStatus
;
384 EFI_SHELL_FILE_INFO
*FileList
;
387 ShellStatus
= SHELL_SUCCESS
;
392 // initialize the shell lib (we must be in non-auto-init...)
394 Status
= ShellInitialize();
395 ASSERT_EFI_ERROR(Status
);
398 // parse the command line
400 Status
= ShellCommandLineParse (EmptyParamList
, &Package
, &ProblemParam
, TRUE
);
401 if (EFI_ERROR(Status
)) {
402 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
403 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, ProblemParam
);
404 FreePool(ProblemParam
);
405 ShellStatus
= SHELL_INVALID_PARAMETER
;
413 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
417 switch (ParamCount
= ShellCommandLineGetCount(Package
)) {
421 // we have insufficient parameters
423 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
);
424 ShellStatus
= SHELL_INVALID_PARAMETER
;
428 // must have valid CWD for single parameter...
430 if (ShellGetCurrentDir(NULL
) == NULL
){
431 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
432 ShellStatus
= SHELL_INVALID_PARAMETER
;
434 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, 1), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
435 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
436 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1));
437 ShellStatus
= SHELL_NOT_FOUND
;
440 // ValidateAndMoveFiles will report errors to the screen itself
442 ShellStatus
= ValidateAndMoveFiles(FileList
, ShellGetCurrentDir(NULL
));
448 ///@todo make sure this works with error half way through and continues...
449 for (ParamCount
--, LoopCounter
= 1 ; LoopCounter
< ParamCount
&& ShellStatus
== SHELL_SUCCESS
; LoopCounter
++) {
450 if (ShellGetExecutionBreakFlag()) {
453 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, LoopCounter
), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
454 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
455 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1));
456 ShellStatus
= SHELL_NOT_FOUND
;
459 // ValidateAndMoveFiles will report errors to the screen itself
460 // Only change ShellStatus if it's sucessful
462 if (ShellStatus
== SHELL_SUCCESS
) {
463 ShellStatus
= ValidateAndMoveFiles(FileList
, ShellCommandLineGetRawValue(Package
, ParamCount
));
465 ValidateAndMoveFiles(FileList
, ShellCommandLineGetRawValue(Package
, ParamCount
));
468 if (FileList
!= NULL
&& !IsListEmpty(&FileList
->Link
)) {
469 Status
= ShellCloseFileMetaArg(&FileList
);
470 if (EFI_ERROR(Status
) && ShellStatus
== SHELL_SUCCESS
) {
471 ShellStatus
= SHELL_ACCESS_DENIED
;
472 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_FILE
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1), ShellStatus
|MAX_BIT
);
477 } // switch on parameter count
479 if (FileList
!= NULL
) {
480 ShellCloseFileMetaArg(&FileList
);
484 // free the command line package
486 ShellCommandLineFreeVarList (Package
);
489 if (ShellGetExecutionBreakFlag()) {
490 return (SHELL_ABORTED
);
493 return (ShellStatus
);