Ticket #4059: remember_filereplace_fix_2.diff
File remember_filereplace_fix_2.diff, 15.3 KB (added by , 15 years ago) |
---|
-
src/apps/packageinstaller/PackageItem.cpp
19 19 #include <fs_info.h> 20 20 #include "zlib.h" 21 21 22 #include <string.h> 23 22 24 // Macro reserved for later localization 23 25 #define T(x) x 24 26 … … 160 162 } 161 163 162 164 163 int32164 PackageItem::ItemExists(const char *name)165 {166 // TODO: this function doesn't really fit in, the GUI should be separated167 // from the package engine completely168 169 BString alertString = "The ";170 171 alertString << ItemKind() << " named \'" << name << "\' ";172 alertString << T("already exists in the given path. Should I replace "173 "the existing file with the one from this package?");174 175 BAlert *alert = new BAlert(T("file_exists"), alertString.String(),176 T("Yes"), T("No"), T("Abort"));177 178 return alert->Go();179 }180 181 182 165 status_t 183 166 PackageItem::InitPath(const char *path, BPath *destination) 184 167 { … … 452 435 453 436 454 437 status_t 455 PackageDirectory::WriteToPath(const char *path, BPath *final)438 PackageDirectory::WriteToPath(const char *path, ItemState *state) 456 439 { 457 BPath destination;440 BPath *destination = &(state->destination); 458 441 status_t ret; 459 442 parser_debug("Directory: %s WriteToPath() called!\n", fPath.String()); 460 443 461 ret = InitPath(path, &destination); 444 ret = InitPath(path, destination); 445 parser_debug("Ret: %d %s\n", ret, strerror(ret)); 462 446 if (ret != B_OK) 463 447 return ret; 464 448 465 449 // Since Haiku is single-user right now, we give the newly 466 450 // created directory default permissions 467 ret = create_directory(destination.Path(), kDefaultMode); 451 ret = create_directory(destination->Path(), kDefaultMode); 452 parser_debug("Create dir ret: %d %s\n", ret, strerror(ret)); 468 453 if (ret != B_OK) 469 454 return ret; 470 BDirectory dir(destination .Path());455 BDirectory dir(destination->Path()); 471 456 parser_debug("Directory created!\n"); 472 457 473 458 if (fCreationTime) … … 479 464 // Since directories can only have attributes in the offset section, 480 465 // we can check here whether it is necessary to continue 481 466 if (fOffset) 482 ret = HandleAttributes(&destination, &dir, "FoDa"); 483 484 if (final) 485 *final = destination; 467 ret = HandleAttributes(destination, &dir, "FoDa"); 486 468 469 parser_debug("Ret: %d %s\n", ret, strerror(ret)); 487 470 return ret; 488 471 } 489 472 … … 513 496 514 497 515 498 status_t 516 PackageFile::WriteToPath(const char *path, BPath *final)499 PackageFile::WriteToPath(const char *path, ItemState *state) 517 500 { 518 BPath destination; 519 status_t ret; 501 BFile file; 502 503 if (state == NULL) 504 return B_ERROR; 505 506 BPath *destination = &(state->destination); 507 status_t ret = B_OK; 520 508 parser_debug("File: %s WriteToPath() called!\n", fPath.String()); 521 509 522 ret = InitPath(path, &destination); 523 if (ret != B_OK) 524 return ret; 510 if (state->status == B_NO_INIT || destination->InitCheck() != B_OK) { 511 ret = InitPath(path, destination); 512 if (ret != B_OK) 513 return ret; 525 514 526 BFile file(destination.Path(), 527 B_WRITE_ONLY | B_CREATE_FILE | B_FAIL_IF_EXISTS); 528 ret = file.InitCheck(); 529 if (ret == B_FILE_EXISTS) { 530 int32 selection = ItemExists(destination.Leaf()); 531 switch (selection) { 532 case 0: 533 ret = file.SetTo(destination.Path(), 515 ret = file.SetTo(destination->Path(), 516 B_WRITE_ONLY | B_CREATE_FILE | B_FAIL_IF_EXISTS); 517 if (ret == B_ENTRY_NOT_FOUND) { 518 BPath directory; 519 destination->GetParent(&directory); 520 if (create_directory(directory.Path(), kDefaultMode) != B_OK) 521 return B_ERROR; 522 523 ret = file.SetTo(destination->Path(), B_WRITE_ONLY | B_CREATE_FILE); 524 } else if (ret == B_FILE_EXISTS) 525 state->status = B_FILE_EXISTS; 526 527 if (ret != B_OK) 528 return ret; 529 } 530 531 if (state->status == B_FILE_EXISTS) { 532 switch (state->policy) { 533 case P_EXISTS_OVERWRITE: 534 ret = file.SetTo(destination->Path(), 534 535 B_WRITE_ONLY | B_ERASE_FILE); 535 if (ret != B_OK)536 return ret;537 536 break; 538 case 1: 537 538 case P_EXISTS_NONE: 539 case P_EXISTS_ASK: 540 ret = B_FILE_EXISTS; 541 break; 542 543 case P_EXISTS_SKIP: 539 544 return B_OK; 540 default:541 return B_FILE_EXISTS;542 545 } 543 } else if (ret == B_ENTRY_NOT_FOUND) { 544 BPath directory; 545 destination.GetParent(&directory); 546 if (create_directory(directory.Path(), kDefaultMode) != B_OK) 547 return B_ERROR; 546 } 548 547 549 ret = file.SetTo(destination.Path(), B_WRITE_ONLY | B_CREATE_FILE); 550 if (ret != B_OK) 551 return ret; 552 } else if (ret != B_OK) 548 if (ret != B_OK) 553 549 return ret; 554 550 555 551 parser_debug(" File created!\n"); … … 637 633 delete[] temp; 638 634 } 639 635 640 if (final)641 *final = destination;642 643 636 return ret; 644 637 } 645 638 … … 665 658 666 659 667 660 status_t 668 PackageLink::WriteToPath(const char *path, BPath *final)661 PackageLink::WriteToPath(const char *path, ItemState *state) 669 662 { 663 if (state == NULL) 664 return B_ERROR; 665 666 status_t ret = B_OK; 667 BSymLink symlink; 670 668 parser_debug("Symlink: %s WriteToPath() called!\n", fPath.String()); 671 669 672 BPath destination; 673 status_t ret = InitPath(path, &destination); 674 if (ret != B_OK) 675 return ret; 670 BPath *destination = &(state->destination); 671 BDirectory *dir = &(state->parent); 676 672 677 BString linkName(destination.Leaf()); 678 parser_debug("%s:%s:%s\n", fPath.String(), destination.Path(), 679 linkName.String()); 673 if (state->status == B_NO_INIT || destination->InitCheck() != B_OK 674 || dir->InitCheck() != B_OK) { 675 // Not yet initialized 676 ret = InitPath(path, destination); 677 if (ret != B_OK) 678 return ret; 680 679 681 BPath dirPath;682 ret = destination.GetParent(&dirPath);683 BDirectory dir(dirPath.Path());680 BString linkName(destination->Leaf()); 681 parser_debug("%s:%s:%s\n", fPath.String(), destination->Path(), 682 linkName.String()); 684 683 685 ret = dir.InitCheck(); 686 if (ret == B_ENTRY_NOT_FOUND) { 687 if ((ret = create_directory(dirPath.Path(), kDefaultMode)) != B_OK) { 688 parser_debug("create_directory()) failed\n"); 689 return B_ERROR; 684 BPath dirPath; 685 ret = destination->GetParent(&dirPath); 686 ret = dir->SetTo(dirPath.Path()); 687 688 if (ret == B_ENTRY_NOT_FOUND) { 689 if ((ret = create_directory(dirPath.Path(), kDefaultMode)) != B_OK) { 690 parser_debug("create_directory()) failed\n"); 691 return B_ERROR; 692 } 690 693 } 694 if (ret != B_OK) { 695 parser_debug("destination InitCheck failed %s for %s\n", strerror(ret), dirPath.Path()); 696 return ret; 697 } 698 699 ret = dir->CreateSymLink(destination->Path(), fLink.String(), &symlink); 700 if (ret == B_FILE_EXISTS) { 701 // We need to check if the existing symlink is pointing at the same path 702 // as our new one - if not, let's prompt the user 703 symlink.SetTo(destination->Path()); 704 BPath oldLink; 705 706 ret = symlink.MakeLinkedPath(dir, &oldLink); 707 chdir(dirPath.Path()); 708 709 if (ret == B_BAD_VALUE || oldLink != fLink.String()) 710 state->status = ret = B_FILE_EXISTS; 711 else 712 ret = B_OK; 713 } 691 714 } 692 if (ret != B_OK) {693 parser_debug("destination InitCheck failed %s for %s\n", strerror(ret), dirPath.Path());694 return ret;695 }696 715 697 BSymLink symlink; 698 ret = dir.CreateSymLink(destination.Path(), fLink.String(), &symlink); 699 if (ret == B_FILE_EXISTS) { 700 // We need to check if the existing symlink is pointing at the same path 701 // as our new one - if not, let's prompt the user 702 symlink.SetTo(destination.Path()); 703 BPath oldLink; 716 if (state->status == B_FILE_EXISTS) { 717 switch (state->policy) { 718 case P_EXISTS_OVERWRITE: 719 { 720 BEntry entry; 721 ret = entry.SetTo(destination->Path()); 722 if (ret != B_OK) 723 return ret; 704 724 705 ret = symlink.MakeLinkedPath(&dir, &oldLink); 706 chdir(dirPath.Path()); 725 entry.Remove(); 726 ret = dir->CreateSymLink(destination->Path(), fLink.String(), 727 &symlink); 728 break; 729 } 707 730 708 if (ret == B_BAD_VALUE || oldLink != fLink.String()) { 709 // The old symlink is different (or not a symlink) - ask the user 710 int32 selection = ItemExists(destination.Leaf()); 711 switch (selection) { 712 case 0: 713 { 714 symlink.Unset(); 715 BEntry entry; 716 ret = entry.SetTo(destination.Path()); 717 if (ret != B_OK) 718 return ret; 731 case P_EXISTS_NONE: 732 case P_EXISTS_ASK: 733 ret = B_FILE_EXISTS; 734 break; 719 735 720 entry.Remove(); 721 ret = dir.CreateSymLink(destination.Path(), fLink.String(), 722 &symlink); 723 break; 724 } 725 case 1: 726 parser_debug("Skipping already existent SymLink\n"); 727 return B_OK; 728 default: 729 ret = B_FILE_EXISTS; 730 } 731 } else { 732 ret = B_OK; 736 case P_EXISTS_SKIP: 737 return B_OK; 733 738 } 734 739 } 740 735 741 if (ret != B_OK) { 736 742 parser_debug("CreateSymLink failed\n"); 737 743 return ret; … … 756 762 757 763 if (fOffset) { 758 764 // Symlinks also seem to have attributes - so parse them 759 ret = HandleAttributes( &destination, &symlink, "LnDa");765 ret = HandleAttributes(destination, &symlink, "LnDa"); 760 766 } 761 767 762 if (final) {763 *final = destination;764 }765 766 768 return ret; 767 769 } 768 770 -
src/apps/packageinstaller/PackageItem.h
1 1 /* 2 * Copyright (c) 2007 , Haiku, Inc.2 * Copyright (c) 2007-2009, Haiku, Inc. 3 3 * Distributed under the terms of the MIT license. 4 4 * 5 5 * Author: … … 15 15 #include <File.h> 16 16 #include <Path.h> 17 17 #include <String.h> 18 #include <Directory.h> 18 19 19 20 20 21 // Local macro for the parser debug output … … 32 33 P_USER_PATH 33 34 }; 34 35 36 // Existant item overwriting policy of a single file 37 enum { 38 P_EXISTS_ASK = 0, 39 P_EXISTS_OVERWRITE, 40 P_EXISTS_SKIP, 41 P_EXISTS_ABORT, 42 P_EXISTS_NONE 43 }; 44 35 45 extern status_t inflate_data(uint8* in, uint32 inSize, uint8* out, 36 46 uint32 outSize); 37 47 38 48 49 struct ItemState { 50 ItemState() : policy(P_EXISTS_NONE), status(B_NO_INIT) {} 51 ~ItemState() {} 52 53 inline void Reset(int32 currentPolicy) 54 { 55 destination.Unset(); 56 parent.Unset(); 57 status = B_NO_INIT; 58 policy = currentPolicy; 59 } 60 61 BPath destination; 62 BDirectory parent; 63 uint8 policy; 64 status_t status; 65 }; 66 67 39 68 class PackageItem { 40 69 public: 41 70 PackageItem(BFile* parent, const BString& path, … … 44 73 virtual ~PackageItem(); 45 74 46 75 virtual status_t WriteToPath(const char* path = NULL, 47 BPath* final= NULL) = 0;76 ItemState *state = NULL) = 0; 48 77 virtual void SetTo(BFile* parent, const BString& path, 49 78 uint8 type, uint32 ctime, uint32 mtime, 50 79 uint64 offset = 0, uint64 size = 0); 80 virtual const char* ItemKind() = 0; 51 81 52 82 protected: 53 virtual const char* ItemKind() = 0;54 int32 ItemExists(const char* name);55 83 status_t InitPath(const char* path, BPath* destination); 56 84 status_t HandleAttributes(BPath* destination, BNode* node, 57 85 const char* header); … … 84 112 uint64 offset = 0, uint64 size = 0); 85 113 86 114 virtual status_t WriteToPath(const char* path = NULL, 87 BPath* final = NULL); 88 89 protected: 115 ItemState *state = NULL); 90 116 virtual const char* ItemKind(); 91 117 }; 92 118 … … 100 126 const BString& signature, uint32 mode); 101 127 102 128 virtual status_t WriteToPath(const char* path = NULL, 103 BPath* final = NULL); 104 105 protected: 129 ItemState *state = NULL); 106 130 virtual const char* ItemKind(); 107 131 108 132 private: … … 123 147 uint64 size = 0); 124 148 125 149 virtual status_t WriteToPath(const char* path = NULL, 126 BPath* final = NULL); 127 128 protected: 150 ItemState *state = NULL); 129 151 virtual const char* ItemKind(); 130 152 131 153 private: -
src/apps/packageinstaller/PackageView.cpp
1 1 /* 2 * Copyright (c) 2007 , Haiku, Inc.2 * Copyright (c) 2007-2009, Haiku, Inc. 3 3 * Distributed under the terms of the MIT license. 4 4 * 5 5 * Author: … … 305 305 306 306 // Install files and directories 307 307 PackageItem *iter; 308 BPath installedTo;308 ItemState state; 309 309 uint32 i; 310 int32 choice; 310 311 BString label; 311 312 312 313 packageInfo.SetName(fInfo.GetName()); … … 322 323 packageInfo.SetDescription(description.String()); 323 324 packageInfo.SetSpaceNeeded(type->space_needed); 324 325 326 fItemExistsPolicy = P_EXISTS_NONE; 327 325 328 for (i = 0; i < n; i++) { 329 state.Reset(fItemExistsPolicy); // Reset the current item state 326 330 iter = static_cast<PackageItem *>(type->items.ItemAt(i)); 327 err = iter->WriteToPath(fCurrentPath.Path(), &installedTo); 331 332 err = iter->WriteToPath(fCurrentPath.Path(), &state); 333 if (err == B_FILE_EXISTS) { 334 // Writing to path failed because path already exists - ask the user 335 // what to do and retry the writing process 336 choice = _ItemExists(*iter, state.destination); 337 if (choice != P_EXISTS_ABORT) { 338 state.policy = choice; 339 err = iter->WriteToPath(fCurrentPath.Path(), &state); 340 } 341 } 342 328 343 if (err != B_OK) { 329 344 fprintf(stderr, "Error while writing path %s\n", fCurrentPath.Path()); 330 345 return err; 331 346 } 347 332 348 if (fStatusWindow->Stopped()) 333 349 return B_FILE_EXISTS; 334 350 label = ""; 335 351 label << (uint32)(i + 1) << " of " << (uint32)n; 336 352 fStatusWindow->StageStep(1, NULL, label.String()); 337 353 338 packageInfo.AddItem( installedTo.Path());354 packageInfo.AddItem(state.destination.Path()); 339 355 } 340 356 341 357 fStatusWindow->StageStep(1, "Finishing installation", ""); … … 534 550 } 535 551 536 552 553 int32 554 PackageView::_ItemExists(PackageItem &item, BPath &path) 555 { 556 int32 choice = P_EXISTS_NONE; 557 558 switch (fItemExistsPolicy) { 559 case P_EXISTS_OVERWRITE: 560 choice = P_EXISTS_OVERWRITE; 561 break; 562 563 case P_EXISTS_SKIP: 564 choice = P_EXISTS_SKIP; 565 break; 566 567 case P_EXISTS_ASK: 568 case P_EXISTS_NONE: 569 { 570 BString alertString = T("The "); 571 572 alertString << item.ItemKind() << T(" named \'") << path.Leaf() << "\' "; 573 alertString << T("already exists in the given path. Should the " 574 "existing file be replaced with the one from this package?"); 575 576 BAlert *alert = new BAlert(T("file_exists"), alertString.String(), 577 T("Yes"), T("No"), T("Abort")); 578 579 choice = alert->Go(); 580 switch (choice) { 581 case 0: 582 choice = P_EXISTS_OVERWRITE; 583 break; 584 case 1: 585 choice = P_EXISTS_SKIP; 586 break; 587 default: 588 return P_EXISTS_ABORT; 589 } 590 591 if (fItemExistsPolicy == P_EXISTS_NONE) { 592 // XXX: Maybe add 'No, but ask again' type of choice as well? 593 alertString = T("Should this decision be remembered and all existing " 594 "files encountered in the future be "); 595 alertString << ((choice == P_EXISTS_OVERWRITE) ? T("replaced?") : T("skipped?")); 596 597 alert = new BAlert(T("policy_decision"), alertString.String(), 598 T("Yes"), T("No")); 599 600 int32 decision = alert->Go(); 601 if (decision == 0) 602 fItemExistsPolicy = choice; 603 else 604 fItemExistsPolicy = P_EXISTS_ASK; 605 } 606 break; 607 } 608 } 609 610 return choice; 611 } 612 613 537 614 status_t 538 615 PackageView::_GroupChanged(int32 index) 539 616 { -
src/apps/packageinstaller/PackageView.h
1 1 /* 2 * Copyright (c) 2007 , Haiku, Inc.2 * Copyright (c) 2007-2009, Haiku, Inc. 3 3 * Distributed under the terms of the MIT license. 4 4 * 5 5 * Author: … … 42 42 private: 43 43 void _InitView(); 44 44 void _InitProfiles(); 45 int32 _ItemExists(PackageItem &item, BPath &path); 45 46 46 47 status_t _GroupChanged(int32 index); 47 48 … … 54 55 BFilePanel *fOpenPanel; 55 56 BPath fCurrentPath; 56 57 uint32 fCurrentType; 58 int32 fItemExistsPolicy; 57 59 58 60 PackageInfo fInfo; 59 61 PackageStatus *fStatusWindow;