VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c@ 109091

Last change on this file since 109091 was 105670, checked in by vboxsync, 9 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette