Ticket #3762: script.patch

File script.patch, 35.9 KB (added by sil2100, 14 years ago)

Patch fixing the invalid script file handling + some other modifications.

  • 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);
  • 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
  • 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
  • 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        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
     567const char*
     568PackageScript::ItemKind()
     569{
     570    return "script";
     571}
     572
     573
     574status_t
     575PackageScript::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
     642status_t
     643PackageScript::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
    428701// #pragma mark - PackageDirectory
    429702
    430703
     
    437710
    438711
    439712status_t
    440 PackageDirectory::WriteToPath(const char *path, ItemState *state)
     713PackageDirectory::DoInstall(const char *path, ItemState *state)
    441714{
    442715    BPath &destination = state->destination;
    443716    status_t ret;
    444     parser_debug("Directory: %s WriteToPath() called!\n", fPath.String());
     717    parser_debug("Directory: %s DoInstall() called!\n", fPath.String());
    445718
    446719    ret = InitPath(path, &destination);
    447720    parser_debug("Ret: %d %s\n", ret, strerror(ret));
     
    499772
    500773
    501774status_t
    502 PackageFile::WriteToPath(const char *path, ItemState *state)
     775PackageFile::DoInstall(const char *path, ItemState *state)
    503776{
    504777    if (state == NULL)
    505778        return B_ERROR;
    506779
    507780    BPath &destination = state->destination;
    508781    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());
    510783
    511784    BFile file;
    512785    if (state->status == B_NO_INIT || destination.InitCheck() != B_OK) {
     
    661934
    662935
    663936status_t
    664 PackageLink::WriteToPath(const char *path, ItemState *state)
     937PackageLink::DoInstall(const char *path, ItemState *state)
    665938{
    666939    if (state == NULL)
    667940        return B_ERROR;
    668941
    669942    status_t ret = B_OK;
    670943    BSymLink symlink;
    671     parser_debug("Symlink: %s WriteToPath() called!\n", fPath.String());
     944    parser_debug("Symlink: %s DoInstall() called!\n", fPath.String());
    672945
    673946    BPath &destination = state->destination;
    674947    BDirectory *dir = &state->parent;
  • 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
  • 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                                uint8 **script, 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
  • 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    return install->Install();
     31}
     32
     33
     34PackageInstall::PackageInstall(PackageView *parent)
     35    : fParent(parent),
     36    fThreadId(-1)
     37{
     38}
     39
     40
     41PackageInstall::~PackageInstall()
     42{
     43}
     44
     45
     46status_t
     47PackageInstall::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
     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
     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
     96status_t
     97PackageInstall::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

     
    1111    PackageView.cpp
    1212    PackageInfo.cpp
    1313    PackageItem.cpp
     14    PackageInstall.cpp
    1415    PackageStatus.cpp
    1516    PackageTextViewer.cpp
    1617    PackageImageViewer.cpp
  • 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{
  • 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        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

     
    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>
     19#include <Locker.h>
    1820#include <MenuField.h>
    19 #include <FilePanel.h>
     21#include <View.h>
    2022
    2123class BPopUpMenu;
    2224class BTextView;
     
    3739        void AttachedToWindow();
    3840        void MessageReceived(BMessage *msg);
    3941
    40         status_t Install();
     42        int32 ItemExists(PackageItem &item, BPath &path, int32 &policy);
    4143
     44        BPath *GetCurrentPath()          { return &fCurrentPath; }
     45        PackageInfo *GetPackageInfo()    { return &fInfo; }
     46        uint32 GetCurrentType()          { return fCurrentType; }
     47        PackageStatus *GetStatusWindow() { return fStatusWindow; }
     48
    4249    private:
    4350        void _InitView();
    4451        void _InitProfiles();
    45         int32 _ItemExists(PackageItem &item, BPath &path);
    4652
    4753        status_t _GroupChanged(int32 index);
    4854
     
    5561        BFilePanel *fOpenPanel;
    5662        BPath fCurrentPath;
    5763        uint32 fCurrentType;
    58         int32 fItemExistsPolicy;
    5964
    6065        PackageInfo fInfo;
    6166        PackageStatus *fStatusWindow;
     67        PackageInstall fInstallProcess;
    6268};
    6369
    6470#endif  // PACKAGE_VIEW_H