Ticket #3762: fixed_script.patch

File fixed_script.patch, 36.4 KB (added by sil2100, 14 years ago)

Fixed according to the notes provided by korli, thanks! Also fixed something I forgot about earlier. (v3)

  • src/apps/packageinstaller/PackageStatus.cpp

     
    9292
    9393
    9494PackageStatus::PackageStatus(const char *title, const char *label,
    95         const char *trailing)
     95        const char *trailing, BHandler *parent)
    9696    :   BWindow(BRect(200, 200, 550, 255), title, B_TITLED_WINDOW,
    9797            B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE, 0),
    98     fIsStopped(false)
     98    fIsStopped(false),
     99    fParent(parent)
    99100{
    100101    SetLayout(new BGroupLayout(B_VERTICAL));
    101102
     
    129130    switch (msg->what) {
    130131        case P_MSG_STOP:
    131132            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            }
    132140            break;
    133141        default:
    134142            BWindow::MessageReceived(msg);
  • src/apps/packageinstaller/PackageStatus.h

     
    3131class PackageStatus : public BWindow {
    3232    public:
    3333        PackageStatus(const char *title, const char *label = NULL,
    34                 const char *trailing = NULL);
     34                const char *trailing = NULL, BHandler *parent = NULL);
    3535        ~PackageStatus();
    3636       
    3737        void MessageReceived(BMessage *msg);
     
    4646        BStatusBar *fStatus;
    4747        StopButton *fButton;
    4848        bool fIsStopped;
     49        BHandler *fParent;
    4950};
    5051
    5152
  • src/apps/packageinstaller/PackageInfo.cpp

     
    3939    P_NONE = 0,
    4040    P_FILE,
    4141    P_DIRECTORY,
    42     P_LINK
     42    P_LINK,
     43    P_SCRIPT
    4344};
    4445
    4546
     
    8687        delete file;
    8788    }
    8889
     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
    8998    delete fPackageFile;
    9099}
    91100
     
    624633            RETURN_AND_SET_STATUS(B_ERROR);
    625634        }
    626635
    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
    635652
    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);
    651655        } 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);
    667657        } 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);
    684661        } else if (!memcmp(buffer, "Name", 5)) {
    685662            if (element == P_NONE) {
    686663                RETURN_AND_SET_STATUS(B_ERROR);
     
    795772            swap_data(B_UINT64_TYPE, &size, sizeof(uint64),
    796773                B_SWAP_BENDIAN_TO_HOST);
    797774        } 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) {
    799776                RETURN_AND_SET_STATUS(B_ERROR);
    800777            }
    801778
     
    1019996                    item = new PackageLink(fPackageFile, dest, linkString,
    1020997                        localType, ctime, mtime, mode, offset, size);
    1021998                }
     999            } else if (element == P_SCRIPT) {
     1000                fScripts.AddItem(new PackageScript(fPackageFile, offset, size,
     1001                    originalSize));
    10221002            } else {
    10231003                // If the directory tree count is equal to zero, this means all
    10241004                // directory trees have been closed and a padding sequence means the
  • src/apps/packageinstaller/PackageItem.cpp

     
    1616#include <Directory.h>
    1717#include <fs_info.h>
    1818#include <NodeInfo.h>
     19#include <OS.h>
    1920#include <SymLink.h>
    2021#include <Volume.h>
    2122
     
    3738    P_ATTRIBUTE
    3839};
    3940
     41extern const char **environ;
    4042
     43
    4144status_t
    4245inflate_data(uint8 *in, uint32 inSize, uint8 *out, uint32 outSize)
    4346{
     47    parser_debug("inflate_data() called - input_size: %ld, output_size: %ld\n",
     48        inSize, outSize);
    4449    z_stream stream;
    4550    stream.zalloc = Z_NULL;
    4651    stream.zfree = Z_NULL;
     
    375380
    376381
    377382status_t
     383PackageItem::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
     443status_t
    378444PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
    379445    bool *done)
    380446{
     
    425491}
    426492
    427493
     494// #pragma mark - PackageScript
     495
     496
     497PackageScript::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
     507status_t
     508PackageScript::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        while (fPackage->Read(buffer, 7) == 7) {
     530            if (!memcmp(buffer, "FBeA", 5)) {
     531                parser_debug("-> Attribute\n");
     532                section = P_ATTRIBUTE;
     533                continue;
     534            } else if (!memcmp(buffer, "FiDa", 5)) {
     535                parser_debug("-> File data\n");
     536                section = P_DATA;
     537                continue;
     538            }
     539
     540            switch (section) {
     541                case P_ATTRIBUTE:
     542                    ret = SkipAttribute(buffer, &attrStarted, &done);
     543                    break;
     544
     545                case P_DATA:
     546                    ret = _ParseScript(buffer, fOriginalSize, &done);
     547                    break;
     548
     549                default:
     550                    return B_ERROR;
     551            }
     552
     553            if (ret != B_OK || done)
     554                break;
     555        }
     556    }
     557
     558    parser_debug("Ret: %d %s\n", ret, strerror(ret));
     559    return ret;
     560}
     561
     562
     563const char*
     564PackageScript::ItemKind()
     565{
     566    return "script";
     567}
     568
     569
     570status_t
     571PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, bool *done)
     572{
     573    status_t ret = B_OK;
     574
     575    if (!memcmp(buffer, "FiMF", 5)) {
     576        parser_debug(" Found file (script) data.\n");
     577        uint64 compressed, original;
     578        fPackage->Read(&compressed, 8);
     579        swap_data(B_UINT64_TYPE, &compressed, sizeof(uint64),
     580                B_SWAP_BENDIAN_TO_HOST);
     581
     582        fPackage->Read(&original, 8);
     583        swap_data(B_UINT64_TYPE, &original, sizeof(uint64),
     584                B_SWAP_BENDIAN_TO_HOST);
     585        parser_debug(" Still good... (%llu : %llu)\n", original,
     586                originalSize);
     587
     588        if (original != originalSize) {
     589            parser_debug(" File size mismatch\n");
     590            return B_ERROR; // File size mismatch
     591        }
     592        parser_debug(" Still good...\n");
     593
     594        if (fPackage->Read(buffer, 4) != 4) {
     595            parser_debug(" Read(buffer, 4) failed\n");
     596            return B_ERROR;
     597        }
     598        parser_debug(" Still good...\n");
     599
     600        uint8 *temp = new uint8[compressed];
     601        if (fPackage->Read(temp, compressed) != compressed) {
     602            parser_debug(" Read(temp, compressed) failed\n");
     603            delete[] temp;
     604            return B_ERROR;
     605        }
     606
     607        uint8 *script = new uint8[original];
     608        ret = inflate_data(temp, compressed, script, original);
     609        if (ret != B_OK) {
     610            parser_debug(" inflate_data failed\n");
     611            delete[] temp;
     612            delete[] script;
     613            return ret;
     614        }
     615
     616        ret = _RunScript(script, originalSize);
     617        delete[] script;
     618        delete[] temp;
     619        parser_debug(" Script data inflation complete!\n");
     620    } else if (!memcmp(buffer, padding, 7)) {
     621        *done = true;
     622        return ret;
     623    } else {
     624        parser_debug("_ParseData unknown tag\n");
     625        ret = B_ERROR;
     626    }
     627
     628    return ret;
     629}
     630
     631
     632status_t
     633PackageScript::_RunScript(uint8 *script, uint32 len)
     634{
     635    // This function written by Peter Folk <pfolk@uni.uiuc.edu>
     636    // and published in the BeDevTalk FAQ, modified for use in the
     637    // PackageInstaller
     638    // http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209
     639
     640    // Save current FDs
     641    int old_in  =  dup(0);
     642    int old_out  =  dup(1);
     643    int old_err  =  dup(2);
     644
     645    int filedes[2];
     646
     647    /* Create new pipe FDs as stdin, stdout, stderr */
     648    pipe(filedes);  dup2(filedes[0], 0); close(filedes[0]);
     649    int in = filedes[1];  // Write to in, appears on cmd's stdin
     650    pipe(filedes);  dup2(filedes[1], 1); close(filedes[1]);
     651    pipe(filedes);  dup2(filedes[1], 2); close(filedes[1]);
     652
     653    const char **argv = new const char * [3];
     654    argv[0] = strdup("/bin/sh");
     655    argv[1] = strdup("-s");
     656    argv[2] = NULL;
     657
     658    // "load" command.
     659    fThreadId = load_image(2, argv, environ);
     660
     661    int i;
     662    for (i = 0; i < 2; i++)
     663        delete argv[i];
     664    delete [] argv;
     665
     666    if (fThreadId < B_OK)
     667        return fThreadId;
     668
     669    // thread id is now suspended.
     670    setpgid(fThreadId, fThreadId);
     671
     672    // Restore old FDs
     673    close(0); dup(old_in); close(old_in);
     674    close(1); dup(old_out); close(old_out);
     675    close(2); dup(old_err); close(old_err);
     676
     677    set_thread_priority(fThreadId, B_LOW_PRIORITY);
     678    resume_thread(fThreadId);
     679
     680    // Write the script
     681    if (write(in, script, len) != len || write(in, "\nexit\n", 6) != 6) {
     682        parser_debug("Writing script failed\n");
     683        kill_thread(fThreadId);
     684        return B_ERROR;
     685    }
     686
     687    return B_OK;
     688}
     689
     690
    428691// #pragma mark - PackageDirectory
    429692
    430693
     
    437700
    438701
    439702status_t
    440 PackageDirectory::WriteToPath(const char *path, ItemState *state)
     703PackageDirectory::DoInstall(const char *path, ItemState *state)
    441704{
    442705    BPath &destination = state->destination;
    443706    status_t ret;
    444     parser_debug("Directory: %s WriteToPath() called!\n", fPath.String());
     707    parser_debug("Directory: %s DoInstall() called!\n", fPath.String());
    445708
    446709    ret = InitPath(path, &destination);
    447710    parser_debug("Ret: %d %s\n", ret, strerror(ret));
     
    499762
    500763
    501764status_t
    502 PackageFile::WriteToPath(const char *path, ItemState *state)
     765PackageFile::DoInstall(const char *path, ItemState *state)
    503766{
    504767    if (state == NULL)
    505768        return B_ERROR;
    506769
    507770    BPath &destination = state->destination;
    508771    status_t ret = B_OK;
    509     parser_debug("File: %s WriteToPath() called!\n", fPath.String());
     772    parser_debug("File: %s DoInstall() called!\n", fPath.String());
    510773
    511774    BFile file;
    512775    if (state->status == B_NO_INIT || destination.InitCheck() != B_OK) {
     
    661924
    662925
    663926status_t
    664 PackageLink::WriteToPath(const char *path, ItemState *state)
     927PackageLink::DoInstall(const char *path, ItemState *state)
    665928{
    666929    if (state == NULL)
    667930        return B_ERROR;
    668931
    669932    status_t ret = B_OK;
    670933    BSymLink symlink;
    671     parser_debug("Symlink: %s WriteToPath() called!\n", fPath.String());
     934    parser_debug("Symlink: %s DoInstall() called!\n", fPath.String());
    672935
    673936    BPath &destination = state->destination;
    674937    BDirectory *dir = &state->parent;
  • src/apps/packageinstaller/PackageInfo.h

     
    3333        BMallocIO *GetSplashScreen() { return fHasImage ? &fImage : NULL; }
    3434        int32 GetProfileCount() { return fProfiles.CountItems(); }
    3535        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)); }
    3638       
    3739        status_t Parse();
    3840        status_t InitCheck() { return fStatus; }
     
    5658        bool fHasImage;
    5759
    5860        BList fFiles; // Holds all files in the package
     61        BList fScripts;
    5962};
    6063
    6164
  • src/apps/packageinstaller/PackageItem.h

     
    7272                                uint64 offset = 0, uint64 size = 0);
    7373    virtual                 ~PackageItem();
    7474
    75     virtual status_t        WriteToPath(const char* path = NULL,
     75    virtual status_t        DoInstall(const char* path = NULL,
    7676                                ItemState *state = NULL) = 0;
    7777    virtual void            SetTo(BFile* parent, const BString& path,
    7878                                uint8 type, uint32 ctime, uint32 mtime,
    7979                                uint64 offset = 0, uint64 size = 0);
    8080    virtual const char*     ItemKind() = 0;
    8181
    82 protected:
     82    protected:
    8383            status_t        InitPath(const char* path, BPath* destination);
    8484            status_t        HandleAttributes(BPath* destination, BNode* node,
    8585                                const char* header);
     
    9191                                uint64* tempSize, uint64* attrCSize,
    9292                                uint64* attrOSize, bool* attrStarted,
    9393                                bool* done);
     94            status_t        SkipAttribute(uint8 *buffer, bool *attrStarted,
     95                                bool *done);
    9496            status_t        ParseData(uint8* buffer, BFile* file,
    9597                                uint64 originalSize, bool* done);
    9698
     
    111113                                uint8 type, uint32 ctime, uint32 mtime,
    112114                                uint64 offset = 0, uint64 size = 0);
    113115
    114     virtual status_t        WriteToPath(const char* path = NULL,
     116    virtual status_t        DoInstall(const char* path = NULL,
    115117                                ItemState *state = NULL);
    116118    virtual const char*     ItemKind();
    117119};
    118120
    119121
     122class PackageScript : public PackageItem {
     123public:
     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
     134private:
     135            status_t        _ParseScript(uint8 *buffer, uint64 originalSize,
     136                                bool *done);
     137            status_t        _RunScript(uint8 *script, uint32 len);
     138
     139            uint64          fOriginalSize;
     140            thread_id       fThreadId;
     141};
     142
     143
    120144class PackageFile : public PackageItem {
    121145public:
    122146                            PackageFile(BFile* parent, const BString& path,
     
    125149                                uint32 platform, const BString& mime,
    126150                                const BString& signature, uint32 mode);
    127151
    128     virtual status_t        WriteToPath(const char* path = NULL,
     152    virtual status_t        DoInstall(const char* path = NULL,
    129153                                ItemState *state = NULL);
    130154    virtual const char*     ItemKind();
    131155
     
    146170                                uint32 mtime, uint32 mode, uint64 offset = 0,
    147171                                uint64 size = 0);
    148172
    149     virtual status_t        WriteToPath(const char* path = NULL,
     173    virtual status_t        DoInstall(const char* path = NULL,
    150174                                ItemState *state = NULL);
    151175    virtual const char*     ItemKind();
    152176
  • src/apps/packageinstaller/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
     23static 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    install->Install();
     31    return 0;
     32}
     33
     34
     35PackageInstall::PackageInstall(PackageView *parent)
     36    : fParent(parent),
     37    fThreadId(-1)
     38{
     39}
     40
     41
     42PackageInstall::~PackageInstall()
     43{
     44}
     45
     46
     47status_t
     48PackageInstall::Start()
     49{
     50    status_t ret = B_OK;
     51
     52    fIdLocker.Lock();
     53    if (fThreadId > -1) {
     54        ret = B_BUSY;
     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
     66void
     67PackageInstall::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
     89void
     90PackageInstall::Install()
     91{
     92    // A message sending wrapper around _Install()
     93    uint32 msg = _Install();
     94    if (fParent && fParent->Looper())
     95        fParent->Looper()->PostMessage(new BMessage(msg), fParent);
     96}
     97
     98
     99uint32
     100PackageInstall::_Install()
     101{
     102    PackageInfo *info = fParent->GetPackageInfo();
     103    pkg_profile *type = static_cast<pkg_profile *>(info->GetProfile(fParent->GetCurrentType()));
     104    uint32 n = type->items.CountItems(), m = info->GetScriptCount();
     105
     106    PackageStatus *progress = fParent->GetStatusWindow();
     107    progress->Reset(n + m + 5);
     108
     109    progress->StageStep(1, T("Preparing package"));
     110
     111    InstalledPackageInfo packageInfo(info->GetName(), info->GetVersion());
     112
     113    status_t err = packageInfo.InitCheck();
     114    if (err == B_OK) {
     115        // The package is already installed, inform the user
     116        BAlert *reinstall = new BAlert("reinstall",
     117            T("The given package seems to be already installed on your system. "
     118                "Would you like to uninstall the existing one and continue the "
     119                "installation?"), T("Continue"), T("Abort"));
     120
     121        if (reinstall->Go() == 0) {
     122            // Uninstall the package
     123            err = packageInfo.Uninstall();
     124            if (err != B_OK) {
     125                fprintf(stderr, "Error on uninstall\n");
     126                return P_MSG_I_ERROR;
     127            }
     128
     129            err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true);
     130            if (err != B_OK) {
     131                fprintf(stderr, "Error on SetTo\n");
     132                return P_MSG_I_ERROR;
     133            }
     134        } else {
     135            // Abort the installation
     136            return P_MSG_I_ABORT;
     137        }
     138    } else if (err == B_ENTRY_NOT_FOUND) {
     139        err = packageInfo.SetTo(info->GetName(), info->GetVersion(), true);
     140        if (err != B_OK) {
     141            fprintf(stderr, "Error on SetTo\n");
     142            return P_MSG_I_ERROR;
     143        }
     144    } else if (progress->Stopped()) {
     145        return P_MSG_I_ABORT;
     146    } else {
     147        fprintf(stderr, "returning on error\n");
     148        return P_MSG_I_ERROR;
     149    }
     150
     151    progress->StageStep(1, T("Installing files and folders"));
     152
     153    // Install files and directories
     154    PackageItem *iter;
     155    ItemState state;
     156    uint32 i;
     157    int32 choice;
     158    BString label;
     159
     160    packageInfo.SetName(info->GetName());
     161    // TODO: Here's a small problem, since right now it's not quite sure
     162    //      which description is really used as such. The one displayed on
     163    //      the installer is mostly package installation description, but
     164    //      most people use it for describing the application in more detail
     165    //      then in the short description.
     166    //      For now, we'll use the short description if possible.
     167    BString description = info->GetShortDescription();
     168    if (description.Length() <= 0)
     169        description = info->GetDescription();
     170    packageInfo.SetDescription(description.String());
     171    packageInfo.SetSpaceNeeded(type->space_needed);
     172
     173    fItemExistsPolicy = P_EXISTS_NONE;
     174
     175    const char *installPath = fParent->GetCurrentPath()->Path();
     176    for (i = 0; i < n; i++) {
     177        state.Reset(fItemExistsPolicy); // Reset the current item state
     178        iter = static_cast<PackageItem *>(type->items.ItemAt(i));
     179
     180        err = iter->DoInstall(installPath, &state);
     181        if (err == B_FILE_EXISTS) {
     182            // Writing to path failed because path already exists - ask the user
     183            // what to do and retry the writing process
     184            choice = fParent->ItemExists(*iter, state.destination, fItemExistsPolicy);
     185            if (choice != P_EXISTS_ABORT) {
     186                state.policy = choice;
     187                err = iter->DoInstall(installPath, &state);
     188            }
     189        }
     190
     191        if (err != B_OK) {
     192            fprintf(stderr, "Error while writing path\n");
     193            return P_MSG_I_ERROR;
     194        }
     195
     196        if (progress->Stopped())
     197            return P_MSG_I_ABORT;
     198        label = "";
     199        label << (uint32)(i + 1) << " of " << (uint32)n;
     200        progress->StageStep(1, NULL, label.String());
     201
     202        packageInfo.AddItem(state.destination.Path());
     203    }
     204
     205    progress->StageStep(1, T("Running post-installation scripts"), "");
     206
     207    PackageScript *scr;
     208    status_t status;
     209    // Run all scripts
     210    for (i = 0; i < m; i++) {
     211        scr = info->GetScript(i);
     212
     213        fCurrentScriptLocker.Lock();
     214        fCurrentScript = scr;
     215
     216        if (scr->DoInstall() != B_OK) {
     217            fprintf(stderr, "Error while running script\n");
     218            return P_MSG_I_ERROR;
     219        }
     220        fCurrentScriptLocker.Unlock();
     221
     222        wait_for_thread(scr->GetThreadId(), &status);
     223        fCurrentScriptLocker.Lock();
     224        scr->SetThreadId(-1);
     225        fCurrentScript = NULL;
     226        fCurrentScriptLocker.Unlock();
     227
     228        if (progress->Stopped())
     229            return P_MSG_I_ABORT;
     230        label = "";
     231        label << (uint32)(i + 1) << " of " << (uint32)m;
     232        progress->StageStep(1, NULL, label.String());
     233    }
     234
     235    progress->StageStep(1, T("Finishing installation"), "");
     236
     237    err = packageInfo.Save();
     238    if (err != B_OK)
     239        return P_MSG_I_ERROR;
     240
     241    progress->StageStep(1, T("Done"));
     242
     243    // Inform our parent that we finished
     244    return P_MSG_I_FINISHED;
     245}
     246
  • src/apps/packageinstaller/Jamfile

     
    1111    PackageView.cpp
    1212    PackageInfo.cpp
    1313    PackageItem.cpp
     14    PackageInstall.cpp
    1415    PackageStatus.cpp
    1516    PackageTextViewer.cpp
    1617    PackageImageViewer.cpp
  • src/apps/packageinstaller/PackageView.cpp

     
    6363        //BView("package_view", B_WILL_DRAW, new BGroupLayout(B_HORIZONTAL)),
    6464    fOpenPanel(new BFilePanel(B_OPEN_PANEL, NULL, NULL,
    6565        B_DIRECTORY_NODE, false)),
    66     fInfo(ref)
     66    fInfo(ref),
     67    fInstallProcess(this)
    6768{
    6869    _InitView();
    6970
     
    121122        // attaching the view to the window
    122123        _GroupChanged(0);
    123124
    124         fStatusWindow = new PackageStatus(T("Installation progress"));
     125        fStatusWindow = new PackageStatus(T("Installation progress"), NULL, NULL,
     126                this);
    125127
    126128        // Show the splash screen, if present
    127129        BMallocIO *image = fInfo.GetSplashScreen();
     
    133135        // Show the disclaimer/info text popup, if present
    134136        BString disclaimer = fInfo.GetDisclaimer();
    135137        if (disclaimer.Length() != 0) {
    136             PackageTextViewer *text = new PackageTextViewer(disclaimer.String());
     138            PackageTextViewer *text = new PackageTextViewer(disclaimer.String());
    137139            int32 selection = text->Go();
    138140            // The user didn't accept our disclaimer, this means we cannot continue.
    139             if (selection == 0) {
     141            if (selection == 0) {
    140142                BWindow *parent = Window();
    141143                if (parent && parent->Lock())
    142144                    parent->Quit();
     
    153155        case P_MSG_INSTALL:
    154156        {
    155157            fInstall->SetEnabled(false);
     158            fInstallTypes->SetEnabled(false);
     159            fDestination->SetEnabled(false);
    156160            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"));
    163161
    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();
    186163            break;
    187164        }
    188165        case P_MSG_PATH_CHANGED:
     
    204181            }
    205182            break;
    206183        }
     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        }
    207243        case B_REFS_RECEIVED:
    208244        {
    209245            entry_ref ref;
     
    247283}
    248284
    249285
    250 status_t
    251 PackageView::Install()
     286int32
     287PackageView::ItemExists(PackageItem &item, BPath &path, int32 &policy)
    252288{
    253     pkg_profile *type = static_cast<pkg_profile *>(fInfo.GetProfile(fCurrentType));
    254     uint32 n = type->items.CountItems();
     289    int32 choice = P_EXISTS_NONE;
    255290
    256     fStatusWindow->Reset(n + 4);
     291    switch (policy) {
     292        case P_EXISTS_OVERWRITE:
     293            choice = P_EXISTS_OVERWRITE;
     294            break;
    257295
    258     fStatusWindow->StageStep(1, "Preparing package");
     296        case P_EXISTS_SKIP:
     297            choice = P_EXISTS_SKIP;
     298            break;
    259299
    260     InstalledPackageInfo packageInfo(fInfo.GetName(), fInfo.GetVersion());
     300        case P_EXISTS_ASK:
     301        case P_EXISTS_NONE:
     302        {
     303            BString alertString = T("The ");
    261304
    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?");
    270308
    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"));
    278311
    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;
    283322            }
    284         }
    285         else {
    286             // Abort the installation
    287             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     }
    303323
    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?"));
    305330
    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"));
    312333
    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;
    340339            }
     340            break;
    341341        }
    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());
    355342    }
    356343
    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;
    366345}
    367346
    368347
     
    550529}
    551530
    552531
    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.\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                 else
    605                     fItemExistsPolicy = P_EXISTS_ASK;
    606             }
    607             break;
    608         }
    609     }
    610 
    611     return choice;
    612 }
    613 
    614 
    615532status_t
    616533PackageView::_GroupChanged(int32 index)
    617534{
  • src/apps/packageinstaller/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
     13class PackageView;
     14class PackageScript;
     15
     16enum {
     17    P_MSG_I_FINISHED = 'pifi',
     18    P_MSG_I_ABORT = 'piab',
     19    P_MSG_I_ERROR = 'pier'
     20};
     21
     22class PackageInstall {
     23    public:
     24        PackageInstall(PackageView *parent);
     25        ~PackageInstall();
     26
     27        status_t Start();
     28        void Stop();
     29        void Install();
     30
     31    private:
     32        uint32 _Install();
     33
     34        PackageView *fParent;
     35        thread_id fThreadId;
     36        BLocker fIdLocker;
     37
     38        PackageScript *fCurrentScript;
     39        BLocker fCurrentScriptLocker; // XXX: will we need this?
     40        int32 fItemExistsPolicy;
     41};
     42
     43#endif
  • src/apps/packageinstaller/PackageView.h

     
    1010
    1111
    1212#include "PackageInfo.h"
     13#include "PackageInstall.h"
    1314#include "PackageStatus.h"
    1415
    15 #include <View.h>
    1616#include <Box.h>
    1717#include <Button.h>
     18#include <FilePanel.h>
    1819#include <MenuField.h>
    19 #include <FilePanel.h>
     20#include <View.h>
    2021
    2122class BPopUpMenu;
    2223class BTextView;
     
    3738        void AttachedToWindow();
    3839        void MessageReceived(BMessage *msg);
    3940
    40         status_t Install();
     41        int32 ItemExists(PackageItem &item, BPath &path, int32 &policy);
    4142
     43        BPath *GetCurrentPath()          { return &fCurrentPath; }
     44        PackageInfo *GetPackageInfo()    { return &fInfo; }
     45        uint32 GetCurrentType()          { return fCurrentType; }
     46        PackageStatus *GetStatusWindow() { return fStatusWindow; }
     47
    4248    private:
    4349        void _InitView();
    4450        void _InitProfiles();
    45         int32 _ItemExists(PackageItem &item, BPath &path);
    4651
    4752        status_t _GroupChanged(int32 index);
    4853
     
    5560        BFilePanel *fOpenPanel;
    5661        BPath fCurrentPath;
    5762        uint32 fCurrentType;
    58         int32 fItemExistsPolicy;
    5963
    6064        PackageInfo fInfo;
    6165        PackageStatus *fStatusWindow;
     66        PackageInstall fInstallProcess;
    6267};
    6368
    6469#endif  // PACKAGE_VIEW_H