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