2 Main file for mv shell level 2 function.
4 Copyright (c) 2013, Hewlett-Packard Development Company, L.P.
5 Copyright (c) 2009 - 2013, 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
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.
16 #include "UefiShellLevel2CommandsLib.h"
19 Function to validate that moving a specific file (FileName) to a specific
20 location (DestPath) is valid.
22 This function will verify that the destination is not a subdirectory of
23 FullName, that the Current working Directory is not being moved, and that
24 the directory is not read only.
26 if the move is invalid this function will report the error to StdOut.
28 @param FullName [in] The name of the file to move.
29 @param Cwd [in] The current working directory
30 @param DestPath [in] The target location to move to
31 @param Attribute[in] The Attribute of the file
33 @retval TRUE The move is valid
34 @retval FALSE The move is not
39 IN CONST CHAR16
*FullName
,
41 IN CONST CHAR16
*DestPath
,
42 IN CONST UINT64 Attribute
50 if (Cwd
!= NULL
&& StrCmp(FullName
, Cwd
) == 0) {
54 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_CWD
), gShellLevel2HiiHandle
);
58 Test
= StrnCatGrow(&Test
, NULL
, DestPath
, 0);
60 ASSERT(TestWalker
!= NULL
);
61 while(*TestWalker
== L
'\\') {
64 while(TestWalker
!= NULL
&& TestWalker
[StrLen(TestWalker
)-1] == L
'\\') {
65 TestWalker
[StrLen(TestWalker
)-1] = CHAR_NULL
;
67 ASSERT(TestWalker
!= NULL
);
68 ASSERT(FullName
!= NULL
);
69 if (StrStr(FullName
, TestWalker
) != 0) {
70 TempLen
= StrLen(FullName
);
71 if (StrStr(FullName
, TestWalker
) != FullName
// not the first items... (could below it)
72 && TempLen
<= (StrLen(TestWalker
) + 1)
73 && StrStr(FullName
+StrLen(TestWalker
) + 1, L
"\\") == NULL
) {
77 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_SUB
), gShellLevel2HiiHandle
);
83 if (StrStr(DestPath
, FullName
) != 0 && StrStr(DestPath
, FullName
) != DestPath
) {
87 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_SUB
), gShellLevel2HiiHandle
);
90 if ((Attribute
& EFI_FILE_READ_ONLY
) != 0) {
92 // invalid to move read only
94 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_RO
), gShellLevel2HiiHandle
);
97 Test
= StrStr(FullName
, L
":");
98 Test1
= StrStr(DestPath
, L
":");
99 if (Test1
!= NULL
&& Test
!= NULL
) {
102 Result
= StringNoCaseCompare(&FullName
, &DestPath
);
106 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_MV_INV_FS
), gShellLevel2HiiHandle
);
114 Function to take a destination path that might contain wildcards and verify
115 that there is only a single possible target (IE we cant have wildcards that
116 have 2 possible destination).
118 if the result is sucessful the caller must free *DestPathPointer.
120 @param[in] DestDir The original path to the destination.
121 @param[in, out] DestPathPointer A pointer to the callee allocated final path.
122 @param[in] Cwd A pointer to the current working directory.
124 @retval SHELL_INVALID_PARAMETER The DestDir could not be resolved to a location.
125 @retval SHELL_INVALID_PARAMETER The DestDir could be resolved to more than 1 location.
126 @retval SHELL_INVALID_PARAMETER Cwd is required and is NULL.
127 @retval SHELL_SUCCESS The operation was sucessful.
131 GetDestinationLocation(
132 IN CONST CHAR16
*DestDir
,
133 IN OUT CHAR16
**DestPathPointer
,
137 EFI_SHELL_FILE_INFO
*DestList
;
138 EFI_SHELL_FILE_INFO
*Node
;
146 if (StrStr(DestDir
, L
"\\") == DestDir
) {
148 return SHELL_INVALID_PARAMETER
;
150 DestPath
= AllocateZeroPool(StrSize(Cwd
));
151 if (DestPath
== NULL
) {
152 return (SHELL_OUT_OF_RESOURCES
);
154 StrCpy(DestPath
, Cwd
);
155 while (PathRemoveLastItem(DestPath
)) ;
158 // Append DestDir beyond '\' which may be present
160 CurrentSize
= StrSize(DestPath
);
161 StrnCatGrow(&DestPath
, &CurrentSize
, &DestDir
[1], 0);
163 *DestPathPointer
= DestPath
;
164 return (SHELL_SUCCESS
);
167 // get the destination path
169 ShellOpenFileMetaArg((CHAR16
*)DestDir
, EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
|EFI_FILE_MODE_CREATE
, &DestList
);
170 if (DestList
== NULL
|| IsListEmpty(&DestList
->Link
)) {
172 // Not existing... must be renaming
174 if (StrStr(DestDir
, L
":") == NULL
) {
176 ShellCloseFileMetaArg(&DestList
);
177 return (SHELL_INVALID_PARAMETER
);
179 NewSize
= StrSize(Cwd
);
180 NewSize
+= StrSize(DestDir
);
181 DestPath
= AllocateZeroPool(NewSize
);
182 if (DestPath
== NULL
) {
183 ShellCloseFileMetaArg(&DestList
);
184 return (SHELL_OUT_OF_RESOURCES
);
186 StrCpy(DestPath
, Cwd
);
187 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && DestDir
[0] != L
'\\') {
188 StrCat(DestPath
, L
"\\");
189 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && DestDir
[0] == L
'\\') {
190 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
192 StrCat(DestPath
, DestDir
);
194 ASSERT(DestPath
== NULL
);
195 DestPath
= StrnCatGrow(&DestPath
, NULL
, DestDir
, 0);
196 if (DestPath
== NULL
) {
197 ShellCloseFileMetaArg(&DestList
);
198 return (SHELL_OUT_OF_RESOURCES
);
202 Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&DestList
->Link
);
204 // Make sure there is only 1 node in the list.
206 if (!IsNodeAtEnd(&DestList
->Link
, &Node
->Link
)) {
207 ShellCloseFileMetaArg(&DestList
);
208 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_MARG_ERROR
), gShellLevel2HiiHandle
, DestDir
);
209 return (SHELL_INVALID_PARAMETER
);
211 if (ShellIsDirectory(Node
->FullName
)==EFI_SUCCESS
) {
212 DestPath
= AllocateZeroPool(StrSize(Node
->FullName
)+sizeof(CHAR16
));
213 if (DestPath
== NULL
) {
214 ShellCloseFileMetaArg(&DestList
);
215 return (SHELL_OUT_OF_RESOURCES
);
217 StrCpy(DestPath
, Node
->FullName
);
218 StrCat(DestPath
, L
"\\");
221 // cant move onto another file.
223 ShellCloseFileMetaArg(&DestList
);
224 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_ERROR
), gShellLevel2HiiHandle
, DestDir
);
225 return (SHELL_INVALID_PARAMETER
);
229 *DestPathPointer
= DestPath
;
230 ShellCloseFileMetaArg(&DestList
);
232 return (SHELL_SUCCESS
);
236 function to take a list of files to move and a destination location and do
237 the verification and moving of those files to that location. This function
238 will report any errors to the user and continue to move the rest of the files.
240 @param[in] FileList A LIST_ENTRY* based list of files to move
241 @param[out] Resp pointer to response from question. Pass back on looped calling
242 @param[in] DestDir the destination location
244 @retval SHELL_SUCCESS the files were all moved.
245 @retval SHELL_INVALID_PARAMETER a parameter was invalid
246 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
247 @retval SHELL_WRITE_PROTECTED the destination was write protected
248 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
252 ValidateAndMoveFiles(
253 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
255 IN CONST CHAR16
*DestDir
263 SHELL_STATUS ShellStatus
;
264 CONST EFI_SHELL_FILE_INFO
*Node
;
265 EFI_FILE_INFO
*NewFileInfo
;
266 CHAR16
*TempLocation
;
270 SHELL_FILE_HANDLE DestHandle
;
272 ASSERT(FileList
!= NULL
);
273 ASSERT(DestDir
!= NULL
);
276 Cwd
= ShellGetCurrentDir(NULL
);
280 // Get and validate the destination location
282 ShellStatus
= GetDestinationLocation(DestDir
, &DestPath
, Cwd
);
283 if (ShellStatus
!= SHELL_SUCCESS
) {
284 return (ShellStatus
);
286 DestPath
= PathCleanUpDirectories(DestPath
);
288 HiiOutput
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_MV_OUTPUT
), NULL
);
289 HiiResultOk
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_GEN_RES_OK
), NULL
);
290 ASSERT (DestPath
!= NULL
);
291 ASSERT (HiiResultOk
!= NULL
);
292 ASSERT (HiiOutput
!= NULL
);
293 // ASSERT (Cwd != NULL);
296 // Go through the list of files and directories to move...
298 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
299 ; !IsNull(&FileList
->Link
, &Node
->Link
)
300 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
302 if (ShellGetExecutionBreakFlag()) {
305 ASSERT(Node
->FileName
!= NULL
);
306 ASSERT(Node
->FullName
!= NULL
);
309 // skip the directory traversing stuff...
311 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
316 // Validate that the move is valid
318 if (!IsValidMove(Node
->FullName
, Cwd
, DestPath
, Node
->Info
->Attribute
)) {
319 ShellStatus
= SHELL_INVALID_PARAMETER
;
324 // Chop off map info from "DestPath"
326 if ((TempLocation
= StrStr(DestPath
, L
":")) != NULL
) {
327 CopyMem(DestPath
, TempLocation
+1, StrSize(TempLocation
+1));
331 // construct the new file info block
333 NewSize
= StrSize(DestPath
);
334 NewSize
+= StrSize(Node
->FileName
) + SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
335 NewFileInfo
= AllocateZeroPool(NewSize
);
336 if (NewFileInfo
== NULL
) {
337 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_MEM
), gShellLevel2HiiHandle
);
338 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
340 CopyMem(NewFileInfo
, Node
->Info
, SIZE_OF_EFI_FILE_INFO
);
341 if (DestPath
[0] != L
'\\') {
342 StrCpy(NewFileInfo
->FileName
, L
"\\");
343 StrCat(NewFileInfo
->FileName
, DestPath
);
345 StrCpy(NewFileInfo
->FileName
, DestPath
);
347 Length
= StrLen(NewFileInfo
->FileName
);
351 if (NewFileInfo
->FileName
[Length
] == L
'\\') {
352 if (Node
->FileName
[0] == L
'\\') {
354 // Don't allow for double slashes. Eliminate one of them.
356 NewFileInfo
->FileName
[Length
] = CHAR_NULL
;
358 StrCat(NewFileInfo
->FileName
, Node
->FileName
);
360 NewFileInfo
->Size
= SIZE_OF_EFI_FILE_INFO
+ StrSize(NewFileInfo
->FileName
);
361 ShellPrintEx(-1, -1, HiiOutput
, Node
->FullName
, NewFileInfo
->FileName
);
363 if (!EFI_ERROR(ShellFileExists(NewFileInfo
->FileName
))) {
364 if (Response
== NULL
) {
365 ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel
, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR
), gShellLevel2HiiHandle
, &Response
);
367 switch (*(SHELL_PROMPT_RESPONSE
*)Response
) {
368 case ShellPromptResponseNo
:
369 FreePool(NewFileInfo
);
371 case ShellPromptResponseCancel
:
374 // indicate to stop everything
376 FreePool(NewFileInfo
);
379 FreePool(HiiResultOk
);
380 return (SHELL_ABORTED
);
381 case ShellPromptResponseAll
:
384 case ShellPromptResponseYes
:
389 FreePool(NewFileInfo
);
392 FreePool(HiiResultOk
);
393 return SHELL_ABORTED
;
395 Status
= ShellOpenFileByName(NewFileInfo
->FileName
, &DestHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
, 0);
396 ShellDeleteFile(&DestHandle
);
401 // Perform the move operation
403 Status
= ShellSetFileInfo(Node
->Handle
, NewFileInfo
);
406 // Free the info object we used...
408 FreePool(NewFileInfo
);
413 if (EFI_ERROR(Status
)) {
414 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_UK
), gShellLevel2HiiHandle
, Status
);
415 ShellStatus
= SHELL_INVALID_PARAMETER
;
416 if (Status
== EFI_SECURITY_VIOLATION
) {
417 ShellStatus
= SHELL_SECURITY_VIOLATION
;
418 } else if (Status
== EFI_WRITE_PROTECTED
) {
419 ShellStatus
= SHELL_WRITE_PROTECTED
;
420 } else if (Status
== EFI_OUT_OF_RESOURCES
) {
421 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
422 } else if (Status
== EFI_DEVICE_ERROR
) {
423 ShellStatus
= SHELL_DEVICE_ERROR
;
424 } else if (Status
== EFI_ACCESS_DENIED
) {
425 ShellStatus
= SHELL_ACCESS_DENIED
;
428 ShellPrintEx(-1, -1, L
"%s", HiiResultOk
);
435 FreePool(HiiResultOk
);
436 return (ShellStatus
);
440 Function for 'mv' command.
442 @param[in] ImageHandle Handle to the Image (NULL if Internal).
443 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
448 IN EFI_HANDLE ImageHandle
,
449 IN EFI_SYSTEM_TABLE
*SystemTable
454 CHAR16
*ProblemParam
;
455 SHELL_STATUS ShellStatus
;
458 EFI_SHELL_FILE_INFO
*FileList
;
462 ShellStatus
= SHELL_SUCCESS
;
468 // initialize the shell lib (we must be in non-auto-init...)
470 Status
= ShellInitialize();
471 ASSERT_EFI_ERROR(Status
);
474 // parse the command line
476 Status
= ShellCommandLineParse (EmptyParamList
, &Package
, &ProblemParam
, TRUE
);
477 if (EFI_ERROR(Status
)) {
478 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
479 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, ProblemParam
);
480 FreePool(ProblemParam
);
481 ShellStatus
= SHELL_INVALID_PARAMETER
;
489 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
493 switch (ParamCount
= ShellCommandLineGetCount(Package
)) {
497 // we have insufficient parameters
499 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
);
500 ShellStatus
= SHELL_INVALID_PARAMETER
;
504 // must have valid CWD for single parameter...
506 if (ShellGetCurrentDir(NULL
) == NULL
){
507 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
508 ShellStatus
= SHELL_INVALID_PARAMETER
;
510 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, 1), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
511 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
512 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1));
513 ShellStatus
= SHELL_NOT_FOUND
;
516 // ValidateAndMoveFiles will report errors to the screen itself
518 ShellStatus
= ValidateAndMoveFiles(FileList
, &Response
, ShellGetCurrentDir(NULL
));
524 ///@todo make sure this works with error half way through and continues...
525 for (ParamCount
--, LoopCounter
= 1 ; LoopCounter
< ParamCount
; LoopCounter
++) {
526 if (ShellGetExecutionBreakFlag()) {
529 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, LoopCounter
), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
530 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
531 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, LoopCounter
));
532 ShellStatus
= SHELL_NOT_FOUND
;
535 // ValidateAndMoveFiles will report errors to the screen itself
536 // Only change ShellStatus if it's sucessful
538 if (ShellStatus
== SHELL_SUCCESS
) {
539 ShellStatus
= ValidateAndMoveFiles(FileList
, &Response
, ShellCommandLineGetRawValue(Package
, ParamCount
));
541 ValidateAndMoveFiles(FileList
, &Response
, ShellCommandLineGetRawValue(Package
, ParamCount
));
544 if (FileList
!= NULL
&& !IsListEmpty(&FileList
->Link
)) {
545 Status
= ShellCloseFileMetaArg(&FileList
);
546 if (EFI_ERROR(Status
) && ShellStatus
== SHELL_SUCCESS
) {
547 ShellStatus
= SHELL_ACCESS_DENIED
;
548 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_FILE
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1), ShellStatus
|MAX_BIT
);
553 } // switch on parameter count
555 if (FileList
!= NULL
) {
556 ShellCloseFileMetaArg(&FileList
);
560 // free the command line package
562 ShellCommandLineFreeVarList (Package
);
565 SHELL_FREE_NON_NULL(Response
);
567 if (ShellGetExecutionBreakFlag()) {
568 return (SHELL_ABORTED
);
571 return (ShellStatus
);