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:
parent
beb0419df1
commit
9ff2343b35
|
@ -11,6 +11,7 @@ Application PackageInstaller :
|
|||
PackageView.cpp
|
||||
PackageInfo.cpp
|
||||
PackageItem.cpp
|
||||
PackageInstall.cpp
|
||||
PackageStatus.cpp
|
||||
PackageTextViewer.cpp
|
||||
PackageImageViewer.cpp
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue