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