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 487 FullCwd = AllocateZeroPool(StrSize(Cwd) + sizeof(CHAR16)); 488 if (FullCwd == NULL) { 489 return SHELL_OUT_OF_RESOURCES; 490 } else { 491 StrCpyS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, Cwd); 492 StrCatS(FullCwd, StrSize(Cwd)/sizeof(CHAR16)+1, L"\\"); 493 } 494 495 Status = ShellLevel2StripQuotes (DestParameter, &CleanFilePathStr); 496 if (EFI_ERROR (Status)) { 497 FreePool (FullCwd); 498 if (Status == EFI_OUT_OF_RESOURCES) { 499 return SHELL_OUT_OF_RESOURCES; 500 } else { 501 return SHELL_INVALID_PARAMETER; 502 } 503 } 504 505 ASSERT (CleanFilePathStr != NULL); 506 507 // 508 // Get and validate the destination location 509 // 510 ShellStatus = GetDestinationLocation(CleanFilePathStr, &DestPath, FullCwd, (BOOLEAN)(FileList->Link.ForwardLink == FileList->Link.BackLink), &Attr); 511 FreePool (CleanFilePathStr); 512 513 if (ShellStatus != SHELL_SUCCESS) { 514 FreePool (FullCwd); 515 return (ShellStatus); 516 } 517 DestPath = PathCleanUpDirectories(DestPath); 518 if (DestPath == NULL) { 519 FreePool (FullCwd); 520 return (SHELL_OUT_OF_RESOURCES); 521 } 522 523 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL); 524 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL); 525 if (HiiOutput == NULL || HiiResultOk == NULL) { 526 SHELL_FREE_NON_NULL(DestPath); 527 SHELL_FREE_NON_NULL(HiiOutput); 528 SHELL_FREE_NON_NULL(HiiResultOk); 529 FreePool (FullCwd); 530 return (SHELL_OUT_OF_RESOURCES); 531 } 532 533 // 534 // Go through the list of files and directories to move... 535 // 536 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) 537 ; !IsNull(&FileList->Link, &Node->Link) 538 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) 539 ){ 540 if (ShellGetExecutionBreakFlag()) { 541 break; 542 } 543 544 // 545 // These should never be NULL 546 // 547 ASSERT(Node->FileName != NULL); 548 ASSERT(Node->FullName != NULL); 549 ASSERT(Node->Info != NULL); 550 551 // 552 // skip the directory traversing stuff... 553 // 554 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { 555 continue; 556 } 557 558 SHELL_FREE_NON_NULL(FullDestPath); 559 FullDestPath = NULL; 560 if (ShellIsDirectory(DestPath)==EFI_SUCCESS) { 561 CreateFullDestPath((CONST CHAR16 **)&DestPath, &FullDestPath, Node->FileName); 562 } 563 564 // 565 // Validate that the move is valid 566 // 567 if (!IsValidMove(Node->FullName, FullCwd, FullDestPath!=NULL? FullDestPath:DestPath, Node->Info->Attribute, Attr, Node->Status)) { 568 ShellStatus = SHELL_INVALID_PARAMETER; 569 continue; 570 } 571 572 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, FullDestPath!=NULL? FullDestPath:DestPath); 573 574 // 575 // See if destination exists 576 // 577 if (!EFI_ERROR(ShellFileExists(FullDestPath!=NULL? FullDestPath:DestPath))) { 578 if (Response == NULL) { 579 ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response); 580 } 581 switch (*(SHELL_PROMPT_RESPONSE*)Response) { 582 case ShellPromptResponseNo: 583 FreePool(Response); 584 Response = NULL; 585 continue; 586 case ShellPromptResponseCancel: 587 *Resp = Response; 588 // 589 // indicate to stop everything 590 // 591 FreePool(FullCwd); 592 return (SHELL_ABORTED); 593 case ShellPromptResponseAll: 594 *Resp = Response; 595 break; 596 case ShellPromptResponseYes: 597 FreePool(Response); 598 Response = NULL; 599 break; 600 default: 601 FreePool(Response); 602 FreePool(FullCwd); 603 return SHELL_ABORTED; 604 } 605 Status = ShellDeleteFileByName(FullDestPath!=NULL? FullDestPath:DestPath); 606 } 607 608 if (IsBetweenFileSystem(Node->FullName, FullCwd, DestPath)) { 609 while (FullDestPath == NULL && DestPath != NULL && DestPath[0] != CHAR_NULL && DestPath[StrLen(DestPath) - 1] == L'\\') { 610 DestPath[StrLen(DestPath) - 1] = CHAR_NULL; 611 } 612 Status = MoveBetweenFileSystems(Node, FullDestPath!=NULL? FullDestPath:DestPath, &Response); 613 } else { 614 Status = MoveWithinFileSystems(Node, DestPath, &Response); 615 // 616 // Display error status 617 // 618 if (EFI_ERROR(Status)) { 619 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"mv", Status); 620 } 621 } 622 623 // 624 // Check our result 625 // 626 if (EFI_ERROR(Status)) { 627 ShellStatus = SHELL_INVALID_PARAMETER; 628 if (Status == EFI_SECURITY_VIOLATION) { 629 ShellStatus = SHELL_SECURITY_VIOLATION; 630 } else if (Status == EFI_WRITE_PROTECTED) { 631 ShellStatus = SHELL_WRITE_PROTECTED; 632 } else if (Status == EFI_OUT_OF_RESOURCES) { 633 ShellStatus = SHELL_OUT_OF_RESOURCES; 634 } else if (Status == EFI_DEVICE_ERROR) { 635 ShellStatus = SHELL_DEVICE_ERROR; 636 } else if (Status == EFI_ACCESS_DENIED) { 637 ShellStatus = SHELL_ACCESS_DENIED; 638 } 639 } else { 640 ShellPrintEx(-1, -1, L"%s", HiiResultOk); 641 } 642 643 } // main for loop 644 645 SHELL_FREE_NON_NULL(FullDestPath); 646 SHELL_FREE_NON_NULL(DestPath); 647 SHELL_FREE_NON_NULL(HiiOutput); 648 SHELL_FREE_NON_NULL(HiiResultOk); 649 FreePool (FullCwd); 650 return (ShellStatus); 651 } 652 653 /** 654 Function for 'mv' command. 655 656 @param[in] ImageHandle Handle to the Image (NULL if Internal). 657 @param[in] SystemTable Pointer to the System Table (NULL if Internal). 658 **/ 659 SHELL_STATUS 660 EFIAPI 661 ShellCommandRunMv ( 662 IN EFI_HANDLE ImageHandle, 663 IN EFI_SYSTEM_TABLE *SystemTable 664 ) 665 { 666 EFI_STATUS Status; 667 LIST_ENTRY *Package; 668 CHAR16 *ProblemParam; 669 CHAR16 *Cwd; 670 UINTN CwdSize; 671 SHELL_STATUS ShellStatus; 672 UINTN ParamCount; 673 UINTN LoopCounter; 674 EFI_SHELL_FILE_INFO *FileList; 675 VOID *Response; 676 677 ProblemParam = NULL; 678 ShellStatus = SHELL_SUCCESS; 679 ParamCount = 0; 680 FileList = NULL; 681 Response = NULL; 682 683 // 684 // initialize the shell lib (we must be in non-auto-init...) 685 // 686 Status = ShellInitialize(); 687 ASSERT_EFI_ERROR(Status); 688 689 // 690 // parse the command line 691 // 692 Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE); 693 if (EFI_ERROR(Status)) { 694 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { 695 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"mv", ProblemParam); 696 FreePool(ProblemParam); 697 ShellStatus = SHELL_INVALID_PARAMETER; 698 } else { 699 ASSERT(FALSE); 700 } 701 } else { 702 // 703 // check for "-?" 704 // 705 if (ShellCommandLineGetFlag(Package, L"-?")) { 706 ASSERT(FALSE); 707 } 708 709 switch (ParamCount = ShellCommandLineGetCount(Package)) { 710 case 0: 711 case 1: 712 // 713 // we have insufficient parameters 714 // 715 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"mv"); 716 ShellStatus = SHELL_INVALID_PARAMETER; 717 break; 718 case 2: 719 // 720 // must have valid CWD for single parameter... 721 // 722 if (ShellGetCurrentDir(NULL) == NULL){ 723 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"mv"); 724 ShellStatus = SHELL_INVALID_PARAMETER; 725 } else { 726 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); 727 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) { 728 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1)); 729 ShellStatus = SHELL_NOT_FOUND; 730 } else { 731 // 732 // ValidateAndMoveFiles will report errors to the screen itself 733 // 734 CwdSize = StrSize(ShellGetCurrentDir(NULL)) + sizeof(CHAR16); 735 Cwd = AllocateZeroPool(CwdSize); 736 ASSERT (Cwd != NULL); 737 StrCpyS(Cwd, CwdSize/sizeof(CHAR16), ShellGetCurrentDir(NULL)); 738 StrCatS(Cwd, CwdSize/sizeof(CHAR16), L"\\"); 739 ShellStatus = ValidateAndMoveFiles(FileList, &Response, Cwd); 740 FreePool(Cwd); 741 } 742 } 743 744 break; 745 default: 746 ///@todo make sure this works with error half way through and continues... 747 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount ; LoopCounter++) { 748 if (ShellGetExecutionBreakFlag()) { 749 break; 750 } 751 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); 752 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) { 753 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, LoopCounter)); 754 ShellStatus = SHELL_NOT_FOUND; 755 } else { 756 // 757 // ValidateAndMoveFiles will report errors to the screen itself 758 // Only change ShellStatus if it's sucessful 759 // 760 if (ShellStatus == SHELL_SUCCESS) { 761 ShellStatus = ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount)); 762 } else { 763 ValidateAndMoveFiles(FileList, &Response, ShellCommandLineGetRawValue(Package, ParamCount)); 764 } 765 } 766 if (FileList != NULL && !IsListEmpty(&FileList->Link)) { 767 Status = ShellCloseFileMetaArg(&FileList); 768 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) { 769 ShellStatus = SHELL_ACCESS_DENIED; 770 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"mv", ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT); 771 } 772 } 773 } 774 break; 775 } // switch on parameter count 776 777 if (FileList != NULL) { 778 ShellCloseFileMetaArg(&FileList); 779 } 780 781 // 782 // free the command line package 783 // 784 ShellCommandLineFreeVarList (Package); 785 } 786 787 SHELL_FREE_NON_NULL(Response); 788 789 if (ShellGetExecutionBreakFlag()) { 790 return (SHELL_ABORTED); 791 } 792 793 return (ShellStatus); 794 } 795