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
+1
View File
@@ -11,6 +11,7 @@ Application PackageInstaller :
PackageView.cpp PackageView.cpp
PackageInfo.cpp PackageInfo.cpp
PackageItem.cpp PackageItem.cpp
PackageInstall.cpp
PackageStatus.cpp PackageStatus.cpp
PackageTextViewer.cpp PackageTextViewer.cpp
PackageImageViewer.cpp PackageImageViewer.cpp
+36 -56
View File
@@ -39,7 +39,8 @@ enum {
P_NONE = 0, P_NONE = 0,
P_FILE, P_FILE,
P_DIRECTORY, P_DIRECTORY,
P_LINK P_LINK,
P_SCRIPT
}; };
@@ -86,6 +87,14 @@ PackageInfo::~PackageInfo()
delete file; delete file;
} }
while (true) {
file = static_cast<PackageScript *>(fScripts.RemoveItem((long int)0));
if (file == NULL)
break;
delete file;
}
delete fPackageFile; delete fPackageFile;
} }
@@ -624,63 +633,31 @@ PackageInfo::Parse()
RETURN_AND_SET_STATUS(B_ERROR); RETURN_AND_SET_STATUS(B_ERROR);
} }
// TODO: Here's the deal... there seems to be a strange ScrI tag that #define INIT_VARS(tag, type) \
// seems to mean script files (check this). It seems exaclty the same parser_debug(tag "\n"); \
// as a normal file (just as script files are normal files) so for element = type; \
// now I'm treating those as files. Check if it's correct! mimeString = ""; \
// No, it isn't and I will fix this soon. nameString = ""; \
if (!memcmp(buffer, "FilI", 5) || !memcmp(buffer, "ScrI", 5)) { linkString = ""; \
parser_debug("FilI\n"); signatureString = ""; \
element = P_FILE; itemGroups = 0; \
ctime = 0; \
mtime = 0; \
offset = 0; \
cust = 0; \
mode = 0; \
platform = 0xffffffff; \
size = 0; \
originalSize = 0
mimeString = ""; if (!memcmp(buffer, "FilI", 5)) {
nameString = ""; INIT_VARS("FilI", P_FILE);
signatureString = "";
itemGroups = 0;
ctime = 0;
mtime = 0;
offset = 0;
itemGroups = 0;
cust = 0;
mode = 0;
platform = 0xffffffff;
size = 0;
originalSize = 0;
} else if (!memcmp(buffer, "FldI", 5)) { } else if (!memcmp(buffer, "FldI", 5)) {
parser_debug("FldI\n"); INIT_VARS("FldI", P_DIRECTORY);
element = P_DIRECTORY;
nameString = "";
itemGroups = 0;
ctime = 0;
mtime = 0;
offset = 0;
itemGroups = 0;
cust = 0;
platform = 0xffffffff;
size = 0;
originalSize = 0;
} else if (!memcmp(buffer, "LnkI", 5)) { } else if (!memcmp(buffer, "LnkI", 5)) {
parser_debug("LnkI\n"); INIT_VARS("LnkI", P_LINK);
element = P_LINK; } else if (!memcmp(buffer, "ScrI", 5)) {
INIT_VARS("ScrI", P_SCRIPT);
nameString = "";
linkString = "";
itemGroups = 0;
ctime = 0;
mtime = 0;
offset = 0;
itemGroups = 0;
cust = 0;
platform = 0xffffffff;
size = 0;
originalSize = 0;
} else if (!memcmp(buffer, "Name", 5)) { } else if (!memcmp(buffer, "Name", 5)) {
if (element == P_NONE) { if (element == P_NONE) {
RETURN_AND_SET_STATUS(B_ERROR); RETURN_AND_SET_STATUS(B_ERROR);
@@ -795,7 +772,7 @@ PackageInfo::Parse()
swap_data(B_UINT64_TYPE, &size, sizeof(uint64), swap_data(B_UINT64_TYPE, &size, sizeof(uint64),
B_SWAP_BENDIAN_TO_HOST); B_SWAP_BENDIAN_TO_HOST);
} else if (!memcmp(buffer, "OrgS", 5)) { } 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); RETURN_AND_SET_STATUS(B_ERROR);
} }
@@ -1019,6 +996,9 @@ PackageInfo::Parse()
item = new PackageLink(fPackageFile, dest, linkString, item = new PackageLink(fPackageFile, dest, linkString,
localType, ctime, mtime, mode, offset, size); localType, ctime, mtime, mode, offset, size);
} }
} else if (element == P_SCRIPT) {
fScripts.AddItem(new PackageScript(fPackageFile, offset, size,
originalSize));
} else { } else {
// If the directory tree count is equal to zero, this means all // If the directory tree count is equal to zero, this means all
// directory trees have been closed and a padding sequence means the // directory trees have been closed and a padding sequence means the
+6 -1
View File
@@ -32,7 +32,11 @@ class PackageInfo {
const char *GetDisclaimer() { return fDisclaimer.String(); } const char *GetDisclaimer() { return fDisclaimer.String(); }
BMallocIO *GetSplashScreen() { return fHasImage ? &fImage : NULL; } BMallocIO *GetSplashScreen() { return fHasImage ? &fImage : NULL; }
int32 GetProfileCount() { return fProfiles.CountItems(); } 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 Parse();
status_t InitCheck() { return fStatus; } status_t InitCheck() { return fStatus; }
@@ -56,6 +60,7 @@ class PackageInfo {
bool fHasImage; bool fHasImage;
BList fFiles; // Holds all files in the package BList fFiles; // Holds all files in the package
BList fScripts;
}; };
+270 -6
View File
@@ -16,6 +16,7 @@
#include <Directory.h> #include <Directory.h>
#include <fs_info.h> #include <fs_info.h>
#include <NodeInfo.h> #include <NodeInfo.h>
#include <OS.h>
#include <SymLink.h> #include <SymLink.h>
#include <Volume.h> #include <Volume.h>
@@ -37,10 +38,14 @@ enum {
P_ATTRIBUTE P_ATTRIBUTE
}; };
extern const char **environ;
status_t status_t
inflate_data(uint8 *in, uint32 inSize, uint8 *out, uint32 outSize) 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; z_stream stream;
stream.zalloc = Z_NULL; stream.zalloc = Z_NULL;
stream.zfree = 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 status_t
PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize, PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
bool *done) 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 <[email protected]>
// 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 // #pragma mark - PackageDirectory
@@ -437,11 +701,11 @@ PackageDirectory::PackageDirectory(BFile *parent, const BString &path,
status_t status_t
PackageDirectory::WriteToPath(const char *path, ItemState *state) PackageDirectory::DoInstall(const char *path, ItemState *state)
{ {
BPath &destination = state->destination; BPath &destination = state->destination;
status_t ret; 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); ret = InitPath(path, &destination);
parser_debug("Ret: %d %s\n", ret, strerror(ret)); parser_debug("Ret: %d %s\n", ret, strerror(ret));
@@ -499,14 +763,14 @@ PackageFile::PackageFile(BFile *parent, const BString &path, uint8 type,
status_t status_t
PackageFile::WriteToPath(const char *path, ItemState *state) PackageFile::DoInstall(const char *path, ItemState *state)
{ {
if (state == NULL) if (state == NULL)
return B_ERROR; return B_ERROR;
BPath &destination = state->destination; BPath &destination = state->destination;
status_t ret = B_OK; 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; BFile file;
if (state->status == B_NO_INIT || destination.InitCheck() != B_OK) { if (state->status == B_NO_INIT || destination.InitCheck() != B_OK) {
@@ -661,14 +925,14 @@ PackageLink::PackageLink(BFile *parent, const BString &path,
status_t status_t
PackageLink::WriteToPath(const char *path, ItemState *state) PackageLink::DoInstall(const char *path, ItemState *state)
{ {
if (state == NULL) if (state == NULL)
return B_ERROR; return B_ERROR;
status_t ret = B_OK; status_t ret = B_OK;
BSymLink symlink; BSymLink symlink;
parser_debug("Symlink: %s WriteToPath() called!\n", fPath.String()); parser_debug("Symlink: %s DoInstall() called!\n", fPath.String());
BPath &destination = state->destination; BPath &destination = state->destination;
BDirectory *dir = &state->parent; BDirectory *dir = &state->parent;
+29 -5
View File
@@ -72,14 +72,14 @@ public:
uint64 offset = 0, uint64 size = 0); uint64 offset = 0, uint64 size = 0);
virtual ~PackageItem(); virtual ~PackageItem();
virtual status_t WriteToPath(const char* path = NULL, virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL) = 0; ItemState *state = NULL) = 0;
virtual void SetTo(BFile* parent, const BString& path, virtual void SetTo(BFile* parent, const BString& path,
uint8 type, uint32 ctime, uint32 mtime, uint8 type, uint32 ctime, uint32 mtime,
uint64 offset = 0, uint64 size = 0); uint64 offset = 0, uint64 size = 0);
virtual const char* ItemKind() = 0; virtual const char* ItemKind() = 0;
protected: protected:
status_t InitPath(const char* path, BPath* destination); status_t InitPath(const char* path, BPath* destination);
status_t HandleAttributes(BPath* destination, BNode* node, status_t HandleAttributes(BPath* destination, BNode* node,
const char* header); const char* header);
@@ -91,6 +91,8 @@ protected:
uint64* tempSize, uint64* attrCSize, uint64* tempSize, uint64* attrCSize,
uint64* attrOSize, bool* attrStarted, uint64* attrOSize, bool* attrStarted,
bool* done); bool* done);
status_t SkipAttribute(uint8 *buffer, bool *attrStarted,
bool *done);
status_t ParseData(uint8* buffer, BFile* file, status_t ParseData(uint8* buffer, BFile* file,
uint64 originalSize, bool* done); uint64 originalSize, bool* done);
@@ -111,12 +113,34 @@ public:
uint8 type, uint32 ctime, uint32 mtime, uint8 type, uint32 ctime, uint32 mtime,
uint64 offset = 0, uint64 size = 0); 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); ItemState *state = NULL);
virtual const char* ItemKind(); 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 { class PackageFile : public PackageItem {
public: public:
PackageFile(BFile* parent, const BString& path, PackageFile(BFile* parent, const BString& path,
@@ -125,7 +149,7 @@ public:
uint32 platform, const BString& mime, uint32 platform, const BString& mime,
const BString& signature, uint32 mode); const BString& signature, uint32 mode);
virtual status_t WriteToPath(const char* path = NULL, virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL); ItemState *state = NULL);
virtual const char* ItemKind(); virtual const char* ItemKind();
@@ -146,7 +170,7 @@ public:
uint32 mtime, uint32 mode, uint64 offset = 0, uint32 mtime, uint32 mode, uint64 offset = 0,
uint64 size = 0); uint64 size = 0);
virtual status_t WriteToPath(const char* path = NULL, virtual status_t DoInstall(const char* path = NULL,
ItemState *state = NULL); ItemState *state = NULL);
virtual const char* ItemKind(); virtual const char* ItemKind();
+10 -2
View File
@@ -92,10 +92,11 @@ StopButton::Draw(BRect updateRect)
PackageStatus::PackageStatus(const char *title, const char *label, 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, : BWindow(BRect(200, 200, 550, 255), title, B_TITLED_WINDOW,
B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE, 0), B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE, 0),
fIsStopped(false) fIsStopped(false),
fParent(parent)
{ {
SetLayout(new BGroupLayout(B_VERTICAL)); SetLayout(new BGroupLayout(B_VERTICAL));
@@ -129,6 +130,13 @@ PackageStatus::MessageReceived(BMessage *msg)
switch (msg->what) { switch (msg->what) {
case P_MSG_STOP: case P_MSG_STOP:
fIsStopped = true; 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; break;
default: default:
BWindow::MessageReceived(msg); BWindow::MessageReceived(msg);
+2 -1
View File
@@ -31,7 +31,7 @@ class StopButton : public BButton {
class PackageStatus : public BWindow { class PackageStatus : public BWindow {
public: public:
PackageStatus(const char *title, const char *label = NULL, PackageStatus(const char *title, const char *label = NULL,
const char *trailing = NULL); const char *trailing = NULL, BHandler *parent = NULL);
~PackageStatus(); ~PackageStatus();
void MessageReceived(BMessage *msg); void MessageReceived(BMessage *msg);
@@ -46,6 +46,7 @@ class PackageStatus : public BWindow {
BStatusBar *fStatus; BStatusBar *fStatus;
StopButton *fButton; StopButton *fButton;
bool fIsStopped; bool fIsStopped;
BHandler *fParent;
}; };
+115 -198
View File
@@ -63,7 +63,8 @@ PackageView::PackageView(BRect frame, const entry_ref *ref)
//BView("package_view", B_WILL_DRAW, new BGroupLayout(B_HORIZONTAL)), //BView("package_view", B_WILL_DRAW, new BGroupLayout(B_HORIZONTAL)),
fOpenPanel(new BFilePanel(B_OPEN_PANEL, NULL, NULL, fOpenPanel(new BFilePanel(B_OPEN_PANEL, NULL, NULL,
B_DIRECTORY_NODE, false)), B_DIRECTORY_NODE, false)),
fInfo(ref) fInfo(ref),
fInstallProcess(this)
{ {
_InitView(); _InitView();
@@ -121,7 +122,8 @@ PackageView::AttachedToWindow()
// attaching the view to the window // attaching the view to the window
_GroupChanged(0); _GroupChanged(0);
fStatusWindow = new PackageStatus(T("Installation progress")); fStatusWindow = new PackageStatus(T("Installation progress"), NULL, NULL,
this);
// Show the splash screen, if present // Show the splash screen, if present
BMallocIO *image = fInfo.GetSplashScreen(); BMallocIO *image = fInfo.GetSplashScreen();
@@ -133,10 +135,10 @@ PackageView::AttachedToWindow()
// Show the disclaimer/info text popup, if present // Show the disclaimer/info text popup, if present
BString disclaimer = fInfo.GetDisclaimer(); BString disclaimer = fInfo.GetDisclaimer();
if (disclaimer.Length() != 0) { if (disclaimer.Length() != 0) {
PackageTextViewer *text = new PackageTextViewer(disclaimer.String()); PackageTextViewer *text = new PackageTextViewer(disclaimer.String());
int32 selection = text->Go(); int32 selection = text->Go();
// The user didn't accept our disclaimer, this means we cannot continue. // The user didn't accept our disclaimer, this means we cannot continue.
if (selection == 0) { if (selection == 0) {
BWindow *parent = Window(); BWindow *parent = Window();
if (parent && parent->Lock()) if (parent && parent->Lock())
parent->Quit(); parent->Quit();
@@ -153,36 +155,11 @@ PackageView::MessageReceived(BMessage *msg)
case P_MSG_INSTALL: case P_MSG_INSTALL:
{ {
fInstall->SetEnabled(false); fInstall->SetEnabled(false);
fInstallTypes->SetEnabled(false);
fDestination->SetEnabled(false);
fStatusWindow->Show(); 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; break;
} }
case P_MSG_PATH_CHANGED: case P_MSG_PATH_CHANGED:
@@ -204,6 +181,65 @@ PackageView::MessageReceived(BMessage *msg)
} }
break; 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: case B_REFS_RECEIVED:
{ {
entry_ref ref; entry_ref ref;
@@ -247,122 +283,65 @@ PackageView::MessageReceived(BMessage *msg)
} }
status_t int32
PackageView::Install() PackageView::ItemExists(PackageItem &item, BPath &path, int32 &policy)
{ {
pkg_profile *type = static_cast<pkg_profile *>(fInfo.GetProfile(fCurrentType)); int32 choice = P_EXISTS_NONE;
uint32 n = type->items.CountItems();
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(); alertString << item.ItemKind() << T(" named \'") << path.Leaf() << "\' ";
err = B_ENTRY_NOT_FOUND; alertString << T("already exists in the given path.\nReplace the file with "
if (err == B_OK) { "the one from this package or skip it?");
// 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"));
if (reinstall->Go() == 0) { BAlert *alert = new BAlert(T("file_exists"), alertString.String(),
// Uninstall the package T("Replace"), T("Skip"), T("Abort"));
err = packageInfo.Uninstall();
if (err != B_OK) { choice = alert->Go();
fprintf(stderr, "Error on uninstall\n"); switch (choice) {
return err; 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 (policy == P_EXISTS_NONE) {
if (err != B_OK) { // TODO: Maybe add 'No, but ask again' type of choice as well?
fprintf(stderr, "Error on SetTo\n"); alertString = T("Do you want to remember this decision for the rest of "
return err; "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;
} }
} break;
else {
// Abort the installation
return B_FILE_EXISTS;
} }
} }
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"); return choice;
// 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;
} }
@@ -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 status_t
PackageView::_GroupChanged(int32 index) PackageView::_GroupChanged(int32 index)
{ {
+10 -5
View File
@@ -10,13 +10,14 @@
#include "PackageInfo.h" #include "PackageInfo.h"
#include "PackageInstall.h"
#include "PackageStatus.h" #include "PackageStatus.h"
#include <View.h>
#include <Box.h> #include <Box.h>
#include <Button.h> #include <Button.h>
#include <MenuField.h>
#include <FilePanel.h> #include <FilePanel.h>
#include <MenuField.h>
#include <View.h>
class BPopUpMenu; class BPopUpMenu;
class BTextView; class BTextView;
@@ -37,12 +38,16 @@ class PackageView : public BView {
void AttachedToWindow(); void AttachedToWindow();
void MessageReceived(BMessage *msg); 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: private:
void _InitView(); void _InitView();
void _InitProfiles(); void _InitProfiles();
int32 _ItemExists(PackageItem &item, BPath &path);
status_t _GroupChanged(int32 index); status_t _GroupChanged(int32 index);
@@ -55,10 +60,10 @@ class PackageView : public BView {
BFilePanel *fOpenPanel; BFilePanel *fOpenPanel;
BPath fCurrentPath; BPath fCurrentPath;
uint32 fCurrentType; uint32 fCurrentType;
int32 fItemExistsPolicy;
PackageInfo fInfo; PackageInfo fInfo;
PackageStatus *fStatusWindow; PackageStatus *fStatusWindow;
PackageInstall fInstallProcess;
}; };
#endif // PACKAGE_VIEW_H #endif // PACKAGE_VIEW_H