]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
efaaeb2d7b3e665f6aef94c140e1fb934eb112d9
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Mv.c
1 /** @file
2 Main file for mv shell level 2 function.
3
4 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2016, 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
10
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.
13
14 **/
15
16 #include "UefiShellLevel2CommandsLib.h"
17
18 /**
19 function to determine if a move is between file systems.
20
21 @param FullName [in] The name of the file to move.
22 @param Cwd [in] The current working directory
23 @param DestPath [in] The target location to move to
24
25 @retval TRUE The move is across file system.
26 @retval FALSE The move is within a file system.
27 **/
28 BOOLEAN
29 IsBetweenFileSystem(
30 IN CONST CHAR16 *FullName,
31 IN CONST CHAR16 *Cwd,
32 IN CONST CHAR16 *DestPath
33 )
34 {
35 CHAR16 *Test;
36 CHAR16 *Test1;
37 UINTN Result;
38
39 Test = StrStr(FullName, L":");
40 if (Test == NULL && Cwd != NULL) {
41 Test = StrStr(Cwd, L":");
42 }
43 Test1 = StrStr(DestPath, L":");
44 if (Test1 == NULL && Cwd != NULL) {
45 Test1 = StrStr(Cwd, L":");
46 }
47 if (Test1 != NULL && Test != NULL) {
48 *Test = CHAR_NULL;
49 *Test1 = CHAR_NULL;
50 Result = StringNoCaseCompare(&FullName, &DestPath);
51 *Test = L':';
52 *Test1 = L':';
53 if (Result != 0) {
54 return (TRUE);
55 }
56 }
57 return (FALSE);
58 }
59
60 /**
61 Function to validate that moving a specific file (FileName) to a specific
62 location (DestPath) is valid.
63
64 This function will verify that the destination is not a subdirectory of
65 FullName, that the Current working Directory is not being moved, and that
66 the directory is not read only.
67
68 if the move is invalid this function will report the error to StdOut.
69
70 @param SourcePath [in] The name of the file to move.
71 @param Cwd [in] The current working directory
72 @param DestPath [in] The target location to move to
73 @param Attribute [in] The Attribute of the file
74 @param DestAttr [in] The Attribute of the destination
75 @param FileStatus [in] The Status of the file when opened
76
77 @retval TRUE The move is valid
78 @retval FALSE The move is not
79 **/
80 BOOLEAN
81 IsValidMove(
82 IN CONST CHAR16 *SourcePath,
83 IN CONST CHAR16 *Cwd,
84 IN CONST CHAR16 *DestPath,
85 IN CONST UINT64 Attribute,
86 IN CONST UINT64 DestAttr,
87 IN CONST EFI_STATUS FileStatus
88 )
89 {
90 CHAR16 *DestPathCopy;
91 CHAR16 *DestPathWalker;
92
93 if (Cwd != NULL && StrCmp(SourcePath, Cwd) == 0) {
94 //
95 // Invalid move
96 //
97 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle);
98 return (FALSE);
99 }
100
101 //
102 // invalid to move read only or move to a read only destination
103 //
104 if (((Attribute & EFI_FILE_READ_ONLY) != 0)
105 || (FileStatus == EFI_WRITE_PROTECTED)
106 || ((DestAttr & EFI_FILE_READ_ONLY) != 0)
107 ) {
108 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle, SourcePath);
109 return (FALSE);
110 }
111
112 DestPathCopy = AllocateCopyPool(StrSize(DestPath), DestPath);
113 if (DestPathCopy == NULL) {
114 return (FALSE);
115 }
116
117 for (DestPathWalker = DestPathCopy; *DestPathWalker == L'\\'; DestPathWalker++) ;
118
119 while(DestPathWalker != NULL && DestPathWalker[StrLen(DestPathWalker)-1] == L'\\') {
120 DestPathWalker[StrLen(DestPathWalker)-1] = CHAR_NULL;
121 }
122
123 ASSERT(DestPathWalker != NULL);
124 ASSERT(SourcePath != NULL);
125
126 //
127 // If they're the same, or if source is "above" dest on file path tree
128 //
129 if ( StringNoCaseCompare (&DestPathWalker, &SourcePath) == 0 ||
130 ((StrStr(DestPathWalker, SourcePath) == DestPathWalker) &&
131 (DestPathWalker[StrLen(SourcePath)] == '\\')
132 )
133 ) {
134 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);
135 FreePool(DestPathCopy);
136 return (FALSE);
137 }
138 FreePool(DestPathCopy);
139
140 return (TRUE);
141 }
142
143 /**
144 Function to take a destination path that might contain wildcards and verify
145 that there is only a single possible target (IE we cant have wildcards that
146 have 2 possible destination).
147
148 if the result is sucessful the caller must free *DestPathPointer.
149
150 @param[in] DestParameter The original path to the destination.
151 @param[in, out] DestPathPointer A pointer to the callee allocated final path.
152 @param[in] Cwd A pointer to the current working directory.
153 @param[in] SingleSource TRUE to have only one source file.
154 @param[in, out] DestAttr A pointer to the destination information attribute.
155
156 @retval SHELL_INVALID_PARAMETER The DestParameter could not be resolved to a location.
157 @retval SHELL_INVALID_PARAMETER The DestParameter could be resolved to more than 1 location.
158 @retval SHELL_INVALID_PARAMETER Cwd is required and is NULL.
159 @retval SHELL_SUCCESS The operation was sucessful.
160 **/
161 SHELL_STATUS
162 GetDestinationLocation(
163 IN CONST CHAR16 *DestParameter,
164 IN OUT CHAR16 **DestPathPointer,
165 IN CONST CHAR16 *Cwd,
166 IN CONST BOOLEAN SingleSource,
167 IN OUT UINT64 *DestAttr
168 )
169 {
170 EFI_SHELL_FILE_INFO *DestList;
171 EFI_SHELL_FILE_INFO *Node;
172 CHAR16 *DestPath;
173 UINTN NewSize;
174 UINTN CurrentSize;
175
176 DestList = NULL;
177 DestPath = NULL;
178
179 ASSERT(DestAttr != NULL);
180
181 if (StrStr(DestParameter, L"\\") == DestParameter) {
182 if (Cwd == NULL) {
183 return SHELL_INVALID_PARAMETER;
184 }
185 DestPath = AllocateZeroPool(StrSize(Cwd));
186 if (DestPath == NULL) {
187 return (SHELL_OUT_OF_RESOURCES);
188 }
189 StrCpyS(DestPath, StrSize(Cwd) / sizeof(CHAR16), Cwd);
190 while (PathRemoveLastItem(DestPath)) ;
191
192 //
193 // Append DestParameter beyond '\' which may be present
194 //
195 CurrentSize = StrSize(DestPath);
196 StrnCatGrow(&DestPath, &CurrentSize, &DestParameter[1], 0);
197
198 *DestPathPointer = DestPath;
199 return (SHELL_SUCCESS);
200 }
201 //
202 // get the destination path
203 //
204 ShellOpenFileMetaArg((CHAR16*)DestParameter, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);
205 if (DestList == NULL || IsListEmpty(&DestList->Link)) {
206 //
207 // Not existing... must be renaming
208 //
209 if (StrStr(DestParameter, L":") == NULL) {
210 if (Cwd == NULL) {
211 ShellCloseFileMetaArg(&DestList);
212 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
213 return (SHELL_INVALID_PARAMETER);
214 }
215 NewSize = StrSize(Cwd);
216 NewSize += StrSize(DestParameter);
217 DestPath = AllocateZeroPool(NewSize);
218 if (DestPath == NULL) {
219 ShellCloseFileMetaArg(&DestList);
220 return (SHELL_OUT_OF_RESOURCES);
221 }
222 StrCpyS(DestPath, NewSize / sizeof(CHAR16), Cwd);
223 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestParameter[0] != L'\\') {
224 StrCatS(DestPath, NewSize / sizeof(CHAR16), L"\\");
225 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestParameter[0] == L'\\') {
226 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
227 }
228 StrCatS(DestPath, NewSize / sizeof(CHAR16), DestParameter);
229 } else {
230 ASSERT(DestPath == NULL);
231 DestPath = StrnCatGrow(&DestPath, NULL, DestParameter, 0);
232 if (DestPath == NULL) {
233 ShellCloseFileMetaArg(&DestList);
234 return (SHELL_OUT_OF_RESOURCES);
235 }
236 }
237 } else {
238 Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link);
239 *DestAttr = Node->Info->Attribute;
240 //
241 // Make sure there is only 1 node in the list.
242 //
243 if (!IsNodeAtEnd(&DestList->Link, &Node->Link)) {
244 ShellCloseFileMetaArg(&DestList);
245 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);
246 return (SHELL_INVALID_PARAMETER);
247 }
248
249 //
250 // If we are a directory or a single file, then one node is fine.
251 //
252 if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS || SingleSource) {
253 DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16));
254 if (DestPath == NULL) {
255 ShellCloseFileMetaArg(&DestList);
256 return (SHELL_OUT_OF_RESOURCES);
257 }
258 StrCpyS(DestPath, (StrSize(Node->FullName)+sizeof(CHAR16)) / sizeof(CHAR16), Node->FullName);
259 StrCatS(DestPath, (StrSize(Node->FullName)+sizeof(CHAR16)) / sizeof(CHAR16), L"\\");
260 } else {
261 //
262 // cant move multiple files onto a single file.
263 //
264 ShellCloseFileMetaArg(&DestList);
265 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, L"mv", DestParameter);
266 return (SHELL_INVALID_PARAMETER);
267 }
268 }
269
270 *DestPathPointer = DestPath;
271 ShellCloseFileMetaArg(&DestList);
272
273 return (SHELL_SUCCESS);
274 }
275
276 /**
277 Function to do a move across file systems.
278
279 @param[in] Node A pointer to the file to be removed.
280 @param[in] DestPath A pointer to the destination file path.
281 @param[out] Resp A pointer to response from question. Pass back on looped calling
282
283 @retval SHELL_SUCCESS The source file was moved to the destination.
284 **/
285 EFI_STATUS
286 MoveBetweenFileSystems(
287 IN EFI_SHELL_FILE_INFO *Node,
288 IN CONST CHAR16 *DestPath,
289 OUT VOID **Resp
290 )
291 {
292 SHELL_STATUS ShellStatus;
293
294 //
295 // First we copy the file
296 //
297 ShellStatus = CopySingleFile (Node->FullName, DestPath, Resp, TRUE, L"mv");
298
299 //
300 // Check our result
301 //
302 if (ShellStatus == SHELL_SUCCESS) {
303 //
304 // The copy was successful. delete the source file.
305 //
306 CascadeDelete(Node, TRUE);
307 Node->Handle = NULL;
308 } else if (ShellStatus == SHELL_ABORTED) {
309 return EFI_ABORTED;
310 } else if (ShellStatus == SHELL_ACCESS_DENIED) {
311 return EFI_ACCESS_DENIED;
312 } else if (ShellStatus == SHELL_VOLUME_FULL) {
313 return EFI_VOLUME_FULL;
314 } else {
315 return EFI_UNSUPPORTED;
316 }
317
318 return (EFI_SUCCESS);
319 }
320
321 /**
322 Function to take the destination path and target file name to generate the full destination path.
323
324 @param[in] DestPath A pointer to the destination file path string.
325 @param[out] FullDestPath A pointer to the full destination path string.
326 @param[in] FileName Name string of the targe file.
327
328 @retval SHELL_SUCCESS the files were all moved.
329 @retval SHELL_INVALID_PARAMETER a parameter was invalid
330 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
331 **/
332 EFI_STATUS
333 CreateFullDestPath(
334 IN CONST CHAR16 **DestPath,
335 OUT CHAR16 **FullDestPath,
336 IN CONST CHAR16 *FileName
337 )
338 {
339 UINTN Size;
340 if (FullDestPath == NULL || FileName == NULL || DestPath == NULL || *DestPath == NULL){
341 return (EFI_INVALID_PARAMETER);
342 }
343
344 Size = StrSize(*DestPath) + StrSize(FileName);
345
346 *FullDestPath = AllocateZeroPool(Size);
347 if (*FullDestPath == NULL){
348 return (EFI_OUT_OF_RESOURCES);
349 }
350
351 StrCpyS(*FullDestPath, Size / sizeof(CHAR16), *DestPath);
352 if ((*FullDestPath)[StrLen(*FullDestPath)-1] != L'\\' && FileName[0] != L'\\') {
353 StrCatS(*FullDestPath, Size / sizeof(CHAR16), L"\\");
354 }
355 StrCatS(*FullDestPath, Size / sizeof(CHAR16), FileName);
356
357 return (EFI_SUCCESS);
358 }
359
360 /**
361 Function to do a move within a file system.
362
363 @param[in] Node A pointer to the file to be removed.
364 @param[in] DestPath A pointer to the destination file path.
365 @param[out] Resp A pointer to response from question. Pass back on looped calling.
366
367 @retval SHELL_SUCCESS The source file was moved to the destination.
368 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
369 **/
370 EFI_STATUS
371 MoveWithinFileSystems(
372 IN EFI_SHELL_FILE_INFO *Node,
373 IN CHAR16 *DestPath,
374 OUT VOID **Resp
375 )
376 {
377 EFI_FILE_INFO *NewFileInfo;
378 CHAR16 *TempLocation;
379 UINTN NewSize;
380 UINTN Length;
381 EFI_STATUS Status;
382
383 //
384 // Chop off map info from DestPath
385 //
386 if ((TempLocation = StrStr(DestPath, L":")) != NULL) {
387 CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1));
388 }
389
390 //
391 // construct the new file info block
392 //
393 NewSize = StrSize(DestPath);
394 NewSize += StrSize(Node->FileName) + SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);
395 NewFileInfo = AllocateZeroPool(NewSize);
396 if (NewFileInfo == NULL) {
397 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);
398 Status = EFI_OUT_OF_RESOURCES;
399 } else {
400 CopyMem(NewFileInfo, Node->Info, SIZE_OF_EFI_FILE_INFO);
401 if (DestPath[0] != L'\\') {
402 StrCpyS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), L"\\");
403 StrCatS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), DestPath);
404 } else {
405 StrCpyS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), DestPath);
406 }
407 Length = StrLen(NewFileInfo->FileName);
408 if (Length > 0) {
409 Length--;
410 }
411 if (NewFileInfo->FileName[Length] == L'\\') {
412 if (Node->FileName[0] == L'\\') {
413 //
414 // Don't allow for double slashes. Eliminate one of them.
415 //
416 NewFileInfo->FileName[Length] = CHAR_NULL;
417 }
418 StrCatS(NewFileInfo->FileName, (NewSize - SIZE_OF_EFI_FILE_INFO) / sizeof(CHAR16), Node->FileName);
419 }
420 NewFileInfo->Size = SIZE_OF_EFI_FILE_INFO + StrSize(NewFileInfo->FileName);
421
422 //
423 // Perform the move operation
424 //
425 Status = ShellSetFileInfo(Node->Handle, NewFileInfo);
426
427 //
428 // Free the info object we used...
429 //
430 FreePool(NewFileInfo);
431 }
432
433 return (Status);
434 }
435 /**
436 function to take a list of files to move and a destination location and do
437 the verification and moving of those files to that location. This function
438 will report any errors to the user and continue to move the rest of the files.
439
440 @param[in] FileList A LIST_ENTRY* based list of files to move
441 @param[out] Resp pointer to response from question. Pass back on looped calling
442 @param[in] DestParameter the originally specified destination location
443
444 @retval SHELL_SUCCESS the files were all moved.
445 @retval SHELL_INVALID_PARAMETER a parameter was invalid
446 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
447 @retval SHELL_WRITE_PROTECTED the destination was write protected
448 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
449 **/
450 SHELL_STATUS
451 ValidateAndMoveFiles(
452 IN EFI_SHELL_FILE_INFO *FileList,
453 OUT VOID **Resp,
454 IN CONST CHAR16 *DestParameter
455 )
456 {
457 EFI_STATUS Status;
458 CHAR16 *HiiOutput;
459 CHAR16 *HiiResultOk;
460 CHAR16 *DestPath;
461 CHAR16 *FullDestPath;
462 CONST CHAR16 *Cwd;
463 CHAR16 *FullCwd;
464 SHELL_STATUS ShellStatus;
465 EFI_SHELL_FILE_INFO *Node;
466 VOID *Response;
467 UINT64 Attr;
468 CHAR16 *CleanFilePathStr;
469
470 ASSERT(FileList != NULL);
471 ASSERT(DestParameter != NULL);
472
473 DestPath = NULL;
474 FullDestPath = NULL;
475 Cwd = ShellGetCurrentDir(NULL);
476 Response = *Resp;
477 Attr = 0;
478 CleanFilePathStr = NULL;
479 FullCwd = NULL;
480
481 if (Cwd != NULL) {
482 FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16));
483 if (FullCwd == NULL) {
484 return SHELL_OUT_OF_RESOURCES;
485 } else {
486 StrCpyS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, Cwd);
487 StrCatS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, L"\\");
488 }
489 }
490
491 Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr);
492 if (EFI_ERROR (Status)) {
493 SHELL_FREE_NON_NULL(FullCwd);
494 if (Status == EFI_OUT_OF_RESOURCES) {
495 return SHELL_OUT_OF_RESOURCES;
496 } else {
497 return SHELL_INVALID_PARAMETER;
498 }
499 }
500
501 ASSERT (CleanFilePathStr != NULL);
502
503 //
504 // Get and validate the destination location
505 //
506 ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, FullCwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr);
507 FreePool (CleanFilePathStr);
508
509 if (ShellStatus != SHELL_SUCCESS) {
510 SHELL_FREE_NON_NULL (FullCwd);
511 return (ShellStatus);
512 }
513 DestPath = PathCleanUpDirectories(DestPath);
514 if (DestPath == NULL) {
515 FreePool (FullCwd);
516 return (SHELL_OUT_OF_RESOURCES);
517 }
518
519 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);
520 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
521 if (HiiOutput == NULL || HiiResultOk == NULL) {
522 SHELL_FREE_NON_NULL(DestPath);
523 SHELL_FREE_NON_NULL(HiiOutput);
524 SHELL_FREE_NON_NULL(HiiResultOk);
525 SHELL_FREE_NON_NULL(FullCwd);
526 return (SHELL_OUT_OF_RESOURCES);
527 }
528
529 //
530 // Go through the list of files and directories to move...
531 //
532 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
533 ; !IsNull(&FileList->Link, &Node->Link)
534 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
535 ){
536 if (ShellGetExecutionBreakFlag()) {
537 break;
538 }
539
540 //
541 // These should never be NULL
542 //
543 ASSERT(Node->FileName != NULL);
544 ASSERT(Node->FullName != NULL);
545 ASSERT(Node->Info != NULL);
546
547 //
548 // skip the directory traversing stuff...
549 //
550 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
551 continue;
552 }
553
554 SHELL_FREE_NON_NULL(FullDestPath);
555 FullDestPath = NULL;
556 if (ShellIsDirectory(DestPath)==EFI_SUCCESS) {
557 CreateFullDestPath((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName);
558 }
559
560 //
561 // Validate that the move is valid
562 //
563 if (!IsValidMove(Node->FullName, FullCwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) {
564 ShellStatus = SHELL_INVALID_PARAMETER;
565 continue;
566 }
567
568 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, FullDestPath!=NULL? FullDestPath:DestPath);
569
570 //
571 // See if destination exists
572 //
573 if (!EFI_ERROR(ShellFileExists(FullDestPath!=NULL? FullDestPath:DestPath))) {
574 if (Response == NULL) {
575 ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response);
576 }
577 switch (*(SHELL_PROMPT_RESPONSE*)Response) {
578 case ShellPromptResponseNo:
579 FreePool(Response);
580 Response = NULL;
581 continue;
582 case ShellPromptResponseCancel:
583 *Resp = Response;
584 //
585 // indicate to stop everything
586 //
587 SHELL_FREE_NON_NULL(FullCwd);
588 return (SHELL_ABORTED);
589 case ShellPromptResponseAll:
590 *Resp = Response;
591 break;
592 case ShellPromptResponseYes:
593 FreePool(Response);
594 Response = NULL;
595 break;
596 default:
597 FreePool(Response);
598 SHELL_FREE_NON_NULL(FullCwd);
599 return SHELL_ABORTED;
600 }
601 Status = ShellDeleteFileByName(FullDestPath!=NULL? FullDestPath:DestPath);
602 }
603
604 if (IsBetweenFileSystem(Node->FullName, FullCwd, DestPath)) {
605 while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen(DestPath) - 1] == L'\\') {
606 DestPath[StrLen(DestPath) - 1] = CHAR_NULL;
607 }
608 Status = MoveBetweenFileSystems(Node, FullDestPath!=NULL? FullDestPath:DestPath, &Response);
609 } else {
610 Status = MoveWithinFileSystems(Node, DestPath, &Response);
611 //
612 // Display error status
613 //
614 if (EFI_ERROR(Status)) {
615 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"mv", Status);
616 }
617 }
618
619 //
620 // Check our result
621 //
622 if (EFI_ERROR(Status)) {
623 ShellStatus = SHELL_INVALID_PARAMETER;
624 if (Status == EFI_SECURITY_VIOLATION) {
625 ShellStatus = SHELL_SECURITY_VIOLATION;
626 } else if (Status == EFI_WRITE_PROTECTED) {
627 ShellStatus = SHELL_WRITE_PROTECTED;
628 } else if (Status == EFI_OUT_OF_RESOURCES) {
629 ShellStatus = SHELL_OUT_OF_RESOURCES;
630 } else if (Status == EFI_DEVICE_ERROR) {
631 ShellStatus = SHELL_DEVICE_ERROR;
632 } else if (Status == EFI_ACCESS_DENIED) {
633 ShellStatus = SHELL_ACCESS_DENIED;
634 }
635 } else {
636 ShellPrintEx(-1, -1, L"%s", HiiResultOk);
637 }
638
639 } // main for loop
640
641 SHELL_FREE_NON_NULL(FullDestPath);
642 SHELL_FREE_NON_NULL(DestPath);
643 SHELL_FREE_NON_NULL(HiiOutput);
644 SHELL_FREE_NON_NULL(HiiResultOk);
645 SHELL_FREE_NON_NULL(FullCwd);
646 return (ShellStatus);
647 }
648
649 /**
650 Function for 'mv' command.
651
652 @param[in] ImageHandle Handle to the Image (NULL if Internal).
653 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
654 **/
655 SHELL_STATUS
656 EFIAPI
657 ShellCommandRunMv (
658 IN EFI_HANDLE ImageHandle,
659 IN EFI_SYSTEM_TABLE *SystemTable
660 )
661 {
662 EFI_STATUS Status;
663 LIST_ENTRY *Package;
664 CHAR16 *ProblemParam;
665 CHAR16 *Cwd;
666 UINTN CwdSize;
667 SHELL_STATUS ShellStatus;
668 UINTN ParamCount;
669 UINTN LoopCounter;
670 EFI_SHELL_FILE_INFO *FileList;
671 VOID *Response;
672
673 ProblemParam = NULL;
674 ShellStatus = SHELL_SUCCESS;
675 ParamCount = 0;
676 FileList = NULL;
677 Response = NULL;
678
679 //
680 // initialize the shell lib (we must be in non-auto-init...)
681 //
682 Status = ShellInitialize();
683 ASSERT_EFI_ERROR(Status);
684
685 //
686 // parse the command line
687 //
688 Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);
689 if (EFI_ERROR(Status)) {
690 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
691 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"mv", ProblemParam);
692 FreePool(ProblemParam);
693 ShellStatus = SHELL_INVALID_PARAMETER;
694 } else {
695 ASSERT(FALSE);
696 }
697 } else {
698 //
699 // check for "-?"
700 //
701 if (ShellCommandLineGetFlag(Package, L"-?")) {
702 ASSERT(FALSE);
703 }
704
705 switch (ParamCount = ShellCommandLineGetCount(Package)) {
706 case 0:
707 case 1:
708 //
709 // we have insufficient parameters
710 //
711 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mv");
712 ShellStatus = SHELL_INVALID_PARAMETER;
713 break;
714 case 2:
715 //
716 // must have valid CWD for single parameter...
717 //
718 if (ShellGetCurrentDir(NULL) == NULL){
719 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"mv");
720 ShellStatus = SHELL_INVALID_PARAMETER;
721 } else {
722 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
723 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
724 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1));
725 ShellStatus = SHELL_NOT_FOUND;
726 } else {
727 //
728 // ValidateAndMoveFiles will report errors to the screen itself
729 //
730 CwdSize = StrSize(ShellGetCurrentDir(NULL)) + sizeof(CHAR16);
731 Cwd = AllocateZeroPool(CwdSize);
732 if (Cwd == NULL) {
733 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"mv");
734 ShellStatus = SHELL_OUT_OF_RESOURCES;
735 } else {
736 StrCpyS (Cwd, CwdSize / sizeof (CHAR16), ShellGetCurrentDir (NULL));
737 StrCatS (Cwd, CwdSize / sizeof (CHAR16), L"\\");
738 ShellStatus = ValidateAndMoveFiles (FileList, &Response, Cwd);
739 FreePool (Cwd);
740 }
741 }
742 }
743
744 break;
745 default:
746 ///@todo make sure this works with error half way through and continues...
747 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount ; LoopCounter++) {
748 if (ShellGetExecutionBreakFlag()) {
749 break;
750 }
751 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
752 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
753 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, LoopCounter));
754 ShellStatus = SHELL_NOT_FOUND;
755 } else {
756 //
757 // ValidateAndMoveFiles will report errors to the screen itself
758 // Only change ShellStatus if it's sucessful
759 //
760 if (ShellStatus == SHELL_SUCCESS) {
761 ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));
762 } else {
763 ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount));
764 }
765 }
766 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
767 Status = ShellCloseFileMetaArg(&FileList);
768 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
769 ShellStatus = SHELL_ACCESS_DENIED;
770 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);
771 }
772 }
773 }
774 break;
775 } // switch on parameter count
776
777 if (FileList != NULL) {
778 ShellCloseFileMetaArg(&FileList);
779 }
780
781 //
782 // free the command line package
783 //
784 ShellCommandLineFreeVarList (Package);
785 }
786
787 SHELL_FREE_NON_NULL(Response);
788
789 if (ShellGetExecutionBreakFlag()) {
790 return (SHELL_ABORTED);
791 }
792
793 return (ShellStatus);
794 }