Applied patch by sil2100 that enables handling of script files (bug #3762)

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36020 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2010-04-01 19:02:24 +00:00
parent beb0419df1
commit 9ff2343b35
9 changed files with 479 additions and 274 deletions

View File

@ -11,6 +11,7 @@ Application PackageInstaller :
PackageView.cpp
PackageInfo.cpp
PackageItem.cpp
PackageInstall.cpp
PackageStatus.cpp
PackageTextViewer.cpp
PackageImageViewer.cpp

View File

@ -39,7 +39,8 @@ enum {
P_NONE = 0,
P_FILE,
P_DIRECTORY,
P_LINK
P_LINK,
P_SCRIPT
};
@ -86,6 +87,14 @@ PackageInfo::~PackageInfo()
delete file;
}
while (true) {
file = static_cast<PackageScript *>(fScripts.RemoveItem((long int)0));
if (file == NULL)
break;
delete file;
}
delete fPackageFile;
}
@ -624,63 +633,31 @@ PackageInfo::Parse()
RETURN_AND_SET_STATUS(B_ERROR);
}
// TODO: Here's the deal... there seems to be a strange ScrI tag that
// seems to mean script files (check this). It seems exaclty the same
// as a normal file (just as script files are normal files) so for
// now I'm treating those as files. Check if it's correct!
// No, it isn't and I will fix this soon.
if (!memcmp(buffer, "FilI", 5) || !memcmp(buffer, "ScrI", 5)) {
parser_debug("FilI\n");
element = P_FILE;
#define INIT_VARS(tag, type) \
parser_debug(tag "\n"); \
element = type; \
mimeString = ""; \
nameString = ""; \
linkString = ""; \
signatureString = ""; \
itemGroups = 0; \
ctime = 0; \
mtime = 0; \
offset = 0; \
cust = 0; \
mode = 0; \
platform = 0xffffffff; \
size = 0; \
originalSize = 0
mimeString = "";
nameString = "";
signatureString = "";
itemGroups = 0;
ctime = 0;
mtime = 0;
offset = 0;
itemGroups = 0;
cust = 0;
mode = 0;
platform = 0xffffffff;
size = 0;
originalSize = 0;
if (!memcmp(buffer, "FilI", 5)) {
INIT_VARS("FilI", P_FILE);
} else if (!memcmp(buffer, "FldI", 5)) {
parser_debug("FldI\n");
element = P_DIRECTORY;
nameString = "";
itemGroups = 0;
ctime = 0;
mtime = 0;
offset = 0;
itemGroups = 0;
cust = 0;
platform = 0xffffffff;
size = 0;
originalSize = 0;
INIT_VARS("FldI", P_DIRECTORY);
} else if (!memcmp(buffer, "LnkI", 5)) {
parser_debug("LnkI\n");
element = P_LINK;
nameString = "";
linkString = "";
itemGroups = 0;
ctime = 0;
mtime = 0;
offset = 0;
itemGroups = 0;
cust = 0;
platform = 0xffffffff;
size = 0;
originalSize = 0;
INIT_VARS("LnkI", P_LINK);
} else if (!memcmp(buffer, "ScrI", 5)) {
INIT_VARS("ScrI", P_SCRIPT);
} else if (!memcmp(buffer, "Name", 5)) {
if (element == P_NONE) {
RETURN_AND_SET_STATUS(B_ERROR);
@ -795,7 +772,7 @@ PackageInfo::Parse()
swap_data(B_UINT64_TYPE, &size, sizeof(uint64),
B_SWAP_BENDIAN_TO_HOST);
} else if (!memcmp(buffer, "OrgS", 5)) {
if (element != P_FILE && element != P_LINK) {
if (element != P_FILE && element != P_LINK && element != P_SCRIPT) {
RETURN_AND_SET_STATUS(B_ERROR);
}
@ -1019,6 +996,9 @@ PackageInfo::Parse()
item = new PackageLink(fPackageFile, dest, linkString,
localType, ctime, mtime, mode, offset, size);
}
} else if (element == P_SCRIPT) {
fScripts.AddItem(new PackageScript(fPackageFile, offset, size,
originalSize));
} else {
// If the directory tree count is equal to zero, this means all
// directory trees have been closed and a padding sequence means the

View File

@ -32,7 +32,11 @@ class PackageInfo {
const char *GetDisclaimer() { return fDisclaimer.String(); }
BMallocIO *GetSplashScreen() { return fHasImage ? &fImage : NULL; }
int32 GetProfileCount() { return fProfiles.CountItems(); }
pkg_profile *GetProfile(int32 num) { return static_cast<pkg_profile *>(fProfiles.ItemAt(num)); }
pkg_profile *GetProfile(int32 num) {
return static_cast<pkg_profile *>(fProfiles.ItemAt(num)); }
int32 GetScriptCount() { return fScripts.CountItems(); }
PackageScript *GetScript(int32 num) {
return static_cast<PackageScript *>(fScripts.ItemAt(num)); }
status_t Parse();
status_t InitCheck() { return fStatus; }
@ -56,6 +60,7 @@ class PackageInfo {
bool fHasImage;
BList fFiles; // Holds all files in the package
BList fScripts;
};

View File

@ -16,6 +16,7 @@
#include <Directory.h>
#include <fs_info.h>
#include <NodeInfo.h>
#include <OS.h>
#include <SymLink.h>
#include <Volume.h>
@ -37,10 +38,14 @@ enum {
P_ATTRIBUTE
};
extern const char **environ;
status_t
inflate_data(uint8 *in, uint32 inSize, uint8 *out, uint32 outSize)
{
parser_debug("inflate_data() called - input_size: %ld, output_size: %ld\n",
inSize, outSize);
z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
@ -374,6 +379,68 @@ PackageItem::ParseAttribute(uint8 *buffer, BNode *node, char **attrName,
}
status_t
PackageItem::SkipAttribute(uint8 *buffer, bool *attrStarted, bool *done)
{
status_t ret = B_OK;
uint32 length;
if (!memcmp(buffer, "BeAI", 5)) {
parser_debug(" Attribute started.\n");
*attrStarted = true;
} else if (!memcmp(buffer, "BeAN", 5)) {
if (!*attrStarted) {
ret = B_ERROR;
return ret;
}
parser_debug(" BeAN.\n");
fPackage->Read(&length, 4);
swap_data(B_UINT32_TYPE, &length, sizeof(uint32),
B_SWAP_BENDIAN_TO_HOST);
fPackage->Seek(length, SEEK_CUR);
} else if (!memcmp(buffer, "BeAT", 5)) {
if (!*attrStarted) {
ret = B_ERROR;
return ret;
}
parser_debug(" BeAT.\n");
fPackage->Seek(4, SEEK_CUR);
} else if (!memcmp(buffer, "BeAD", 5)) {
if (!*attrStarted) {
ret = B_ERROR;
return ret;
}
parser_debug(" BeAD.\n");
uint64 length64;
fPackage->Read(&length64, 8);
swap_data(B_UINT64_TYPE, &length64, sizeof(length64),
B_SWAP_BENDIAN_TO_HOST);
fPackage->Seek(12 + length64, SEEK_CUR);
parser_debug(" Data skipped successfuly.\n");
} else if (!memcmp(buffer, padding, 7)) {
if (!*attrStarted) {
*done = true;
return ret;
}
parser_debug(" Padding.\n");
*attrStarted = false;
parser_debug(" > Attribute skipped.\n");
} else {
parser_debug(" Unknown attribute\n");
ret = B_ERROR;
}
return ret;
}
status_t
PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
bool *done)
@ -425,6 +492,203 @@ PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
}
// #pragma mark - PackageScript
PackageScript::PackageScript(BFile *parent, uint64 offset, uint64 size,
uint64 originalSize)
:
PackageItem(parent, NULL, 0, 0, 0, offset, size),
fOriginalSize(originalSize),
fThreadId(-1)
{
}
status_t
PackageScript::DoInstall(const char *path, ItemState *state)
{
status_t ret = B_OK;
parser_debug("Script: DoInstall() called!\n");
if (fOffset) {
parser_debug("We have an offset\n");
if (!fPackage)
return B_ERROR;
ret = fPackage->InitCheck();
if (ret != B_OK)
return ret;
// We need to parse the data section now
fPackage->Seek(fOffset, SEEK_SET);
uint8 buffer[7];
bool attrStarted = false, done = false;
uint8 section = P_ATTRIBUTE;
while (fPackage->Read(buffer, 7) == 7) {
if (!memcmp(buffer, "FBeA", 5)) {
parser_debug("-> Attribute\n");
section = P_ATTRIBUTE;
continue;
} else if (!memcmp(buffer, "FiDa", 5)) {
parser_debug("-> File data\n");
section = P_DATA;
continue;
}
switch (section) {
case P_ATTRIBUTE:
ret = SkipAttribute(buffer, &attrStarted, &done);
break;
case P_DATA:
ret = _ParseScript(buffer, fOriginalSize, &done);
break;
default:
return B_ERROR;
}
if (ret != B_OK || done)
break;
}
}
parser_debug("Ret: %d %s\n", ret, strerror(ret));
return ret;
}
const char*
PackageScript::ItemKind()
{
return "script";
}
status_t
PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, bool *done)
{
status_t ret = B_OK;
if (!memcmp(buffer, "FiMF", 5)) {
parser_debug(" Found file (script) data.\n");
uint64 compressed, original;
fPackage->Read(&compressed, 8);
swap_data(B_UINT64_TYPE, &compressed, sizeof(uint64),
B_SWAP_BENDIAN_TO_HOST);
fPackage->Read(&original, 8);
swap_data(B_UINT64_TYPE, &original, sizeof(uint64),
B_SWAP_BENDIAN_TO_HOST);
parser_debug(" Still good... (%llu : %llu)\n", original,
originalSize);
if (original != originalSize) {
parser_debug(" File size mismatch\n");
return B_ERROR; // File size mismatch
}
parser_debug(" Still good...\n");
if (fPackage->Read(buffer, 4) != 4) {
parser_debug(" Read(buffer, 4) failed\n");
return B_ERROR;
}
parser_debug(" Still good...\n");
uint8 *temp = new uint8[compressed];
if (fPackage->Read(temp, compressed) != (int64)compressed) {
parser_debug(" Read(temp, compressed) failed\n");
delete[] temp;
return B_ERROR;
}
uint8 *script = new uint8[original];
ret = inflate_data(temp, compressed, script, original);
if (ret != B_OK) {
parser_debug(" inflate_data failed\n");
delete[] temp;
delete[] script;
return ret;
}
ret = _RunScript(script, originalSize);
delete[] script;
delete[] temp;
parser_debug(" Script data inflation complete!\n");
} else if (!memcmp(buffer, padding, 7)) {
*done = true;
return ret;
} else {
parser_debug("_ParseData unknown tag\n");
ret = B_ERROR;
}
return ret;
}
status_t
PackageScript::_RunScript(uint8 *script, uint32 len)
{
// This function written by Peter Folk <pfolk@uni.uiuc.edu>
// and published in the BeDevTalk FAQ, modified for use in the
// PackageInstaller
// http://www.abisoft.com/faq/BeDevTalk_FAQ.html#FAQ-209
// Save current FDs
int old_in = dup(0);
int old_out = dup(1);
int old_err = dup(2);
int filedes[2];
/* Create new pipe FDs as stdin, stdout, stderr */
pipe(filedes); dup2(filedes[0], 0); close(filedes[0]);
int in = filedes[1]; // Write to in, appears on cmd's stdin
pipe(filedes); dup2(filedes[1], 1); close(filedes[1]);
pipe(filedes); dup2(filedes[1], 2); close(filedes[1]);
const char **argv = new const char * [3];
argv[0] = strdup("/bin/sh");
argv[1] = strdup("-s");
argv[2] = NULL;
// "load" command.
fThreadId = load_image(2, argv, environ);
int i;
for (i = 0; i < 2; i++)
delete argv[i];
delete [] argv;
if (fThreadId < B_OK)
return fThreadId;
// thread id is now suspended.
setpgid(fThreadId, fThreadId);
// Restore old FDs
close(0); dup(old_in); close(old_in);
close(1); dup(old_out); close(old_out);
close(2); dup(old_err); close(old_err);
set_thread_priority(fThreadId, B_LOW_PRIORITY);
resume_thread(fThreadId);
// Write the script
if (write(in, script, len) != (int32)len || write(in, "\nexit\n", 6) != 6) {
parser_debug("Writing script failed\n");
kill_thread(fThreadId);
return B_ERROR;
}
return B_OK;
}
// #pragma mark - PackageDirectory
@ -437,11 +701,11 @@ PackageDirectory::PackageDirectory(BFile *parent, const BString &path,
status_t
PackageDirectory::WriteToPath(const char *path, ItemState *state)
PackageDirectory::DoInstall(const char *path, ItemState *state)
{
BPath &destination = state->destination;
status_t ret;
parser_debug("Directory: %s WriteToPath() called!\n", fPath.String());
parser_debug("Directory: %s DoInstall() called!\n", fPath.String());
ret = InitPath(path, &destination);
parser_debug("Ret: %d %s\n", ret, strerror(ret));
@ -499,14 +763,14 @@ PackageFile::PackageFile(BFile *parent, const BString &path, uint8 type,
status_t
PackageFile::WriteToPath(const char *path, ItemState *state)
PackageFile::DoInstall(const char *path, ItemState *state)
{
if (state == NULL)
return B_ERROR;
BPath &destination = state->destination;
status_t ret = B_OK;
parser_debug("File: %s WriteToPath() called!\n", fPath.String());
parser_debug("File: %s DoInstall() called!\n", fPath.String());
BFile file;
if (state->status == B_NO_INIT || destination.InitCheck() != B_OK) {
@ -661,14 +925,14 @@ PackageLink::PackageLink(BFile *parent, const BString &path,
status_t
PackageLink::WriteToPath(const char *path, ItemState *state)
PackageLink::DoInstall(const char *path, ItemState *state)
{
if (state == NULL)
return B_ERROR;
status_t ret = B_OK;
BSymLink symlink;
parser_debug("Symlink: %s WriteToPath() called!\n", fPath.String());
parser_debug("Symlink: %s DoInstall() called!\n", fPath.String());
BPath &destination = state->destination;
BDirectory *dir = &state->parent;

View File

@ -72,14 +72,14 @@ public:
uint64 offset = 0, uint64 size = 0);
virtual ~PackageItem();
virtual status_t WriteToPath(const char* path = NULL,
virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL) = 0;
virtual void SetTo(BFile* parent, const BString& path,
uint8 type, uint32 ctime, uint32 mtime,
uint64 offset = 0, uint64 size = 0);
virtual const char* ItemKind() = 0;
protected:
protected:
status_t InitPath(const char* path, BPath* destination);
status_t HandleAttributes(BPath* destination, BNode* node,
const char* header);
@ -91,6 +91,8 @@ protected:
uint64* tempSize, uint64* attrCSize,
uint64* attrOSize, bool* attrStarted,
bool* done);
status_t SkipAttribute(uint8 *buffer, bool *attrStarted,
bool *done);
status_t ParseData(uint8* buffer, BFile* file,
uint64 originalSize, bool* done);
@ -111,12 +113,34 @@ public:
uint8 type, uint32 ctime, uint32 mtime,
uint64 offset = 0, uint64 size = 0);
virtual status_t WriteToPath(const char* path = NULL,
virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL);
virtual const char* ItemKind();
};
class PackageScript : public PackageItem {
public:
PackageScript(BFile* parent, uint64 offset = 0,
uint64 size = 0, uint64 originalSize = 0);
virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL);
virtual const char* ItemKind();
thread_id GetThreadId() { return fThreadId; }
void SetThreadId(thread_id id) { fThreadId = id; }
private:
status_t _ParseScript(uint8 *buffer, uint64 originalSize,
bool *done);
status_t _RunScript(uint8 *script, uint32 len);
uint64 fOriginalSize;
thread_id fThreadId;
};
class PackageFile : public PackageItem {
public:
PackageFile(BFile* parent, const BString& path,
@ -125,7 +149,7 @@ public:
uint32 platform, const BString& mime,
const BString& signature, uint32 mode);
virtual status_t WriteToPath(const char* path = NULL,
virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL);
virtual const char* ItemKind();
@ -146,7 +170,7 @@ public:
uint32 mtime, uint32 mode, uint64 offset = 0,
uint64 size = 0);
virtual status_t WriteToPath(const char* path = NULL,
virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL);
virtual const char* ItemKind();

View File

@ -92,10 +92,11 @@ StopButton::Draw(BRect updateRect)
PackageStatus::PackageStatus(const char *title, const char *label,
const char *trailing)
const char *trailing, BHandler *parent)
: BWindow(BRect(200, 200, 550, 255), title, B_TITLED_WINDOW,
B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE, 0),
fIsStopped(false)
fIsStopped(false),
fParent(parent)
{
SetLayout(new BGroupLayout(B_VERTICAL));
@ -129,6 +130,13 @@ PackageStatus::MessageReceived(BMessage *msg)
switch (msg->what) {
case P_MSG_STOP:
fIsStopped = true;
if (fParent != NULL) {
// If we have a parent defined, forward this message
BLooper *loop = fParent->Looper();
if (loop != NULL) {
loop->PostMessage(msg, fParent);
}
}
break;
default:
BWindow::MessageReceived(msg);

View File

@ -31,7 +31,7 @@ class StopButton : public BButton {
class PackageStatus : public BWindow {
public:
PackageStatus(const char *title, const char *label = NULL,
const char *trailing = NULL);
const char *trailing = NULL, BHandler *parent = NULL);
~PackageStatus();
void MessageReceived(BMessage *msg);
@ -46,6 +46,7 @@ class PackageStatus : public BWindow {
BStatusBar *fStatus;
StopButton *fButton;
bool fIsStopped;
BHandler *fParent;
};

View File

@ -63,7 +63,8 @@ PackageView::PackageView(BRect frame, const entry_ref *ref)
//BView("package_view", B_WILL_DRAW, new BGroupLayout(B_HORIZONTAL)),
fOpenPanel(new BFilePanel(B_OPEN_PANEL, NULL, NULL,
B_DIRECTORY_NODE, false)),
fInfo(ref)
fInfo(ref),
fInstallProcess(this)
{
_InitView();
@ -121,7 +122,8 @@ PackageView::AttachedToWindow()
// attaching the view to the window
_GroupChanged(0);
fStatusWindow = new PackageStatus(T("Installation progress"));
fStatusWindow = new PackageStatus(T("Installation progress"), NULL, NULL,
this);
// Show the splash screen, if present
BMallocIO *image = fInfo.GetSplashScreen();
@ -133,10 +135,10 @@ PackageView::AttachedToWindow()
// Show the disclaimer/info text popup, if present
BString disclaimer = fInfo.GetDisclaimer();
if (disclaimer.Length() != 0) {
PackageTextViewer *text = new PackageTextViewer(disclaimer.String());
PackageTextViewer *text = new PackageTextViewer(disclaimer.String());
int32 selection = text->Go();
// The user didn't accept our disclaimer, this means we cannot continue.
if (selection == 0) {
if (selection == 0) {
BWindow *parent = Window();
if (parent && parent->Lock())
parent->Quit();
@ -153,36 +155,11 @@ PackageView::MessageReceived(BMessage *msg)
case P_MSG_INSTALL:
{
fInstall->SetEnabled(false);
fInstallTypes->SetEnabled(false);
fDestination->SetEnabled(false);
fStatusWindow->Show();
BAlert *notify;
status_t ret = Install();
if (ret == B_OK) {
notify = new BAlert("installation_success",
T("The package you requested has been successfully installed "
"on your system."), T("OK"));
notify->Go();
fStatusWindow->Hide();
BWindow *parent = Window();
if (parent && parent->Lock())
parent->Quit();
}
else if (ret == B_FILE_EXISTS)
notify = new BAlert("installation_aborted",
T("The installation of the package has been aborted."), T("OK"));
else {
notify = new BAlert("installation_failed", // TODO: Review this
T("The requested package failed to install on your system. This "
"might be a problem with the target package file. Please consult "
"this issue with the package distributor."), T("OK"), NULL,
NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
fprintf(stderr, "Error while installing the package : %s\n", strerror(ret));
}
notify->Go();
fStatusWindow->Hide();
fInstall->SetEnabled(true);
fInstallProcess.Start();
break;
}
case P_MSG_PATH_CHANGED:
@ -204,6 +181,65 @@ PackageView::MessageReceived(BMessage *msg)
}
break;
}
case P_MSG_I_FINISHED:
{
BAlert *notify = new BAlert("installation_success",
T("The package you requested has been successfully installed "
"on your system."), T("OK"));
notify->Go();
fStatusWindow->Hide();
fInstall->SetEnabled(true);
fInstallTypes->SetEnabled(true);
fDestination->SetEnabled(true);
fInstallProcess.Stop();
BWindow *parent = Window();
if (parent && parent->Lock())
parent->Quit();
break;
}
case P_MSG_I_ABORT:
{
BAlert *notify = new BAlert("installation_aborted",
T("The installation of the package has been aborted."), T("OK"));
notify->Go();
fStatusWindow->Hide();
fInstall->SetEnabled(true);
fInstallTypes->SetEnabled(true);
fDestination->SetEnabled(true);
fInstallProcess.Stop();
break;
}
case P_MSG_I_ERROR:
{
BAlert *notify = new BAlert("installation_failed", // TODO: Review this
T("The requested package failed to install on your system. This "
"might be a problem with the target package file. Please consult "
"this issue with the package distributor."), T("OK"), NULL,
NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
fprintf(stderr, "Error while installing the package\n");
notify->Go();
fStatusWindow->Hide();
fInstall->SetEnabled(true);
fInstallTypes->SetEnabled(true);
fDestination->SetEnabled(true);
fInstallProcess.Stop();
break;
}
case P_MSG_STOP:
{
// This message is sent to us by the PackageStatus window, informing
// user interruptions.
// We actually use this message only when a post installation script
// is running and we want to kill it while it's still running
fStatusWindow->Hide();
fInstall->SetEnabled(true);
fInstallTypes->SetEnabled(true);
fDestination->SetEnabled(true);
fInstallProcess.Stop();
break;
}
case B_REFS_RECEIVED:
{
entry_ref ref;
@ -247,122 +283,65 @@ PackageView::MessageReceived(BMessage *msg)
}
status_t
PackageView::Install()
int32
PackageView::ItemExists(PackageItem &item, BPath &path, int32 &policy)
{
pkg_profile *type = static_cast<pkg_profile *>(fInfo.GetProfile(fCurrentType));
uint32 n = type->items.CountItems();
int32 choice = P_EXISTS_NONE;
fStatusWindow->Reset(n + 4);
switch (policy) {
case P_EXISTS_OVERWRITE:
choice = P_EXISTS_OVERWRITE;
break;
fStatusWindow->StageStep(1, "Preparing package");
case P_EXISTS_SKIP:
choice = P_EXISTS_SKIP;
break;
InstalledPackageInfo packageInfo(fInfo.GetName(), fInfo.GetVersion());
case P_EXISTS_ASK:
case P_EXISTS_NONE:
{
BString alertString = T("The ");
status_t err = packageInfo.InitCheck();
err = B_ENTRY_NOT_FOUND;
if (err == B_OK) {
// The package is already installed, inform the user
BAlert *reinstall = new BAlert("reinstall",
T("The given package seems to be already installed on your system. "
"Would you like to uninstall the existing one and continue the "
"installation?"), T("Continue"), T("Abort"));
alertString << item.ItemKind() << T(" named \'") << path.Leaf() << "\' ";
alertString << T("already exists in the given path.\nReplace the file with "
"the one from this package or skip it?");
if (reinstall->Go() == 0) {
// Uninstall the package
err = packageInfo.Uninstall();
if (err != B_OK) {
fprintf(stderr, "Error on uninstall\n");
return err;
BAlert *alert = new BAlert(T("file_exists"), alertString.String(),
T("Replace"), T("Skip"), T("Abort"));
choice = alert->Go();
switch (choice) {
case 0:
choice = P_EXISTS_OVERWRITE;
break;
case 1:
choice = P_EXISTS_SKIP;
break;
default:
return P_EXISTS_ABORT;
}
err = packageInfo.SetTo(fInfo.GetName(), fInfo.GetVersion(), true);
if (err != B_OK) {
fprintf(stderr, "Error on SetTo\n");
return err;
if (policy == P_EXISTS_NONE) {
// TODO: Maybe add 'No, but ask again' type of choice as well?
alertString = T("Do you want to remember this decision for the rest of "
"this installation?\nAll existing files will be ");
alertString << ((choice == P_EXISTS_OVERWRITE)
? T("replaced?") : T("skipped?"));
alert = new BAlert(T("policy_decision"), alertString.String(),
T("Yes"), T("No"));
int32 decision = alert->Go();
if (decision == 0)
policy = choice;
else
policy = P_EXISTS_ASK;
}
}
else {
// Abort the installation
return B_FILE_EXISTS;
break;
}
}
else if (err == B_ENTRY_NOT_FOUND) {
err = packageInfo.SetTo(fInfo.GetName(), fInfo.GetVersion(), true);
if (err != B_OK) {
fprintf(stderr, "Error on SetTo\n");
return err;
}
}
else if (fStatusWindow->Stopped())
return B_FILE_EXISTS;
else {
fprintf(stderr, "returning on error\n");
return err;
}
fStatusWindow->StageStep(1, "Installing files and folders");
// Install files and directories
PackageItem *iter;
ItemState state;
uint32 i;
int32 choice;
BString label;
packageInfo.SetName(fInfo.GetName());
// TODO: Here's a small problem, since right now it's not quite sure
// which description is really used as such. The one displayed on
// the installer is mostly package installation description, but
// most people use it for describing the application in more detail
// then in the short description.
// For now, we'll use the short description if possible.
BString description = fInfo.GetShortDescription();
if (description.Length() <= 0)
description = fInfo.GetDescription();
packageInfo.SetDescription(description.String());
packageInfo.SetSpaceNeeded(type->space_needed);
fItemExistsPolicy = P_EXISTS_NONE;
for (i = 0; i < n; i++) {
state.Reset(fItemExistsPolicy); // Reset the current item state
iter = static_cast<PackageItem *>(type->items.ItemAt(i));
err = iter->WriteToPath(fCurrentPath.Path(), &state);
if (err == B_FILE_EXISTS) {
// Writing to path failed because path already exists - ask the user
// what to do and retry the writing process
choice = _ItemExists(*iter, state.destination);
if (choice != P_EXISTS_ABORT) {
state.policy = choice;
err = iter->WriteToPath(fCurrentPath.Path(), &state);
}
}
if (err != B_OK) {
fprintf(stderr, "Error while writing path %s\n", fCurrentPath.Path());
return err;
}
if (fStatusWindow->Stopped())
return B_FILE_EXISTS;
label = "";
label << (uint32)(i + 1) << " of " << (uint32)n;
fStatusWindow->StageStep(1, NULL, label.String());
packageInfo.AddItem(state.destination.Path());
}
fStatusWindow->StageStep(1, "Finishing installation", "");
err = packageInfo.Save();
if (err != B_OK)
return err;
fStatusWindow->StageStep(1, "Done");
return B_OK;
return choice;
}
@ -550,68 +529,6 @@ PackageView::_InitProfiles()
}
int32
PackageView::_ItemExists(PackageItem &item, BPath &path)
{
int32 choice = P_EXISTS_NONE;
switch (fItemExistsPolicy) {
case P_EXISTS_OVERWRITE:
choice = P_EXISTS_OVERWRITE;
break;
case P_EXISTS_SKIP:
choice = P_EXISTS_SKIP;
break;
case P_EXISTS_ASK:
case P_EXISTS_NONE:
{
BString alertString = T("The ");
alertString << item.ItemKind() << T(" named \'") << path.Leaf() << "\' ";
alertString << T("already exists in the given path.\nReplace the file with "
"the one from this package or skip it?");
BAlert *alert = new BAlert(T("file_exists"), alertString.String(),
T("Replace"), T("Skip"), T("Abort"));
choice = alert->Go();
switch (choice) {
case 0:
choice = P_EXISTS_OVERWRITE;
break;
case 1:
choice = P_EXISTS_SKIP;
break;
default:
return P_EXISTS_ABORT;
}
if (fItemExistsPolicy == P_EXISTS_NONE) {
// TODO: Maybe add 'No, but ask again' type of choice as well?
alertString = T("Do you want to remember this decision for the rest of "
"this installation?\nAll existing files will be ");
alertString << ((choice == P_EXISTS_OVERWRITE)
? T("replaced?") : T("skipped?"));
alert = new BAlert(T("policy_decision"), alertString.String(),
T("Yes"), T("No"));
int32 decision = alert->Go();
if (decision == 0)
fItemExistsPolicy = choice;
else
fItemExistsPolicy = P_EXISTS_ASK;
}
break;
}
}
return choice;
}
status_t
PackageView::_GroupChanged(int32 index)
{

View File

@ -10,13 +10,14 @@
#include "PackageInfo.h"
#include "PackageInstall.h"
#include "PackageStatus.h"
#include <View.h>
#include <Box.h>
#include <Button.h>
#include <MenuField.h>
#include <FilePanel.h>
#include <MenuField.h>
#include <View.h>
class BPopUpMenu;
class BTextView;
@ -37,12 +38,16 @@ class PackageView : public BView {
void AttachedToWindow();
void MessageReceived(BMessage *msg);
status_t Install();
int32 ItemExists(PackageItem &item, BPath &path, int32 &policy);
BPath *GetCurrentPath() { return &fCurrentPath; }
PackageInfo *GetPackageInfo() { return &fInfo; }
uint32 GetCurrentType() { return fCurrentType; }
PackageStatus *GetStatusWindow() { return fStatusWindow; }
private:
void _InitView();
void _InitProfiles();
int32 _ItemExists(PackageItem &item, BPath &path);
status_t _GroupChanged(int32 index);
@ -55,10 +60,10 @@ class PackageView : public BView {
BFilePanel *fOpenPanel;
BPath fCurrentPath;
uint32 fCurrentType;
int32 fItemExistsPolicy;
PackageInfo fInfo;
PackageStatus *fStatusWindow;
PackageInstall fInstallProcess;
};
#endif // PACKAGE_VIEW_H