PackageInstaller: Run install scripts in the correct directory
* From debugging with the Gobe and Moho installer, scripts define which folder to run them from. The PackageInstaller is supposed to run the script in that working directory. The parser seems to have the correct folder in "installPath" when adding the script as PackageItem, but that code is rather horrible. I've changed it so PackageScript items also set the path, use InitPath() to obtain the final working directory and set it before running the script. * Both Moho and Gobe create the Deskbar link from that script, the folder is rewritten in the script via ReplaceAll(). * Correctly running the script makes a bug visible: Dynamically added files in the install location by these scripts are not removed when uninstalling the package. When re-installing a package, it is first uninstalled and this currently gives an error for both Moho and Gobe, since they create some links in these scripts which never worked before. To install again, the install folder needs to be deleted manually. * Some cleanup along the way... sorry.
This commit is contained in:
@@ -1024,8 +1024,11 @@ PackageInfo::Parse()
|
||||
localType, ctime, mtime, mode, offset, size);
|
||||
}
|
||||
} else if (element == P_SCRIPT) {
|
||||
fScripts.AddItem(new PackageScript(fPackageFile, offset, size,
|
||||
originalSize));
|
||||
parser_debug("Adding the script %s!\n",
|
||||
nameString.String());
|
||||
|
||||
fScripts.AddItem(new PackageScript(fPackageFile,
|
||||
installDirectory, 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
|
||||
|
||||
@@ -245,10 +245,11 @@ PackageInstall::_Install()
|
||||
fCurrentScriptLocker.Lock();
|
||||
fCurrentScript = script;
|
||||
|
||||
status_t status = script->DoInstall();
|
||||
status_t status = script->DoInstall(installPath);
|
||||
if (status != B_OK) {
|
||||
fprintf(stderr, "Error while running script: %s\n",
|
||||
strerror(status));
|
||||
fCurrentScriptLocker.Unlock();
|
||||
return P_MSG_I_ERROR;
|
||||
}
|
||||
fCurrentScriptLocker.Unlock();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, Haiku, Inc.
|
||||
* Copyright (c) 2010-2014, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*
|
||||
* Author:
|
||||
@@ -8,8 +8,10 @@
|
||||
#ifndef PACKAGE_INSTALL_H
|
||||
#define PACKAGE_INSTALL_H
|
||||
|
||||
|
||||
#include <Locker.h>
|
||||
|
||||
|
||||
class PackageView;
|
||||
class PackageScript;
|
||||
|
||||
@@ -19,6 +21,7 @@ enum {
|
||||
P_MSG_I_ERROR = 'pier'
|
||||
};
|
||||
|
||||
|
||||
class PackageInstall {
|
||||
public:
|
||||
PackageInstall(PackageView* parent);
|
||||
@@ -31,13 +34,15 @@ class PackageInstall {
|
||||
private:
|
||||
uint32 _Install();
|
||||
|
||||
private:
|
||||
PackageView* fParent;
|
||||
thread_id fThreadId;
|
||||
BLocker fIdLocker;
|
||||
|
||||
PackageScript* fCurrentScript;
|
||||
BLocker fCurrentScriptLocker; // XXX: will we need this?
|
||||
BLocker fCurrentScriptLocker;
|
||||
int32 fItemExistsPolicy;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // PACKAGE_INSTALL_H
|
||||
|
||||
@@ -130,10 +130,8 @@ inflate_file_to_file(BFile *in, uint64 in_size, BFile *out, uint64 out_size)
|
||||
(void)inflateEnd(&stream);
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
while (stream.avail_out == 0);
|
||||
}
|
||||
while (bytes_read != in_size);
|
||||
} while (stream.avail_out == 0);
|
||||
} while (bytes_read != in_size);
|
||||
|
||||
(void)inflateEnd(&stream);
|
||||
|
||||
@@ -513,12 +511,10 @@ PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
|
||||
return ret;
|
||||
}
|
||||
parser_debug(" File data inflation complete!\n");
|
||||
}
|
||||
else if (!memcmp(buffer, padding, 7)) {
|
||||
} else if (!memcmp(buffer, padding, 7)) {
|
||||
*done = true;
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
parser_debug("_ParseData unknown tag\n");
|
||||
ret = B_ERROR;
|
||||
}
|
||||
@@ -530,10 +526,10 @@ PackageItem::ParseData(uint8 *buffer, BFile *file, uint64 originalSize,
|
||||
// #pragma mark - PackageScript
|
||||
|
||||
|
||||
PackageScript::PackageScript(BFile *parent, uint64 offset, uint64 size,
|
||||
uint64 originalSize)
|
||||
PackageScript::PackageScript(BFile* parent, const BString& path, uint64 offset,
|
||||
uint64 size, uint64 originalSize)
|
||||
:
|
||||
PackageItem(parent, NULL, 0, 0, 0, offset, size),
|
||||
PackageItem(parent, path, P_INSTALL_PATH, 0, 0, offset, size),
|
||||
fOriginalSize(originalSize),
|
||||
fThreadId(-1)
|
||||
{
|
||||
@@ -579,8 +575,29 @@ PackageScript::DoInstall(const char *path, ItemState *state)
|
||||
break;
|
||||
|
||||
case P_DATA:
|
||||
ret = _ParseScript(buffer, fOriginalSize, &done);
|
||||
{
|
||||
BString script;
|
||||
ret = _ParseScript(buffer, fOriginalSize, script, &done);
|
||||
if (ret == B_OK) {
|
||||
// Rewrite Deskbar entry targets. NOTE: It would
|
||||
// also work to Replace("/config/be", "/config...")
|
||||
// but it would be less save. For example, an app
|
||||
// could have a folder named "config/be..." inside
|
||||
// its installation folder.
|
||||
script.ReplaceAll(
|
||||
"~/config/be",
|
||||
"~/config/settings/deskbar/menu");
|
||||
script.ReplaceAll(
|
||||
"/boot/home/config/be",
|
||||
"/boot/home/config/settings/deskbar/menu");
|
||||
|
||||
BPath workingDirectory;
|
||||
ret = InitPath(path, &workingDirectory);
|
||||
if (ret == B_OK)
|
||||
ret = _RunScript(workingDirectory.Path(), script);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
@@ -604,7 +621,8 @@ PackageScript::ItemKind()
|
||||
|
||||
|
||||
status_t
|
||||
PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, bool *done)
|
||||
PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize,
|
||||
BString& _script, bool *done)
|
||||
{
|
||||
status_t ret = B_OK;
|
||||
|
||||
@@ -649,7 +667,8 @@ PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, bool *done)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = _RunScript(script, originalSize);
|
||||
_script.SetTo((char*)script, originalSize);
|
||||
|
||||
delete[] script;
|
||||
delete[] temp;
|
||||
parser_debug(" Script data inflation complete!\n");
|
||||
@@ -666,13 +685,18 @@ PackageScript::_ParseScript(uint8 *buffer, uint64 originalSize, bool *done)
|
||||
|
||||
|
||||
status_t
|
||||
PackageScript::_RunScript(uint8 *script, uint32 len)
|
||||
PackageScript::_RunScript(const char* workingDirectory, const BString& script)
|
||||
{
|
||||
// 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
|
||||
|
||||
// Change current working directory to install path
|
||||
char oldWorkingDirectory[B_PATH_NAME_LENGTH];
|
||||
getcwd(oldWorkingDirectory, sizeof(oldWorkingDirectory));
|
||||
chdir(workingDirectory);
|
||||
|
||||
// Save current FDs
|
||||
int old_in = dup(0);
|
||||
int old_out = dup(1);
|
||||
@@ -714,12 +738,16 @@ PackageScript::_RunScript(uint8 *script, uint32 len)
|
||||
resume_thread(fThreadId);
|
||||
|
||||
// Write the script
|
||||
if (write(in, script, len) != (int32)len || write(in, "\nexit\n", 6) != 6) {
|
||||
if (write(in, script.String(), script.Length() - 1) != script.Length() - 1
|
||||
|| write(in, "\nexit\n", 6) != 6) {
|
||||
parser_debug("Writing script failed\n");
|
||||
kill_thread(fThreadId);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// Restore current working directory
|
||||
chdir(oldWorkingDirectory);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,7 @@ public:
|
||||
status_t ParseData(uint8* buffer, BFile* file,
|
||||
uint64 originalSize, bool* done);
|
||||
|
||||
protected:
|
||||
BString fPath;
|
||||
uint64 fOffset;
|
||||
uint64 fSize;
|
||||
@@ -127,8 +128,9 @@ public:
|
||||
|
||||
class PackageScript : public PackageItem {
|
||||
public:
|
||||
PackageScript(BFile* parent, uint64 offset = 0,
|
||||
uint64 size = 0, uint64 originalSize = 0);
|
||||
PackageScript(BFile* parent, const BString& path,
|
||||
uint64 offset = 0, uint64 size = 0,
|
||||
uint64 originalSize = 0);
|
||||
|
||||
virtual status_t DoInstall(const char* path = NULL,
|
||||
ItemState *state = NULL);
|
||||
@@ -139,9 +141,11 @@ public:
|
||||
|
||||
private:
|
||||
status_t _ParseScript(uint8* buffer, uint64 originalSize,
|
||||
bool *done);
|
||||
status_t _RunScript(uint8 *script, uint32 len);
|
||||
BString& script, bool* done);
|
||||
status_t _RunScript(const char* workingDirectory,
|
||||
const BString& script);
|
||||
|
||||
private:
|
||||
uint64 fOriginalSize;
|
||||
thread_id fThreadId;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user