Ticket #3762: script.patch
File script.patch, 35.9 KB (added by , 14 years ago) |
---|
-
PackageStatus.cpp
92 92 93 93 94 94 PackageStatus::PackageStatus(const char *title, const char *label, 95 const char *trailing )95 const char *trailing, BHandler *parent) 96 96 : BWindow(BRect(200, 200, 550, 255), title, B_TITLED_WINDOW, 97 97 B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE, 0), 98 fIsStopped(false) 98 fIsStopped(false), 99 fParent(parent) 99 100 { 100 101 SetLayout(new BGroupLayout(B_VERTICAL)); 101 102 … … 129 130 switch (msg->what) { 130 131 case P_MSG_STOP: 131 132 fIsStopped = true; 133 if (fParent != NULL) { 134 // If we have a parent defined, forward this message 135 BLooper *loop = fParent->Looper(); 136 if (loop != NULL) { 137 loop->PostMessage(msg, fParent); 138 } 139 } 132 140 break; 133 141 default: 134 142 BWindow::MessageReceived(msg); -
PackageStatus.h
31 31 class PackageStatus : public BWindow { 32 32 public: 33 33 PackageStatus(const char *title, const char *label = NULL, 34 const char *trailing = NULL );34 const char *trailing = NULL, BHandler *parent = NULL); 35 35 ~PackageStatus(); 36 36 37 37 void MessageReceived(BMessage *msg); … … 46 46 BStatusBar *fStatus; 47 47 StopButton *fButton; 48 48 bool fIsStopped; 49 BHandler *fParent; 49 50 }; 50 51 51 52 -
PackageInfo.cpp
39 39 P_NONE = 0, 40 40 P_FILE, 41 41 P_DIRECTORY, 42 P_LINK 42 P_LINK, 43 P_SCRIPT 43 44 }; 44 45 45 46 … … 86 87 delete file; 87 88 } 88 89 90 while (true) { 91 file = static_cast<PackageScript *>(fScripts.RemoveItem((long int)0)); 92 if (file == NULL) 93 break; 94 95 delete file; 96 } 97 89 98 delete fPackageFile; 90 99 } 91 100 … … 624 633 RETURN_AND_SET_STATUS(B_ERROR); 625 634 } 626 635 627 // TODO: Here's the deal... there seems to be a strange ScrI tag that 628 // seems to mean script files (check this). It seems exaclty the same 629 // as a normal file (just as script files are normal files) so for 630 // now I'm treating those as files. Check if it's correct! 631 // No, it isn't and I will fix this soon. 632 if (!memcmp(buffer, "FilI", 5) || !memcmp(buffer, "ScrI", 5)) { 633 parser_debug("FilI\n"); 634 element = P_FILE; 636 #define INIT_VARS(tag, type) \ 637 parser_debug(tag "\n"); \ 638 element = type; \ 639 mimeString = ""; \ 640 nameString = ""; \ 641 linkString = ""; \ 642 signatureString = ""; \ 643 itemGroups = 0; \ 644 ctime = 0; \ 645 mtime = 0; \ 646 offset = 0; \ 647 cust = 0; \ 648 mode = 0; \ 649 platform = 0xffffffff; \ 650 size = 0; \ 651 originalSize = 0 635 652 636 mimeString = ""; 637 nameString = ""; 638 signatureString = ""; 639 640 itemGroups = 0; 641 ctime = 0; 642 mtime = 0; 643 offset = 0; 644 itemGroups = 0; 645 cust = 0; 646 mode = 0; 647 platform = 0xffffffff; 648 649 size = 0; 650 originalSize = 0; 653 if (!memcmp(buffer, "FilI", 5)) { 654 INIT_VARS("FilI", P_FILE); 651 655 } else if (!memcmp(buffer, "FldI", 5)) { 652 parser_debug("FldI\n"); 653 element = P_DIRECTORY; 654 655 nameString = ""; 656 657 itemGroups = 0; 658 ctime = 0; 659 mtime = 0; 660 offset = 0; 661 itemGroups = 0; 662 cust = 0; 663 platform = 0xffffffff; 664 665 size = 0; 666 originalSize = 0; 656 INIT_VARS("FldI", P_DIRECTORY); 667 657 } else if (!memcmp(buffer, "LnkI", 5)) { 668 parser_debug("LnkI\n"); 669 element = P_LINK; 670 671 nameString = ""; 672 linkString = ""; 673 674 itemGroups = 0; 675 ctime = 0; 676 mtime = 0; 677 offset = 0; 678 itemGroups = 0; 679 cust = 0; 680 platform = 0xffffffff; 681 682 size = 0; 683 originalSize = 0; 658 INIT_VARS("LnkI", P_LINK); 659 } else if (!memcmp(buffer, "ScrI", 5)) { 660 INIT_VARS("ScrI", P_SCRIPT); 684 661 } else if (!memcmp(buffer, "Name", 5)) { 685 662 if (element == P_NONE) { 686 663 RETURN_AND_SET_STATUS(B_ERROR); … … 795 772 swap_data(B_UINT64_TYPE, &size, sizeof(uint64), 796 773 B_SWAP_BENDIAN_TO_HOST); 797 774 } else if (!memcmp(buffer, "OrgS", 5)) { 798 if (element != P_FILE && element != P_LINK ) {775 if (element != P_FILE && element != P_LINK && element != P_SCRIPT) { 799 776 RETURN_AND_SET_STATUS(B_ERROR); 800 777 } 801 778 … … 1019 996 item = new PackageLink(fPackageFile, dest, linkString, 1020 997 localType, ctime, mtime, mode, offset, size); 1021 998 } 999 } else if (element == P_SCRIPT) { 1000 fScripts.AddItem(new PackageScript(fPackageFile, offset, size, 1001 originalSize)); 1022 1002 } else { 1023 1003 // If the directory tree count is equal to zero, this means all 1024 1004 // directory trees have been closed and a padding sequence means the -
PackageItem.cpp
16 16 #include <Directory.h> 17 17 #include <fs_info.h> 18 18 #include <NodeInfo.h> 19 #include <OS.h> 19 20 #include <SymLink.h> 20 21 #include <Volume.h> 21 22 … … 37 38 P_ATTRIBUTE 38 39 }; 39 40 41 extern const char **environ; 40 42 43 41 44 status_t 42 45 inflate_data(uint8 *in, uint32 inSize, uint8 *out, uint32 outSize) 43 46 { 47 parser_debug("inflate_data() called - input_size: %ld, output_size: %ld\n", 48 inSize, outSize); 44 49 z_stream stream; 45 50 stream.zalloc = Z_NULL; 46 51 stream.zfree = Z_NULL; … … 375 380 376 381 377 382 status_t 383 PackageItem::SkipAttribute(uint8 *buffer, bool *attrStarted, bool *done) 384 { 385 status_t ret = B_OK; 386 uint32 length; 387 388 if (!memcmp(buffer, "BeAI", 5)) { 389 parser_debug(" Attribute started.\n"); 390 *attrStarted = true; 391 } else if (!memcmp(buffer, "BeAN", 5)) { 392 if (!*attrStarted) { 393 ret = B_ERROR; 394 return ret; 395 } 396 397 parser_debug(" BeAN.\n"); 398 fPackage->Read(&length, 4); 399 swap_data(B_UINT32_TYPE, &length, sizeof(uint32), 400 B_SWAP_BENDIAN_TO_HOST); 401 402 fPackage->Seek(length, SEEK_CUR); 403 } else if (!memcmp(buffer, "BeAT", 5)) { 404 if (!*attrStarted) { 405 ret = B_ERROR; 406 return ret; 407 } 408 409 parser_debug(" BeAT.\n"); 410 fPackage->Seek(4, SEEK_CUR); 411 } else if (!memcmp(buffer, "BeAD", 5)) { 412 if (!*attrStarted) { 413 ret = B_ERROR; 414 return ret; 415 } 416 417 parser_debug(" BeAD.\n"); 418 uint64 length64; 419 fPackage->Read(&length64, 8); 420 swap_data(B_UINT64_TYPE, &length64, sizeof(length64), B_SWAP_BENDIAN_TO_HOST); 421 422 fPackage->Seek(12 + length64, SEEK_CUR); 423 424 parser_debug(" Data skipped successfuly.\n"); 425 } else if (!memcmp(buffer, padding, 7)) { 426 if (!*attrStarted) { 427 *done = true; 428 return ret; 429 } 430 431 parser_debug(" Padding.\n"); 432 *attrStarted = false; 433 parser_debug(" > Attribute skipped.\n"); 434 } else { 435 parser_debug(" Unknown attribute\n"); 436 ret = B_ERROR; 437 } 438 439 return ret; 440 } 441 442 443 status_t 378 444 PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize, 379 445 bool *done) 380 446 { … … 425 491 } 426 492 427 493 494 // #pragma mark - PackageScript 495 496 497 PackageScript::PackageScript(BFile *parent, uint64 offset, uint64 size, 498 uint64 originalSize) 499 : 500 PackageItem(parent, NULL, 0, 0, 0, offset, size), 501 fOriginalSize(originalSize), 502 fThreadId(-1) 503 { 504 } 505 506 507 status_t 508 PackageScript::DoInstall(const char *path, ItemState *state) 509 { 510 status_t ret = B_OK; 511 parser_debug("Script: DoInstall() called!\n"); 512 513 if (fOffset) { 514 parser_debug("We have an offset\n"); 515 if (!fPackage) 516 return B_ERROR; 517 518 ret = fPackage->InitCheck(); 519 if (ret != B_OK) 520 return ret; 521 522 // We need to parse the data section now 523 fPackage->Seek(fOffset, SEEK_SET); 524 uint8 buffer[7]; 525 bool attrStarted = false, done = false; 526 527 uint8 section = P_ATTRIBUTE; 528 529 uint8 *script = NULL; 530 531 while (fPackage->Read(buffer, 7) == 7) { 532 if (!memcmp(buffer, "FBeA", 5)) { 533 parser_debug("-> Attribute\n"); 534 section = P_ATTRIBUTE; 535 continue; 536 } else if (!memcmp(buffer, "FiDa", 5)) { 537 parser_debug("-> File data\n"); 538 section = P_DATA; 539 continue; 540 } 541 542 switch (section) { 543 case P_ATTRIBUTE: 544 ret = SkipAttribute(buffer, &attrStarted, &done); 545 break; 546 547 case P_DATA: 548 ret = ParseScript(buffer, fOriginalSize, &script, &done); 549 break; 550 551 default: 552 return B_ERROR; 553 } 554 555 if (ret != B_OK || done) 556 break; 557 } 558 559 delete[] script; 560 } 561 562 parser_debug("Ret: %d %s\n", ret, strerror(ret)); 563 return ret; 564 } 565 566 567 const char* 568 PackageScript::ItemKind() 569 { 570 return "script"; 571 } 572 573 574 status_t 575 PackageScript::ParseScript(uint8 *buffer, uint64 originalSize, uint8 **script, bool *done) 576 { 577 status_t ret = B_OK; 578 579 if (!memcmp(buffer, "FiMF", 5)) { 580 parser_debug(" Found file (script) data.\n"); 581 uint64 compressed, original; 582 fPackage->Read(&compressed, 8); 583 swap_data(B_UINT64_TYPE, &compressed, sizeof(uint64), 584 B_SWAP_BENDIAN_TO_HOST); 585 586 fPackage->Read(&original, 8); 587 swap_data(B_UINT64_TYPE, &original, sizeof(uint64), 588 B_SWAP_BENDIAN_TO_HOST); 589 parser_debug(" Still good... (%llu : %llu)\n", original, 590 originalSize); 591 592 if (original != originalSize) { 593 parser_debug(" File size mismatch\n"); 594 return B_ERROR; // File size mismatch 595 } 596 parser_debug(" Still good...\n"); 597 598 if (fPackage->Read(buffer, 4) != 4) { 599 parser_debug(" Read(buffer, 4) failed\n"); 600 return B_ERROR; 601 } 602 parser_debug(" Still good...\n"); 603 604 uint8 *temp = new uint8[compressed]; 605 if (fPackage->Read(temp, compressed) != compressed) { 606 parser_debug(" Read(temp, compressed) failed\n"); 607 delete[] temp; 608 return B_ERROR; 609 } 610 611 if (*script != NULL) { 612 delete[] *script; 613 } 614 *script = new uint8[original]; 615 616 ret = inflate_data(temp, compressed, *script, original); 617 if (ret != B_OK) { 618 parser_debug(" inflate_data failed\n"); 619 delete[] temp; 620 return ret; 621 } 622 623 ret = RunScript(*script, originalSize); 624 delete[] *script; 625 *script = NULL; 626 delete[] temp; 627 parser_debug(" Script data inflation complete!\n"); 628 } 629 else if (!memcmp(buffer, padding, 7)) { 630 *done = true; 631 return ret; 632 } 633 else { 634 parser_debug("_ParseData unknown tag\n"); 635 ret = B_ERROR; 636 } 637 638 return ret; 639 } 640 641 642 status_t 643 PackageScript::RunScript(uint8 *script, uint32 len) 644 { 645 // This function written by Peter Folk <pfolk@uni.uiuc.edu> 646 // and published in the BeDevTalk FAQ, modified for use in the 647 // PackageInstaller 648 // http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209 649 650 // Save current FDs 651 int old_in = dup(0); 652 int old_out = dup(1); 653 int old_err = dup(2); 654 655 int filedes[2]; 656 657 /* Create new pipe FDs as stdin, stdout, stderr */ 658 pipe(filedes); dup2(filedes[0], 0); close(filedes[0]); 659 int in = filedes[1]; // Write to in, appears on cmd's stdin 660 pipe(filedes); dup2(filedes[1], 1); close(filedes[1]); 661 pipe(filedes); dup2(filedes[1], 2); close(filedes[1]); 662 663 const char **argv = new const char * [3]; 664 argv[0] = strdup("/bin/sh"); 665 argv[1] = strdup("-s"); 666 argv[2] = NULL; 667 668 // "load" command. 669 fThreadId = load_image(2, argv, environ); 670 671 int i; 672 for (i = 0; i < 2; i++) 673 delete argv[i]; 674 delete [] argv; 675 676 if (fThreadId < B_OK) 677 return fThreadId; 678 679 // thread id is now suspended. 680 setpgid(fThreadId, fThreadId); 681 682 // Restore old FDs 683 close(0); dup(old_in); close(old_in); 684 close(1); dup(old_out); close(old_out); 685 close(2); dup(old_err); close(old_err); 686 687 set_thread_priority(fThreadId, B_LOW_PRIORITY); 688 resume_thread(fThreadId); 689 690 // Write the script 691 if (write(in, script, len) != len || write(in, "\nexit\n", 6) != 6) { 692 parser_debug("Writing script failed\n"); 693 kill_thread(fThreadId); 694 return B_ERROR; 695 } 696 697 return B_OK; 698 } 699 700 428 701 // #pragma mark - PackageDirectory 429 702 430 703 … … 437 710 438 711 439 712 status_t 440 PackageDirectory:: WriteToPath(const char *path, ItemState *state)713 PackageDirectory::DoInstall(const char *path, ItemState *state) 441 714 { 442 715 BPath &destination = state->destination; 443 716 status_t ret; 444 parser_debug("Directory: %s WriteToPath() called!\n", fPath.String());717 parser_debug("Directory: %s DoInstall() called!\n", fPath.String()); 445 718 446 719 ret = InitPath(path, &destination); 447 720 parser_debug("Ret: %d %s\n", ret, strerror(ret)); … … 499 772 500 773 501 774 status_t 502 PackageFile:: WriteToPath(const char *path, ItemState *state)775 PackageFile::DoInstall(const char *path, ItemState *state) 503 776 { 504 777 if (state == NULL) 505 778 return B_ERROR; 506 779 507 780 BPath &destination = state->destination; 508 781 status_t ret = B_OK; 509 parser_debug("File: %s WriteToPath() called!\n", fPath.String());782 parser_debug("File: %s DoInstall() called!\n", fPath.String()); 510 783 511 784 BFile file; 512 785 if (state->status == B_NO_INIT || destination.InitCheck() != B_OK) { … … 661 934 662 935 663 936 status_t 664 PackageLink:: WriteToPath(const char *path, ItemState *state)937 PackageLink::DoInstall(const char *path, ItemState *state) 665 938 { 666 939 if (state == NULL) 667 940 return B_ERROR; 668 941 669 942 status_t ret = B_OK; 670 943 BSymLink symlink; 671 parser_debug("Symlink: %s WriteToPath() called!\n", fPath.String());944 parser_debug("Symlink: %s DoInstall() called!\n", fPath.String()); 672 945 673 946 BPath &destination = state->destination; 674 947 BDirectory *dir = &state->parent; -
PackageInfo.h
33 33 BMallocIO *GetSplashScreen() { return fHasImage ? &fImage : NULL; } 34 34 int32 GetProfileCount() { return fProfiles.CountItems(); } 35 35 pkg_profile *GetProfile(int32 num) { return static_cast<pkg_profile *>(fProfiles.ItemAt(num)); } 36 int32 GetScriptCount() { return fScripts.CountItems(); } 37 PackageScript *GetScript(int32 num) { return static_cast<PackageScript *>(fScripts.ItemAt(num)); } 36 38 37 39 status_t Parse(); 38 40 status_t InitCheck() { return fStatus; } … … 56 58 bool fHasImage; 57 59 58 60 BList fFiles; // Holds all files in the package 61 BList fScripts; 59 62 }; 60 63 61 64 -
PackageItem.h
72 72 uint64 offset = 0, uint64 size = 0); 73 73 virtual ~PackageItem(); 74 74 75 virtual status_t WriteToPath(const char* path = NULL,75 virtual status_t DoInstall(const char* path = NULL, 76 76 ItemState *state = NULL) = 0; 77 77 virtual void SetTo(BFile* parent, const BString& path, 78 78 uint8 type, uint32 ctime, uint32 mtime, 79 79 uint64 offset = 0, uint64 size = 0); 80 80 virtual const char* ItemKind() = 0; 81 81 82 protected:82 protected: 83 83 status_t InitPath(const char* path, BPath* destination); 84 84 status_t HandleAttributes(BPath* destination, BNode* node, 85 85 const char* header); … … 91 91 uint64* tempSize, uint64* attrCSize, 92 92 uint64* attrOSize, bool* attrStarted, 93 93 bool* done); 94 status_t SkipAttribute(uint8 *buffer, bool *attrStarted, 95 bool *done); 94 96 status_t ParseData(uint8* buffer, BFile* file, 95 97 uint64 originalSize, bool* done); 96 98 … … 111 113 uint8 type, uint32 ctime, uint32 mtime, 112 114 uint64 offset = 0, uint64 size = 0); 113 115 114 virtual status_t WriteToPath(const char* path = NULL,116 virtual status_t DoInstall(const char* path = NULL, 115 117 ItemState *state = NULL); 116 118 virtual const char* ItemKind(); 117 119 }; 118 120 119 121 122 class PackageScript : public PackageItem { 123 public: 124 PackageScript(BFile* parent, uint64 offset = 0, uint64 size = 0, 125 uint64 originalSize = 0); 126 127 virtual status_t DoInstall(const char* path = NULL, 128 ItemState *state = NULL); 129 virtual const char* ItemKind(); 130 131 thread_id GetThreadId() { return fThreadId; } 132 void SetThreadId(thread_id id) { fThreadId = id; } 133 134 private: 135 status_t ParseScript(uint8 *buffer, uint64 originalSize, 136 uint8 **script, bool *done); 137 status_t RunScript(uint8 *script, uint32 len); 138 139 uint64 fOriginalSize; 140 thread_id fThreadId; 141 }; 142 143 120 144 class PackageFile : public PackageItem { 121 145 public: 122 146 PackageFile(BFile* parent, const BString& path, … … 125 149 uint32 platform, const BString& mime, 126 150 const BString& signature, uint32 mode); 127 151 128 virtual status_t WriteToPath(const char* path = NULL,152 virtual status_t DoInstall(const char* path = NULL, 129 153 ItemState *state = NULL); 130 154 virtual const char* ItemKind(); 131 155 … … 146 170 uint32 mtime, uint32 mode, uint64 offset = 0, 147 171 uint64 size = 0); 148 172 149 virtual status_t WriteToPath(const char* path = NULL,173 virtual status_t DoInstall(const char* path = NULL, 150 174 ItemState *state = NULL); 151 175 virtual const char* ItemKind(); 152 176 -
PackageInstall.cpp
1 /* 2 * Copyright (c) 2010, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Author: 6 * Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org> 7 */ 8 9 10 #include "PackageInstall.h" 11 12 #include "InstalledPackageInfo.h" 13 #include "PackageItem.h" 14 #include "PackageView.h" 15 16 #include <Alert.h> 17 #include <stdio.h> 18 19 20 // Macro reserved for later localization 21 #define T(x) x 22 23 static int32 install_function(void *data) 24 { 25 // TODO: Inform if already one thread is running 26 PackageInstall *install = static_cast<PackageInstall *>(data); 27 if (data == NULL) 28 return -1; 29 30 return install->Install(); 31 } 32 33 34 PackageInstall::PackageInstall(PackageView *parent) 35 : fParent(parent), 36 fThreadId(-1) 37 { 38 } 39 40 41 PackageInstall::~PackageInstall() 42 { 43 } 44 45 46 status_t 47 PackageInstall::Start() 48 { 49 status_t ret = B_OK; 50 51 fIdLocker.Lock(); 52 if (fThreadId > -1) { 53 ret = B_BUSY; 54 } 55 else { 56 fThreadId = spawn_thread(install_function, "install_package", B_NORMAL_PRIORITY, 57 static_cast<void *>(this)); 58 resume_thread(fThreadId); 59 } 60 fIdLocker.Unlock(); 61 62 return ret; 63 } 64 65 66 void 67 PackageInstall::Stop() 68 { 69 fIdLocker.Lock(); 70 if (fThreadId > -1) { 71 kill_thread(fThreadId); 72 fThreadId = -1; 73 } 74 fIdLocker.Unlock(); 75 76 fCurrentScriptLocker.Lock(); 77 if (fCurrentScript != NULL) { 78 thread_id id = fCurrentScript->GetThreadId(); 79 if (id > -1) { 80 fCurrentScript->SetThreadId(-1); 81 kill_thread(id); 82 } 83 fCurrentScript = NULL; 84 } 85 fCurrentScriptLocker.Unlock(); 86 } 87 88 89 #define RETURN_MESSAGE(msg, st) \ 90 do { \ 91 if (fParent && fParent->Looper()) \ 92 fParent->Looper()->PostMessage(new BMessage(msg), fParent); \ 93 return st; \ 94 } while(0) 95 96 status_t 97 PackageInstall::Install() 98 { 99 PackageInfo *info = fParent->GetPackageInfo(); 100 pkg_profile *type = static_cast<pkg_profile *>(info->GetProfile(fParent->GetCurrentType())); 101 uint32 n = type->items.CountItems(), m = info->GetScriptCount(); 102 103 PackageStatus *progress = fParent->GetStatusWindow(); 104 progress->Reset(n + m + 5); 105 106 progress->StageStep(1, T("Preparing package")); 107 108 InstalledPackageInfo packageInfo(info->GetName(), info->GetVersion()); 109 110 status_t err = packageInfo.InitCheck(); 111 if (err == B_OK) { 112 // The package is already installed, inform the user 113 BAlert *reinstall = new BAlert("reinstall", 114 T("The given package seems to be already installed on your system. " 115 "Would you like to uninstall the existing one and continue the " 116 "installation?"), T("Continue"), T("Abort")); 117 118 if (reinstall->Go() == 0) { 119 // Uninstall the package 120 err = packageInfo.Uninstall(); 121 if (err != B_OK) { 122 fprintf(stderr, "Error on uninstall\n"); 123 RETURN_MESSAGE(P_MSG_I_ERROR, err); 124 } 125 126 err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true); 127 if (err != B_OK) { 128 fprintf(stderr, "Error on SetTo\n"); 129 RETURN_MESSAGE(P_MSG_I_ERROR, err); 130 } 131 } 132 else { 133 // Abort the installation 134 RETURN_MESSAGE(P_MSG_I_ABORT, B_FILE_EXISTS); 135 } 136 } 137 else if (err == B_ENTRY_NOT_FOUND) { 138 err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true); 139 if (err != B_OK) { 140 fprintf(stderr, "Error on SetTo\n"); 141 RETURN_MESSAGE(P_MSG_I_ERROR, err); 142 } 143 } 144 else if (progress->Stopped()) { 145 RETURN_MESSAGE(P_MSG_I_ABORT, B_FILE_EXISTS); 146 } 147 else { 148 fprintf(stderr, "returning on error\n"); 149 RETURN_MESSAGE(P_MSG_I_ERROR, err); 150 } 151 152 progress->StageStep(1, T("Installing files and folders")); 153 154 // Install files and directories 155 PackageItem *iter; 156 ItemState state; 157 uint32 i; 158 int32 choice; 159 BString label; 160 161 packageInfo.SetName(info->GetName()); 162 // TODO: Here's a small problem, since right now it's not quite sure 163 // which description is really used as such. The one displayed on 164 // the installer is mostly package installation description, but 165 // most people use it for describing the application in more detail 166 // then in the short description. 167 // For now, we'll use the short description if possible. 168 BString description = info->GetShortDescription(); 169 if (description.Length() <= 0) 170 description = info->GetDescription(); 171 packageInfo.SetDescription(description.String()); 172 packageInfo.SetSpaceNeeded(type->space_needed); 173 174 fItemExistsPolicy = P_EXISTS_NONE; 175 176 const char *installPath = fParent->GetCurrentPath()->Path(); 177 for (i = 0; i < n; i++) { 178 state.Reset(fItemExistsPolicy); // Reset the current item state 179 iter = static_cast<PackageItem *>(type->items.ItemAt(i)); 180 181 err = iter->DoInstall(installPath, &state); 182 if (err == B_FILE_EXISTS) { 183 // Writing to path failed because path already exists - ask the user 184 // what to do and retry the writing process 185 choice = fParent->ItemExists(*iter, state.destination, fItemExistsPolicy); 186 if (choice != P_EXISTS_ABORT) { 187 state.policy = choice; 188 err = iter->DoInstall(installPath, &state); 189 } 190 } 191 192 if (err != B_OK) { 193 fprintf(stderr, "Error while writing path\n"); 194 RETURN_MESSAGE(P_MSG_I_ERROR, err); 195 } 196 197 if (progress->Stopped()) 198 RETURN_MESSAGE(P_MSG_I_ABORT, B_FILE_EXISTS); 199 label = ""; 200 label << (uint32)(i + 1) << " of " << (uint32)n; 201 progress->StageStep(1, NULL, label.String()); 202 203 packageInfo.AddItem(state.destination.Path()); 204 } 205 206 progress->StageStep(1, T("Running post-installation scripts"), ""); 207 208 PackageScript *scr; 209 status_t status; 210 // Run all scripts 211 for (i = 0; i < m; i++) { 212 scr = info->GetScript(i); 213 214 fCurrentScriptLocker.Lock(); 215 fCurrentScript = scr; 216 217 if (scr->DoInstall() != B_OK) { 218 fprintf(stderr, "Error while running script\n"); 219 RETURN_MESSAGE(P_MSG_I_ERROR, err); 220 } 221 fCurrentScriptLocker.Unlock(); 222 223 wait_for_thread(scr->GetThreadId(), &status); 224 fCurrentScriptLocker.Lock(); 225 scr->SetThreadId(-1); 226 fCurrentScript = NULL; 227 fCurrentScriptLocker.Unlock(); 228 229 if (progress->Stopped()) 230 RETURN_MESSAGE(P_MSG_I_ABORT, B_FILE_EXISTS); 231 label = ""; 232 label << (uint32)(i + 1) << " of " << (uint32)m; 233 progress->StageStep(1, NULL, label.String()); 234 } 235 236 progress->StageStep(1, T("Finishing installation"), ""); 237 238 err = packageInfo.Save(); 239 if (err != B_OK) 240 RETURN_MESSAGE(P_MSG_I_ERROR, err); 241 242 progress->StageStep(1, T("Done")); 243 244 // Inform our parent that we finished 245 RETURN_MESSAGE(P_MSG_I_FINISHED, B_OK); 246 } 247 -
Jamfile
11 11 PackageView.cpp 12 12 PackageInfo.cpp 13 13 PackageItem.cpp 14 PackageInstall.cpp 14 15 PackageStatus.cpp 15 16 PackageTextViewer.cpp 16 17 PackageImageViewer.cpp -
PackageView.cpp
63 63 //BView("package_view", B_WILL_DRAW, new BGroupLayout(B_HORIZONTAL)), 64 64 fOpenPanel(new BFilePanel(B_OPEN_PANEL, NULL, NULL, 65 65 B_DIRECTORY_NODE, false)), 66 fInfo(ref) 66 fInfo(ref), 67 fInstallProcess(this) 67 68 { 68 69 _InitView(); 69 70 … … 121 122 // attaching the view to the window 122 123 _GroupChanged(0); 123 124 124 fStatusWindow = new PackageStatus(T("Installation progress")); 125 fStatusWindow = new PackageStatus(T("Installation progress"), NULL, NULL, 126 this); 125 127 126 128 // Show the splash screen, if present 127 129 BMallocIO *image = fInfo.GetSplashScreen(); … … 133 135 // Show the disclaimer/info text popup, if present 134 136 BString disclaimer = fInfo.GetDisclaimer(); 135 137 if (disclaimer.Length() != 0) { 136 138 PackageTextViewer *text = new PackageTextViewer(disclaimer.String()); 137 139 int32 selection = text->Go(); 138 140 // The user didn't accept our disclaimer, this means we cannot continue. 139 141 if (selection == 0) { 140 142 BWindow *parent = Window(); 141 143 if (parent && parent->Lock()) 142 144 parent->Quit(); … … 153 155 case P_MSG_INSTALL: 154 156 { 155 157 fInstall->SetEnabled(false); 158 fInstallTypes->SetEnabled(false); 159 fDestination->SetEnabled(false); 156 160 fStatusWindow->Show(); 157 BAlert *notify;158 status_t ret = Install();159 if (ret == B_OK) {160 notify = new BAlert("installation_success",161 T("The package you requested has been successfully installed "162 "on your system."), T("OK"));163 161 164 notify->Go(); 165 fStatusWindow->Hide(); 166 167 BWindow *parent = Window(); 168 if (parent && parent->Lock()) 169 parent->Quit(); 170 } 171 else if (ret == B_FILE_EXISTS) 172 notify = new BAlert("installation_aborted", 173 T("The installation of the package has been aborted."), T("OK")); 174 else { 175 notify = new BAlert("installation_failed", // TODO: Review this 176 T("The requested package failed to install on your system. This " 177 "might be a problem with the target package file. Please consult " 178 "this issue with the package distributor."), T("OK"), NULL, 179 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 180 fprintf(stderr, "Error while installing the package : %s\n", strerror(ret)); 181 } 182 notify->Go(); 183 fStatusWindow->Hide(); 184 fInstall->SetEnabled(true); 185 162 fInstallProcess.Start(); 186 163 break; 187 164 } 188 165 case P_MSG_PATH_CHANGED: … … 204 181 } 205 182 break; 206 183 } 184 case P_MSG_I_FINISHED: 185 { 186 BAlert *notify = new BAlert("installation_success", 187 T("The package you requested has been successfully installed " 188 "on your system."), T("OK")); 189 190 notify->Go(); 191 fStatusWindow->Hide(); 192 fInstall->SetEnabled(true); 193 fInstallTypes->SetEnabled(true); 194 fDestination->SetEnabled(true); 195 fInstallProcess.Stop(); 196 197 BWindow *parent = Window(); 198 if (parent && parent->Lock()) 199 parent->Quit(); 200 break; 201 } 202 case P_MSG_I_ABORT: 203 { 204 BAlert *notify = new BAlert("installation_aborted", 205 T("The installation of the package has been aborted."), T("OK")); 206 notify->Go(); 207 fStatusWindow->Hide(); 208 fInstall->SetEnabled(true); 209 fInstallTypes->SetEnabled(true); 210 fDestination->SetEnabled(true); 211 fInstallProcess.Stop(); 212 break; 213 } 214 case P_MSG_I_ERROR: 215 { 216 BAlert *notify = new BAlert("installation_failed", // TODO: Review this 217 T("The requested package failed to install on your system. This " 218 "might be a problem with the target package file. Please consult " 219 "this issue with the package distributor."), T("OK"), NULL, 220 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 221 fprintf(stderr, "Error while installing the package\n"); 222 notify->Go(); 223 fStatusWindow->Hide(); 224 fInstall->SetEnabled(true); 225 fInstallTypes->SetEnabled(true); 226 fDestination->SetEnabled(true); 227 fInstallProcess.Stop(); 228 break; 229 } 230 case P_MSG_STOP: 231 { 232 // This message is sent to us by the PackageStatus window, informing 233 // user interruptions. 234 // We actually use this message only when a post installation script 235 // is running and we want to kill it while it's still running 236 fStatusWindow->Hide(); 237 fInstall->SetEnabled(true); 238 fInstallTypes->SetEnabled(true); 239 fDestination->SetEnabled(true); 240 fInstallProcess.Stop(); 241 break; 242 } 207 243 case B_REFS_RECEIVED: 208 244 { 209 245 entry_ref ref; … … 247 283 } 248 284 249 285 250 status_t 251 PackageView::I nstall()286 int32 287 PackageView::ItemExists(PackageItem &item, BPath &path, int32 &policy) 252 288 { 253 pkg_profile *type = static_cast<pkg_profile *>(fInfo.GetProfile(fCurrentType)); 254 uint32 n = type->items.CountItems(); 289 int32 choice = P_EXISTS_NONE; 255 290 256 fStatusWindow->Reset(n + 4); 291 switch (policy) { 292 case P_EXISTS_OVERWRITE: 293 choice = P_EXISTS_OVERWRITE; 294 break; 257 295 258 fStatusWindow->StageStep(1, "Preparing package"); 296 case P_EXISTS_SKIP: 297 choice = P_EXISTS_SKIP; 298 break; 259 299 260 InstalledPackageInfo packageInfo(fInfo.GetName(), fInfo.GetVersion()); 300 case P_EXISTS_ASK: 301 case P_EXISTS_NONE: 302 { 303 BString alertString = T("The "); 261 304 262 status_t err = packageInfo.InitCheck(); 263 err = B_ENTRY_NOT_FOUND; 264 if (err == B_OK) { 265 // The package is already installed, inform the user 266 BAlert *reinstall = new BAlert("reinstall", 267 T("The given package seems to be already installed on your system. " 268 "Would you like to uninstall the existing one and continue the " 269 "installation?"), T("Continue"), T("Abort")); 305 alertString << item.ItemKind() << T(" named \'") << path.Leaf() << "\' "; 306 alertString << T("already exists in the given path.\nReplace the file with " 307 "the one from this package or skip it?"); 270 308 271 if (reinstall->Go() == 0) { 272 // Uninstall the package 273 err = packageInfo.Uninstall(); 274 if (err != B_OK) { 275 fprintf(stderr, "Error on uninstall\n"); 276 return err; 277 } 309 BAlert *alert = new BAlert(T("file_exists"), alertString.String(), 310 T("Replace"), T("Skip"), T("Abort")); 278 311 279 err = packageInfo.SetTo(fInfo.GetName(), fInfo.GetVersion(), true); 280 if (err != B_OK) { 281 fprintf(stderr, "Error on SetTo\n"); 282 return err; 312 choice = alert->Go(); 313 switch (choice) { 314 case 0: 315 choice = P_EXISTS_OVERWRITE; 316 break; 317 case 1: 318 choice = P_EXISTS_SKIP; 319 break; 320 default: 321 return P_EXISTS_ABORT; 283 322 } 284 }285 else {286 // Abort the installation287 return B_FILE_EXISTS;288 }289 }290 else if (err == B_ENTRY_NOT_FOUND) {291 err = packageInfo.SetTo(fInfo.GetName(), fInfo.GetVersion(), true);292 if (err != B_OK) {293 fprintf(stderr, "Error on SetTo\n");294 return err;295 }296 }297 else if (fStatusWindow->Stopped())298 return B_FILE_EXISTS;299 else {300 fprintf(stderr, "returning on error\n");301 return err;302 }303 323 304 fStatusWindow->StageStep(1, "Installing files and folders"); 324 if (policy == P_EXISTS_NONE) { 325 // TODO: Maybe add 'No, but ask again' type of choice as well? 326 alertString = T("Do you want to remember this decision for the rest of " 327 "this installation?\nAll existing files will be "); 328 alertString << ((choice == P_EXISTS_OVERWRITE) 329 ? T("replaced?") : T("skipped?")); 305 330 306 // Install files and directories 307 PackageItem *iter; 308 ItemState state; 309 uint32 i; 310 int32 choice; 311 BString label; 331 alert = new BAlert(T("policy_decision"), alertString.String(), 332 T("Yes"), T("No")); 312 333 313 packageInfo.SetName(fInfo.GetName()); 314 // TODO: Here's a small problem, since right now it's not quite sure 315 // which description is really used as such. The one displayed on 316 // the installer is mostly package installation description, but 317 // most people use it for describing the application in more detail 318 // then in the short description. 319 // For now, we'll use the short description if possible. 320 BString description = fInfo.GetShortDescription(); 321 if (description.Length() <= 0) 322 description = fInfo.GetDescription(); 323 packageInfo.SetDescription(description.String()); 324 packageInfo.SetSpaceNeeded(type->space_needed); 325 326 fItemExistsPolicy = P_EXISTS_NONE; 327 328 for (i = 0; i < n; i++) { 329 state.Reset(fItemExistsPolicy); // Reset the current item state 330 iter = static_cast<PackageItem *>(type->items.ItemAt(i)); 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); 334 int32 decision = alert->Go(); 335 if (decision == 0) 336 policy = choice; 337 else 338 policy = P_EXISTS_ASK; 340 339 } 340 break; 341 341 } 342 343 if (err != B_OK) {344 fprintf(stderr, "Error while writing path %s\n", fCurrentPath.Path());345 return err;346 }347 348 if (fStatusWindow->Stopped())349 return B_FILE_EXISTS;350 label = "";351 label << (uint32)(i + 1) << " of " << (uint32)n;352 fStatusWindow->StageStep(1, NULL, label.String());353 354 packageInfo.AddItem(state.destination.Path());355 342 } 356 343 357 fStatusWindow->StageStep(1, "Finishing installation", ""); 358 359 err = packageInfo.Save(); 360 if (err != B_OK) 361 return err; 362 363 fStatusWindow->StageStep(1, "Done"); 364 365 return B_OK; 344 return choice; 366 345 } 367 346 368 347 … … 550 529 } 551 530 552 531 553 int32554 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.\nReplace the file with "574 "the one from this package or skip it?");575 576 BAlert *alert = new BAlert(T("file_exists"), alertString.String(),577 T("Replace"), T("Skip"), 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 // TODO: Maybe add 'No, but ask again' type of choice as well?593 alertString = T("Do you want to remember this decision for the rest of "594 "this installation?\nAll existing files will be ");595 alertString << ((choice == P_EXISTS_OVERWRITE)596 ? T("replaced?") : T("skipped?"));597 598 alert = new BAlert(T("policy_decision"), alertString.String(),599 T("Yes"), T("No"));600 601 int32 decision = alert->Go();602 if (decision == 0)603 fItemExistsPolicy = choice;604 else605 fItemExistsPolicy = P_EXISTS_ASK;606 }607 break;608 }609 }610 611 return choice;612 }613 614 615 532 status_t 616 533 PackageView::_GroupChanged(int32 index) 617 534 { -
PackageInstall.h
1 /* 2 * Copyright (c) 2010, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Author: 6 * Łukasz 'Sil2100' Zemczak <sil2100@vexillium.org> 7 */ 8 #ifndef PACKAGE_INSTALL_H 9 #define PACKAGE_INSTALL_H 10 11 #include <Locker.h> 12 13 class PackageView; 14 class PackageScript; 15 16 enum { 17 P_MSG_I_FINISHED = 'pifi', 18 P_MSG_I_ABORT = 'piab', 19 P_MSG_I_ERROR = 'pier' 20 }; 21 22 class PackageInstall { 23 public: 24 PackageInstall(PackageView *parent); 25 ~PackageInstall(); 26 27 status_t Start(); 28 void Stop(); 29 status_t Install(); 30 31 private: 32 PackageView *fParent; 33 thread_id fThreadId; 34 BLocker fIdLocker; 35 36 PackageScript *fCurrentScript; 37 BLocker fCurrentScriptLocker; // XXX: will we need this? 38 int32 fItemExistsPolicy; 39 }; 40 41 #endif -
PackageView.h
10 10 11 11 12 12 #include "PackageInfo.h" 13 #include "PackageInstall.h" 13 14 #include "PackageStatus.h" 14 15 15 #include <View.h>16 16 #include <Box.h> 17 17 #include <Button.h> 18 #include <FilePanel.h> 19 #include <Locker.h> 18 20 #include <MenuField.h> 19 #include < FilePanel.h>21 #include <View.h> 20 22 21 23 class BPopUpMenu; 22 24 class BTextView; … … 37 39 void AttachedToWindow(); 38 40 void MessageReceived(BMessage *msg); 39 41 40 status_t Install();42 int32 ItemExists(PackageItem &item, BPath &path, int32 &policy); 41 43 44 BPath *GetCurrentPath() { return &fCurrentPath; } 45 PackageInfo *GetPackageInfo() { return &fInfo; } 46 uint32 GetCurrentType() { return fCurrentType; } 47 PackageStatus *GetStatusWindow() { return fStatusWindow; } 48 42 49 private: 43 50 void _InitView(); 44 51 void _InitProfiles(); 45 int32 _ItemExists(PackageItem &item, BPath &path);46 52 47 53 status_t _GroupChanged(int32 index); 48 54 … … 55 61 BFilePanel *fOpenPanel; 56 62 BPath fCurrentPath; 57 63 uint32 fCurrentType; 58 int32 fItemExistsPolicy;59 64 60 65 PackageInfo fInfo; 61 66 PackageStatus *fStatusWindow; 67 PackageInstall fInstallProcess; 62 68 }; 63 69 64 70 #endif // PACKAGE_VIEW_H