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 SHELL_INVALID_PARAMETER The DestDir could not be resolved to a location.
124 @retval SHELL_INVALID_PARAMETER The DestDir could be resolved to more than 1 location.
125 @retval SHELL_INVALID_PARAMETER Cwd is required and is NULL.
126 @retval SHELL_SUCCESS The operation was sucessful.
130 GetDestinationLocation(
131 IN CONST CHAR16
*DestDir
,
132 IN OUT CHAR16
**DestPathPointer
,
136 EFI_SHELL_FILE_INFO
*DestList
;
137 EFI_SHELL_FILE_INFO
*Node
;
140 CHAR16
*TempLocation
;
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
)) ;
156 *DestPathPointer
= DestPath
;
157 return (SHELL_SUCCESS
);
160 // get the destination path
162 Status
= ShellOpenFileMetaArg((CHAR16
*)DestDir
, EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
|EFI_FILE_MODE_CREATE
, &DestList
);
163 if (DestList
== NULL
|| IsListEmpty(&DestList
->Link
)) {
165 // Not existing... must be renaming
167 if ((TempLocation
= StrStr(DestDir
, L
":")) == NULL
) {
169 ShellCloseFileMetaArg(&DestList
);
170 return (SHELL_INVALID_PARAMETER
);
172 NewSize
= StrSize(Cwd
);
173 NewSize
+= StrSize(DestDir
);
174 DestPath
= AllocateZeroPool(NewSize
);
175 if (DestPath
== NULL
) {
176 ShellCloseFileMetaArg(&DestList
);
177 return (SHELL_OUT_OF_RESOURCES
);
179 StrCpy(DestPath
, Cwd
);
180 if (DestPath
[StrLen(DestPath
)-1] != L
'\\' && DestDir
[0] != L
'\\') {
181 StrCat(DestPath
, L
"\\");
182 } else if (DestPath
[StrLen(DestPath
)-1] == L
'\\' && DestDir
[0] == L
'\\') {
183 ((CHAR16
*)DestPath
)[StrLen(DestPath
)-1] = CHAR_NULL
;
185 StrCat(DestPath
, DestDir
);
187 ASSERT(DestPath
== NULL
);
188 DestPath
= StrnCatGrow(&DestPath
, NULL
, DestDir
, 0);
189 if (DestPath
== NULL
) {
190 ShellCloseFileMetaArg(&DestList
);
191 return (SHELL_OUT_OF_RESOURCES
);
195 Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&DestList
->Link
);
197 // Make sure there is only 1 node in the list.
199 if (!IsNodeAtEnd(&DestList
->Link
, &Node
->Link
)) {
200 ShellCloseFileMetaArg(&DestList
);
201 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_MARG_ERROR
), gShellLevel2HiiHandle
, DestDir
);
202 return (SHELL_INVALID_PARAMETER
);
204 if (ShellIsDirectory(Node
->FullName
)==EFI_SUCCESS
) {
205 DestPath
= AllocateZeroPool(StrSize(Node
->FullName
)+sizeof(CHAR16
));
206 if (DestPath
== NULL
) {
207 ShellCloseFileMetaArg(&DestList
);
208 return (SHELL_OUT_OF_RESOURCES
);
210 StrCpy(DestPath
, Node
->FullName
);
211 StrCat(DestPath
, L
"\\");
214 // cant move onto another file.
216 ShellCloseFileMetaArg(&DestList
);
217 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_ERROR
), gShellLevel2HiiHandle
, DestDir
);
218 return (SHELL_INVALID_PARAMETER
);
222 *DestPathPointer
= DestPath
;
223 ShellCloseFileMetaArg(&DestList
);
225 return (SHELL_SUCCESS
);
229 function to take a list of files to move and a destination location and do
230 the verification and moving of those files to that location. This function
231 will report any errors to the user and continue to move the rest of the files.
233 @param[in] FileList A LIST_ENTRY* based list of files to move
234 @param[out] Resp pointer to response from question. Pass back on looped calling
235 @param[in] DestDir the destination location
237 @retval SHELL_SUCCESS the files were all moved.
238 @retval SHELL_INVALID_PARAMETER a parameter was invalid
239 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
240 @retval SHELL_WRITE_PROTECTED the destination was write protected
241 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
245 ValidateAndMoveFiles(
246 IN CONST EFI_SHELL_FILE_INFO
*FileList
,
248 IN CONST CHAR16
*DestDir
256 SHELL_STATUS ShellStatus
;
257 CONST EFI_SHELL_FILE_INFO
*Node
;
258 EFI_FILE_INFO
*NewFileInfo
;
259 CHAR16
*TempLocation
;
263 SHELL_FILE_HANDLE DestHandle
;
265 ASSERT(FileList
!= NULL
);
266 ASSERT(DestDir
!= NULL
);
269 Cwd
= ShellGetCurrentDir(NULL
);
273 // Get and validate the destination location
275 ShellStatus
= GetDestinationLocation(DestDir
, &DestPath
, Cwd
);
276 if (ShellStatus
!= SHELL_SUCCESS
) {
277 return (ShellStatus
);
279 DestPath
= PathCleanUpDirectories(DestPath
);
281 HiiOutput
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_MV_OUTPUT
), NULL
);
282 HiiResultOk
= HiiGetString (gShellLevel2HiiHandle
, STRING_TOKEN (STR_GEN_RES_OK
), NULL
);
283 ASSERT (DestPath
!= NULL
);
284 ASSERT (HiiResultOk
!= NULL
);
285 ASSERT (HiiOutput
!= NULL
);
286 // ASSERT (Cwd != NULL);
289 // Go through the list of files and directories to move...
291 for (Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
292 ; !IsNull(&FileList
->Link
, &Node
->Link
)
293 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
295 if (ShellGetExecutionBreakFlag()) {
298 ASSERT(Node
->FileName
!= NULL
);
299 ASSERT(Node
->FullName
!= NULL
);
302 // skip the directory traversing stuff...
304 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
309 // Validate that the move is valid
311 if (!IsValidMove(Node
->FullName
, Cwd
, DestPath
, Node
->Info
->Attribute
)) {
312 ShellStatus
= SHELL_INVALID_PARAMETER
;
317 // Chop off map info from "DestPath"
319 if ((TempLocation
= StrStr(DestPath
, L
":")) != NULL
) {
320 CopyMem(DestPath
, TempLocation
+1, StrSize(TempLocation
+1));
324 // construct the new file info block
326 NewSize
= StrSize(DestPath
);
327 NewSize
+= StrSize(Node
->FileName
) + SIZE_OF_EFI_FILE_INFO
+ sizeof(CHAR16
);
328 NewFileInfo
= AllocateZeroPool(NewSize
);
329 if (NewFileInfo
== NULL
) {
330 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_MEM
), gShellLevel2HiiHandle
);
331 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
333 CopyMem(NewFileInfo
, Node
->Info
, SIZE_OF_EFI_FILE_INFO
);
334 if (DestPath
[0] != L
'\\') {
335 StrCpy(NewFileInfo
->FileName
, L
"\\");
336 StrCat(NewFileInfo
->FileName
, DestPath
);
338 StrCpy(NewFileInfo
->FileName
, DestPath
);
340 Length
= StrLen(NewFileInfo
->FileName
);
344 if (NewFileInfo
->FileName
[Length
] == L
'\\') {
345 if (Node
->FileName
[0] == L
'\\') {
347 // Don't allow for double slashes. Eliminate one of them.
349 NewFileInfo
->FileName
[Length
] = CHAR_NULL
;
351 StrCat(NewFileInfo
->FileName
, Node
->FileName
);
353 NewFileInfo
->Size
= SIZE_OF_EFI_FILE_INFO
+ StrSize(NewFileInfo
->FileName
);
354 ShellPrintEx(-1, -1, HiiOutput
, Node
->FullName
, NewFileInfo
->FileName
);
356 if (!EFI_ERROR(ShellFileExists(NewFileInfo
->FileName
))) {
357 if (Response
== NULL
) {
358 ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel
, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR
), gShellLevel2HiiHandle
, &Response
);
360 switch (*(SHELL_PROMPT_RESPONSE
*)Response
) {
361 case ShellPromptResponseNo
:
362 FreePool(NewFileInfo
);
364 case ShellPromptResponseCancel
:
367 // indicate to stop everything
369 FreePool(NewFileInfo
);
372 FreePool(HiiResultOk
);
373 return (SHELL_ABORTED
);
374 case ShellPromptResponseAll
:
377 case ShellPromptResponseYes
:
382 FreePool(NewFileInfo
);
385 FreePool(HiiResultOk
);
386 return SHELL_ABORTED
;
388 Status
= ShellOpenFileByName(NewFileInfo
->FileName
, &DestHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
, 0);
389 ShellDeleteFile(&DestHandle
);
394 // Perform the move operation
396 Status
= ShellSetFileInfo(Node
->Handle
, NewFileInfo
);
399 // Free the info object we used...
401 FreePool(NewFileInfo
);
406 if (EFI_ERROR(Status
)) {
407 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_UK
), gShellLevel2HiiHandle
, Status
);
413 ShellStatus
= SHELL_INVALID_PARAMETER
;
414 case EFI_SECURITY_VIOLATION
:
415 ShellStatus
= SHELL_SECURITY_VIOLATION
;
416 case EFI_WRITE_PROTECTED
:
417 ShellStatus
= SHELL_WRITE_PROTECTED
;
418 case EFI_OUT_OF_RESOURCES
:
419 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
420 case EFI_DEVICE_ERROR
:
421 ShellStatus
= SHELL_DEVICE_ERROR
;
422 case EFI_ACCESS_DENIED
:
423 ShellStatus
= SHELL_ACCESS_DENIED
;
426 ShellPrintEx(-1, -1, L
"%s", HiiResultOk
);
433 FreePool(HiiResultOk
);
434 return (ShellStatus
);
438 Function for 'mv' command.
440 @param[in] ImageHandle Handle to the Image (NULL if Internal).
441 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
446 IN EFI_HANDLE ImageHandle
,
447 IN EFI_SYSTEM_TABLE
*SystemTable
452 CHAR16
*ProblemParam
;
453 SHELL_STATUS ShellStatus
;
456 EFI_SHELL_FILE_INFO
*FileList
;
460 ShellStatus
= SHELL_SUCCESS
;
466 // initialize the shell lib (we must be in non-auto-init...)
468 Status
= ShellInitialize();
469 ASSERT_EFI_ERROR(Status
);
472 // parse the command line
474 Status
= ShellCommandLineParse (EmptyParamList
, &Package
, &ProblemParam
, TRUE
);
475 if (EFI_ERROR(Status
)) {
476 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
477 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, ProblemParam
);
478 FreePool(ProblemParam
);
479 ShellStatus
= SHELL_INVALID_PARAMETER
;
487 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
491 switch (ParamCount
= ShellCommandLineGetCount(Package
)) {
495 // we have insufficient parameters
497 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
);
498 ShellStatus
= SHELL_INVALID_PARAMETER
;
502 // must have valid CWD for single parameter...
504 if (ShellGetCurrentDir(NULL
) == NULL
){
505 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
506 ShellStatus
= SHELL_INVALID_PARAMETER
;
508 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, 1), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
509 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
510 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1));
511 ShellStatus
= SHELL_NOT_FOUND
;
514 // ValidateAndMoveFiles will report errors to the screen itself
516 ShellStatus
= ValidateAndMoveFiles(FileList
, &Response
, ShellGetCurrentDir(NULL
));
522 ///@todo make sure this works with error half way through and continues...
523 for (ParamCount
--, LoopCounter
= 1 ; LoopCounter
< ParamCount
; LoopCounter
++) {
524 if (ShellGetExecutionBreakFlag()) {
527 Status
= ShellOpenFileMetaArg((CHAR16
*)ShellCommandLineGetRawValue(Package
, LoopCounter
), EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
528 if (FileList
== NULL
|| IsListEmpty(&FileList
->Link
) || EFI_ERROR(Status
)) {
529 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, LoopCounter
));
530 ShellStatus
= SHELL_NOT_FOUND
;
533 // ValidateAndMoveFiles will report errors to the screen itself
534 // Only change ShellStatus if it's sucessful
536 if (ShellStatus
== SHELL_SUCCESS
) {
537 ShellStatus
= ValidateAndMoveFiles(FileList
, &Response
, ShellCommandLineGetRawValue(Package
, ParamCount
));
539 ValidateAndMoveFiles(FileList
, &Response
, ShellCommandLineGetRawValue(Package
, ParamCount
));
542 if (FileList
!= NULL
&& !IsListEmpty(&FileList
->Link
)) {
543 Status
= ShellCloseFileMetaArg(&FileList
);
544 if (EFI_ERROR(Status
) && ShellStatus
== SHELL_SUCCESS
) {
545 ShellStatus
= SHELL_ACCESS_DENIED
;
546 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ERR_FILE
), gShellLevel2HiiHandle
, ShellCommandLineGetRawValue(Package
, 1), ShellStatus
|MAX_BIT
);
551 } // switch on parameter count
553 if (FileList
!= NULL
) {
554 ShellCloseFileMetaArg(&FileList
);
558 // free the command line package
560 ShellCommandLineFreeVarList (Package
);
563 SHELL_FREE_NON_NULL(Response
);
565 if (ShellGetExecutionBreakFlag()) {
566 return (SHELL_ABORTED
);
569 return (ShellStatus
);