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 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 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 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 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 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 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 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 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 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