Ticket #4059: remember_filereplace_fix_2.diff

File remember_filereplace_fix_2.diff, 15.3 KB (added by sil2100, 15 years ago)

Second revision of the patch

  • src/apps/packageinstaller/PackageItem.cpp

     
    1919#include <fs_info.h>
    2020#include "zlib.h"
    2121
     22#include <string.h>
     23
    2224// Macro reserved for later localization
    2325#define T(x) x
    2426
     
    160162}
    161163
    162164
    163 int32
    164 PackageItem::ItemExists(const char *name)
    165 {
    166     // TODO: this function doesn't really fit in, the GUI should be separated
    167     // from the package engine completely
    168 
    169     BString alertString = "The ";
    170 
    171     alertString << ItemKind() << " named \'" << name << "\' ";
    172     alertString << T("already exists in the given path. Should I replace "
    173         "the existing file with the one from this package?");
    174 
    175     BAlert *alert = new BAlert(T("file_exists"), alertString.String(),
    176         T("Yes"), T("No"), T("Abort"));
    177 
    178     return alert->Go();
    179 }
    180 
    181 
    182165status_t
    183166PackageItem::InitPath(const char *path, BPath *destination)
    184167{
     
    452435
    453436
    454437status_t
    455 PackageDirectory::WriteToPath(const char *path, BPath *final)
     438PackageDirectory::WriteToPath(const char *path, ItemState *state)
    456439{
    457     BPath destination;
     440    BPath *destination = &(state->destination);
    458441    status_t ret;
    459442    parser_debug("Directory: %s WriteToPath() called!\n", fPath.String());
    460443
    461     ret = InitPath(path, &destination);
     444    ret = InitPath(path, destination);
     445    parser_debug("Ret: %d %s\n", ret, strerror(ret));
    462446    if (ret != B_OK)
    463447        return ret;
    464448
    465449    // Since Haiku is single-user right now, we give the newly
    466450    // created directory default permissions
    467     ret = create_directory(destination.Path(), kDefaultMode);
     451    ret = create_directory(destination->Path(), kDefaultMode);
     452    parser_debug("Create dir ret: %d %s\n", ret, strerror(ret));
    468453    if (ret != B_OK)
    469454        return ret;
    470     BDirectory dir(destination.Path());
     455    BDirectory dir(destination->Path());
    471456    parser_debug("Directory created!\n");
    472457
    473458    if (fCreationTime)
     
    479464    // Since directories can only have attributes in the offset section,
    480465    // we can check here whether it is necessary to continue
    481466    if (fOffset)
    482         ret = HandleAttributes(&destination, &dir, "FoDa");
    483    
    484     if (final)
    485         *final = destination;
     467        ret = HandleAttributes(destination, &dir, "FoDa");
    486468
     469    parser_debug("Ret: %d %s\n", ret, strerror(ret));
    487470    return ret;
    488471}
    489472
     
    513496
    514497
    515498status_t
    516 PackageFile::WriteToPath(const char *path, BPath *final)
     499PackageFile::WriteToPath(const char *path, ItemState *state)
    517500{
    518     BPath destination;
    519     status_t ret;
     501    BFile file;
     502
     503    if (state == NULL)
     504        return B_ERROR;
     505
     506    BPath *destination = &(state->destination);
     507    status_t ret = B_OK;
    520508    parser_debug("File: %s WriteToPath() called!\n", fPath.String());
    521509
    522     ret = InitPath(path, &destination);
    523     if (ret != B_OK)
    524         return ret;
     510    if (state->status == B_NO_INIT || destination->InitCheck() != B_OK) {
     511        ret = InitPath(path, destination);
     512        if (ret != B_OK)
     513            return ret;
    525514
    526     BFile file(destination.Path(),
    527         B_WRITE_ONLY | B_CREATE_FILE | B_FAIL_IF_EXISTS);
    528     ret = file.InitCheck();
    529     if (ret == B_FILE_EXISTS) {
    530         int32 selection = ItemExists(destination.Leaf());
    531         switch (selection) {
    532             case 0:
    533                 ret = file.SetTo(destination.Path(),
     515        ret = file.SetTo(destination->Path(),
     516            B_WRITE_ONLY | B_CREATE_FILE | B_FAIL_IF_EXISTS);
     517        if (ret == B_ENTRY_NOT_FOUND) {
     518            BPath directory;
     519            destination->GetParent(&directory);
     520            if (create_directory(directory.Path(), kDefaultMode) != B_OK)
     521                return B_ERROR;
     522
     523            ret = file.SetTo(destination->Path(), B_WRITE_ONLY | B_CREATE_FILE);
     524        } else if (ret == B_FILE_EXISTS)
     525            state->status = B_FILE_EXISTS;
     526
     527        if (ret != B_OK)
     528            return ret;
     529    }
     530
     531    if (state->status == B_FILE_EXISTS) {
     532        switch (state->policy) {
     533            case P_EXISTS_OVERWRITE:
     534                ret = file.SetTo(destination->Path(),
    534535                    B_WRITE_ONLY | B_ERASE_FILE);
    535                 if (ret != B_OK)
    536                     return ret;
    537536                break;
    538             case 1:
     537
     538            case P_EXISTS_NONE:
     539            case P_EXISTS_ASK:
     540                ret = B_FILE_EXISTS;
     541                break;
     542
     543            case P_EXISTS_SKIP:
    539544                return B_OK;
    540             default:
    541                 return B_FILE_EXISTS;
    542545        }
    543     } else if (ret == B_ENTRY_NOT_FOUND) {
    544         BPath directory;
    545         destination.GetParent(&directory);
    546         if (create_directory(directory.Path(), kDefaultMode) != B_OK)
    547             return B_ERROR;
     546    }
    548547
    549         ret = file.SetTo(destination.Path(), B_WRITE_ONLY | B_CREATE_FILE);
    550         if (ret != B_OK)
    551             return ret;
    552     } else if (ret != B_OK)
     548    if (ret != B_OK)
    553549        return ret;
    554550
    555551    parser_debug(" File created!\n");
     
    637633        delete[] temp;
    638634    }
    639635
    640     if (final)
    641         *final = destination;
    642 
    643636    return ret;
    644637}
    645638
     
    665658
    666659
    667660status_t
    668 PackageLink::WriteToPath(const char *path, BPath *final)
     661PackageLink::WriteToPath(const char *path, ItemState *state)
    669662{
     663    if (state == NULL)
     664        return B_ERROR;
     665
     666    status_t ret = B_OK;
     667    BSymLink symlink;
    670668    parser_debug("Symlink: %s WriteToPath() called!\n", fPath.String());
    671669
    672     BPath destination;
    673     status_t ret = InitPath(path, &destination);
    674     if (ret != B_OK)
    675         return ret;
     670    BPath *destination = &(state->destination);
     671    BDirectory *dir = &(state->parent);
    676672
    677     BString linkName(destination.Leaf());
    678     parser_debug("%s:%s:%s\n", fPath.String(), destination.Path(),
    679         linkName.String());
     673    if (state->status == B_NO_INIT || destination->InitCheck() != B_OK
     674        || dir->InitCheck() != B_OK) {
     675        // Not yet initialized
     676        ret = InitPath(path, destination);
     677        if (ret != B_OK)
     678            return ret;
    680679
    681     BPath dirPath;
    682     ret = destination.GetParent(&dirPath);
    683     BDirectory dir(dirPath.Path());
     680        BString linkName(destination->Leaf());
     681        parser_debug("%s:%s:%s\n", fPath.String(), destination->Path(),
     682            linkName.String());
    684683
    685     ret = dir.InitCheck();
    686     if (ret == B_ENTRY_NOT_FOUND) {
    687         if ((ret = create_directory(dirPath.Path(), kDefaultMode)) != B_OK) {
    688             parser_debug("create_directory()) failed\n");
    689             return B_ERROR;
     684        BPath dirPath;
     685        ret = destination->GetParent(&dirPath);
     686        ret = dir->SetTo(dirPath.Path());
     687
     688        if (ret == B_ENTRY_NOT_FOUND) {
     689            if ((ret = create_directory(dirPath.Path(), kDefaultMode)) != B_OK) {
     690                parser_debug("create_directory()) failed\n");
     691                return B_ERROR;
     692            }
    690693        }
     694        if (ret != B_OK) {
     695            parser_debug("destination InitCheck failed %s for %s\n", strerror(ret), dirPath.Path());
     696            return ret;
     697        }
     698
     699        ret = dir->CreateSymLink(destination->Path(), fLink.String(), &symlink);
     700        if (ret == B_FILE_EXISTS) {
     701            // We need to check if the existing symlink is pointing at the same path
     702            // as our new one - if not, let's prompt the user
     703            symlink.SetTo(destination->Path());
     704            BPath oldLink;
     705
     706            ret = symlink.MakeLinkedPath(dir, &oldLink);
     707            chdir(dirPath.Path());
     708
     709            if (ret == B_BAD_VALUE || oldLink != fLink.String())
     710                state->status = ret = B_FILE_EXISTS;
     711            else
     712                ret = B_OK;
     713        }
    691714    }
    692     if (ret != B_OK) {
    693         parser_debug("destination InitCheck failed %s for %s\n", strerror(ret), dirPath.Path());
    694         return ret;
    695     }
    696715
    697     BSymLink symlink;
    698     ret = dir.CreateSymLink(destination.Path(), fLink.String(), &symlink);
    699     if (ret == B_FILE_EXISTS) {
    700         // We need to check if the existing symlink is pointing at the same path
    701         // as our new one - if not, let's prompt the user
    702         symlink.SetTo(destination.Path());
    703         BPath oldLink;
     716    if (state->status == B_FILE_EXISTS) {
     717        switch (state->policy) {
     718            case P_EXISTS_OVERWRITE:
     719            {
     720                BEntry entry;
     721                ret = entry.SetTo(destination->Path());
     722                if (ret != B_OK)
     723                    return ret;
    704724
    705         ret = symlink.MakeLinkedPath(&dir, &oldLink);
    706         chdir(dirPath.Path());
     725                entry.Remove();
     726                ret = dir->CreateSymLink(destination->Path(), fLink.String(),
     727                    &symlink);
     728                break;
     729            }
    707730
    708         if (ret == B_BAD_VALUE || oldLink != fLink.String()) {
    709             // The old symlink is different (or not a symlink) - ask the user
    710             int32 selection = ItemExists(destination.Leaf());
    711             switch (selection) {
    712                 case 0:
    713                 {
    714                     symlink.Unset();
    715                     BEntry entry;
    716                     ret = entry.SetTo(destination.Path());
    717                     if (ret != B_OK)
    718                         return ret;
     731            case P_EXISTS_NONE:
     732            case P_EXISTS_ASK:
     733                ret = B_FILE_EXISTS;
     734                break;
    719735
    720                     entry.Remove();
    721                     ret = dir.CreateSymLink(destination.Path(), fLink.String(),
    722                         &symlink);
    723                     break;
    724                 }
    725                 case 1:
    726                     parser_debug("Skipping already existent SymLink\n");
    727                     return B_OK;
    728                 default:
    729                     ret = B_FILE_EXISTS;
    730             }
    731         } else {
    732             ret = B_OK;
     736            case P_EXISTS_SKIP:
     737                return B_OK;
    733738        }
    734739    }
     740
    735741    if (ret != B_OK) {
    736742        parser_debug("CreateSymLink failed\n");
    737743        return ret;
     
    756762
    757763    if (fOffset) {
    758764        // Symlinks also seem to have attributes - so parse them
    759         ret = HandleAttributes(&destination, &symlink, "LnDa");
     765        ret = HandleAttributes(destination, &symlink, "LnDa");
    760766    }
    761767
    762     if (final) {
    763         *final = destination;
    764     }
    765 
    766768    return ret;
    767769}
    768770
  • src/apps/packageinstaller/PackageItem.h

     
    11/*
    2  * Copyright (c) 2007, Haiku, Inc.
     2 * Copyright (c) 2007-2009, Haiku, Inc.
    33 * Distributed under the terms of the MIT license.
    44 *
    55 * Author:
     
    1515#include <File.h>
    1616#include <Path.h>
    1717#include <String.h>
     18#include <Directory.h>
    1819
    1920
    2021// Local macro for the parser debug output
     
    3233    P_USER_PATH
    3334};
    3435
     36// Existant item overwriting policy of a single file
     37enum {
     38    P_EXISTS_ASK = 0,
     39    P_EXISTS_OVERWRITE,
     40    P_EXISTS_SKIP,
     41    P_EXISTS_ABORT,
     42    P_EXISTS_NONE
     43};
     44
    3545extern status_t inflate_data(uint8* in, uint32 inSize, uint8* out,
    3646    uint32 outSize);
    3747
    3848
     49struct ItemState {
     50    ItemState() : policy(P_EXISTS_NONE), status(B_NO_INIT) {}
     51    ~ItemState() {}
     52
     53    inline void Reset(int32 currentPolicy)
     54    {
     55        destination.Unset();
     56        parent.Unset();
     57        status = B_NO_INIT;
     58        policy = currentPolicy;
     59    }
     60
     61    BPath destination;
     62    BDirectory parent;
     63    uint8 policy;
     64    status_t status;
     65};
     66
     67
    3968class PackageItem {
    4069public:
    4170                            PackageItem(BFile* parent, const BString& path,
     
    4473    virtual                 ~PackageItem();
    4574
    4675    virtual status_t        WriteToPath(const char* path = NULL,
    47                                 BPath* final = NULL) = 0;
     76                                ItemState *state = NULL) = 0;
    4877    virtual void            SetTo(BFile* parent, const BString& path,
    4978                                uint8 type, uint32 ctime, uint32 mtime,
    5079                                uint64 offset = 0, uint64 size = 0);
     80    virtual const char*     ItemKind() = 0;
    5181
    5282protected:
    53     virtual const char*     ItemKind() = 0;
    54             int32           ItemExists(const char* name);
    5583            status_t        InitPath(const char* path, BPath* destination);
    5684            status_t        HandleAttributes(BPath* destination, BNode* node,
    5785                                const char* header);
     
    84112                                uint64 offset = 0, uint64 size = 0);
    85113
    86114    virtual status_t        WriteToPath(const char* path = NULL,
    87                                 BPath* final = NULL);
    88 
    89 protected:
     115                                ItemState *state = NULL);
    90116    virtual const char*     ItemKind();
    91117};
    92118
     
    100126                                const BString& signature, uint32 mode);
    101127
    102128    virtual status_t        WriteToPath(const char* path = NULL,
    103                                 BPath* final = NULL);
    104 
    105 protected:
     129                                ItemState *state = NULL);
    106130    virtual const char*     ItemKind();
    107131
    108132private:
     
    123147                                uint64 size = 0);
    124148
    125149    virtual status_t        WriteToPath(const char* path = NULL,
    126                                 BPath* final = NULL);
    127 
    128 protected:
     150                                ItemState *state = NULL);
    129151    virtual const char*     ItemKind();
    130152
    131153private:
  • src/apps/packageinstaller/PackageView.cpp

     
    11/*
    2  * Copyright (c) 2007, Haiku, Inc.
     2 * Copyright (c) 2007-2009, Haiku, Inc.
    33 * Distributed under the terms of the MIT license.
    44 *
    55 * Author:
     
    305305
    306306    // Install files and directories
    307307    PackageItem *iter;
    308     BPath installedTo;
     308    ItemState state;
    309309    uint32 i;
     310    int32 choice;
    310311    BString label;
    311312   
    312313    packageInfo.SetName(fInfo.GetName());
     
    322323    packageInfo.SetDescription(description.String());
    323324    packageInfo.SetSpaceNeeded(type->space_needed);
    324325
     326    fItemExistsPolicy = P_EXISTS_NONE;
     327
    325328    for (i = 0; i < n; i++) {
     329        state.Reset(fItemExistsPolicy); // Reset the current item state
    326330        iter = static_cast<PackageItem *>(type->items.ItemAt(i));
    327         err = iter->WriteToPath(fCurrentPath.Path(), &installedTo);
     331
     332        err = iter->WriteToPath(fCurrentPath.Path(), &state);
     333        if (err == B_FILE_EXISTS) {
     334            // Writing to path failed because path already exists - ask the user
     335            // what to do and retry the writing process
     336            choice = _ItemExists(*iter, state.destination);
     337            if (choice != P_EXISTS_ABORT) {
     338                state.policy = choice;
     339                err = iter->WriteToPath(fCurrentPath.Path(), &state);
     340            }
     341        }
     342
    328343        if (err != B_OK) {
    329344            fprintf(stderr, "Error while writing path %s\n", fCurrentPath.Path());
    330345            return err;
    331346        }
     347
    332348        if (fStatusWindow->Stopped())
    333349            return B_FILE_EXISTS;
    334350        label = "";
    335351        label << (uint32)(i + 1) << " of " << (uint32)n;
    336352        fStatusWindow->StageStep(1, NULL, label.String());
    337353
    338         packageInfo.AddItem(installedTo.Path());
     354        packageInfo.AddItem(state.destination.Path());
    339355    }
    340356
    341357    fStatusWindow->StageStep(1, "Finishing installation", "");
     
    534550}
    535551
    536552
     553int32
     554PackageView::_ItemExists(PackageItem &item, BPath &path)
     555{
     556    int32 choice = P_EXISTS_NONE;
     557
     558    switch (fItemExistsPolicy) {
     559        case P_EXISTS_OVERWRITE:
     560            choice = P_EXISTS_OVERWRITE;
     561            break;
     562
     563        case P_EXISTS_SKIP:
     564            choice = P_EXISTS_SKIP;
     565            break;
     566
     567        case P_EXISTS_ASK:
     568        case P_EXISTS_NONE:
     569        {
     570            BString alertString = T("The ");
     571
     572            alertString << item.ItemKind() << T(" named \'") << path.Leaf() << "\' ";
     573            alertString << T("already exists in the given path. Should the "
     574                "existing file be replaced with the one from this package?");
     575
     576            BAlert *alert = new BAlert(T("file_exists"), alertString.String(),
     577                T("Yes"), T("No"), T("Abort"));
     578
     579            choice = alert->Go();
     580            switch (choice) {
     581                case 0:
     582                    choice = P_EXISTS_OVERWRITE;
     583                    break;
     584                case 1:
     585                    choice = P_EXISTS_SKIP;
     586                    break;
     587                default:
     588                    return P_EXISTS_ABORT;
     589            }
     590
     591            if (fItemExistsPolicy == P_EXISTS_NONE) {
     592                // XXX: Maybe add 'No, but ask again' type of choice as well?
     593                alertString = T("Should this decision be remembered and all existing "
     594                    "files encountered in the future be ");
     595                alertString << ((choice == P_EXISTS_OVERWRITE) ? T("replaced?") : T("skipped?"));
     596
     597                alert = new BAlert(T("policy_decision"), alertString.String(),
     598                    T("Yes"), T("No"));
     599
     600                int32 decision = alert->Go();
     601                if (decision == 0)
     602                    fItemExistsPolicy = choice;
     603                else
     604                    fItemExistsPolicy = P_EXISTS_ASK;
     605            }
     606            break;
     607        }
     608    }
     609
     610    return choice;
     611}
     612
     613
    537614status_t
    538615PackageView::_GroupChanged(int32 index)
    539616{
  • src/apps/packageinstaller/PackageView.h

     
    11/*
    2  * Copyright (c) 2007, Haiku, Inc.
     2 * Copyright (c) 2007-2009, Haiku, Inc.
    33 * Distributed under the terms of the MIT license.
    44 *
    55 * Author:
     
    4242    private:
    4343        void _InitView();
    4444        void _InitProfiles();
     45        int32 _ItemExists(PackageItem &item, BPath &path);
    4546
    4647        status_t _GroupChanged(int32 index);
    4748
     
    5455        BFilePanel *fOpenPanel;
    5556        BPath fCurrentPath;
    5657        uint32 fCurrentType;
     58        int32 fItemExistsPolicy;
    5759
    5860        PackageInfo fInfo;
    5961        PackageStatus *fStatusWindow;