* Copyright 2013-2014, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#include <package/CommitTransactionResult.h>
#include <Message.h>
namespace BPackageKit {
BTransactionIssue::BTransactionIssue()
:
fType(B_WRITABLE_FILE_TYPE_MISMATCH),
fPackageName(),
fPath1(),
fPath2(),
fSystemError(B_OK),
fExitCode(0)
{
}
BTransactionIssue::BTransactionIssue(BType type, const BString& packageName,
const BString& path1, const BString& path2, status_t systemError,
int exitCode)
:
fType(type),
fPackageName(packageName),
fPath1(path1),
fPath2(path2),
fSystemError(systemError),
fExitCode(exitCode)
{
}
BTransactionIssue::BTransactionIssue(const BTransactionIssue& other)
{
*this = other;
}
BTransactionIssue::~BTransactionIssue()
{
}
BTransactionIssue::BType
BTransactionIssue::Type() const
{
return fType;
}
const BString&
BTransactionIssue::PackageName() const
{
return fPackageName;
}
const BString&
BTransactionIssue::Path1() const
{
return fPath1;
}
const BString&
BTransactionIssue::Path2() const
{
return fPath2;
}
status_t
BTransactionIssue::SystemError() const
{
return fSystemError;
}
int
BTransactionIssue::ExitCode() const
{
return fExitCode;
}
BString
BTransactionIssue::ToString() const
{
const char* messageTemplate = "";
switch (fType) {
case B_WRITABLE_FILE_TYPE_MISMATCH:
messageTemplate = "\"%path1%\" cannot be updated automatically,"
" since its type doesn't match the type of \"%path2%\" which it"
" is supposed to be updated with."
" Please perform the update manually if needed.";
break;
case B_WRITABLE_FILE_NO_PACKAGE_ATTRIBUTE:
messageTemplate = "\"%path1%\" cannot be updated automatically,"
" since it doesn't have a SYS:PACKAGE attribute."
" Please perform the update manually if needed.";
break;
case B_WRITABLE_FILE_OLD_ORIGINAL_FILE_MISSING:
messageTemplate = "\"%path1%\" cannot be updated automatically,"
" since \"%path2%\" which we need to compare it with is"
" missing."
" Please perform the update manually if needed.";
break;
case B_WRITABLE_FILE_OLD_ORIGINAL_FILE_TYPE_MISMATCH:
messageTemplate = "\"%path1%\" cannot be updated automatically,"
" since its type doesn't match the type of \"%path2%\" which we"
" need to compare it with."
" Please perform the update manually if needed.";
break;
case B_WRITABLE_FILE_COMPARISON_FAILED:
messageTemplate = "\"%path1%\" cannot be updated automatically,"
" since the comparison with \"%path2%\" failed: %error%."
" Please perform the update manually if needed.";
break;
case B_WRITABLE_FILE_NOT_EQUAL:
messageTemplate = "\"%path1%\" cannot be updated automatically,"
" since it was changed manually from previous version"
" \"%path2%\"."
" Please perform the update manually if needed.";
break;
case B_WRITABLE_SYMLINK_COMPARISON_FAILED:
messageTemplate = "Symbolic link \"%path1%\" cannot be updated"
" automatically, since the comparison with \"%path2%\" failed:"
" %error%."
" Please perform the update manually if needed.";
break;
case B_WRITABLE_SYMLINK_NOT_EQUAL:
messageTemplate = "Symbolic link \"%path1%\" cannot be updated"
" automatically, since it was changed manually from previous"
" version \"%path2%\"."
" Please perform the update manually if needed.";
break;
case B_POST_INSTALL_SCRIPT_NOT_FOUND:
messageTemplate = "Failed to find post-installation script "
" \"%path1%\": %error%.";
break;
case B_STARTING_POST_INSTALL_SCRIPT_FAILED:
messageTemplate = "Failed to run post-installation script "
" \"%path1%\": %error%.";
break;
case B_POST_INSTALL_SCRIPT_FAILED:
messageTemplate = "The post-installation script "
" \"%path1%\" failed with exit code %exitCode%.";
break;
case B_PRE_UNINSTALL_SCRIPT_NOT_FOUND:
messageTemplate = "Failed to find pre-uninstall script "
" \"%path1%\": %error%.";
break;
case B_STARTING_PRE_UNINSTALL_SCRIPT_FAILED:
messageTemplate = "Failed to run pre-uninstall script "
" \"%path1%\": %error%.";
break;
case B_PRE_UNINSTALL_SCRIPT_FAILED:
messageTemplate = "The pre-uninstall script "
" \"%path1%\" failed with exit code %exitCode%.";
break;
}
BString message(messageTemplate);
message.ReplaceAll("%path1%", fPath1)
.ReplaceAll("%path2%", fPath2)
.ReplaceAll("%error%", strerror(fSystemError))
.ReplaceAll("%exitCode%", BString() << fExitCode);
return message;
}
status_t
BTransactionIssue::AddToMessage(BMessage& message) const
{
status_t error;
if ((error = message.AddInt32("type", (int32)fType)) != B_OK
|| (error = message.AddString("package", fPackageName)) != B_OK
|| (error = message.AddString("path1", fPath1)) != B_OK
|| (error = message.AddString("path2", fPath2)) != B_OK
|| (error = message.AddInt32("system error", (int32)fSystemError))
!= B_OK
|| (error = message.AddInt32("exit code", (int32)fExitCode)) != B_OK) {
return error;
}
return B_OK;
}
status_t
BTransactionIssue::ExtractFromMessage(const BMessage& message)
{
status_t error;
int32 type;
int32 systemError;
int32 exitCode;
if ((error = message.FindInt32("type", &type)) != B_OK
|| (error = message.FindString("package", &fPackageName)) != B_OK
|| (error = message.FindString("path1", &fPath1)) != B_OK
|| (error = message.FindString("path2", &fPath2)) != B_OK
|| (error = message.FindInt32("system error", &systemError)) != B_OK
|| (error = message.FindInt32("exit code", &exitCode)) != B_OK) {
return error;
}
fType = (BType)type;
fSystemError = (status_t)systemError;
fExitCode = (int)exitCode;
return B_OK;
}
BTransactionIssue&
BTransactionIssue::operator=(const BTransactionIssue& other)
{
fType = other.fType;
fPackageName = other.fPackageName;
fPath1 = other.fPath1;
fPath2 = other.fPath2;
fSystemError = other.fSystemError;
fExitCode = other.fExitCode;
return *this;
}
BCommitTransactionResult::BCommitTransactionResult()
:
fError(B_TRANSACTION_INTERNAL_ERROR),
fSystemError(B_ERROR),
fErrorPackage(),
fPath1(),
fPath2(),
fString1(),
fString2(),
fOldStateDirectory(),
fIssues(10)
{
}
BCommitTransactionResult::BCommitTransactionResult(BTransactionError error)
:
fError(error),
fSystemError(B_ERROR),
fErrorPackage(),
fPath1(),
fPath2(),
fString1(),
fString2(),
fOldStateDirectory(),
fIssues(10)
{
}
BCommitTransactionResult::BCommitTransactionResult(
const BCommitTransactionResult& other)
:
fError(B_TRANSACTION_INTERNAL_ERROR),
fSystemError(B_ERROR),
fErrorPackage(),
fPath1(),
fPath2(),
fString1(),
fString2(),
fOldStateDirectory(),
fIssues(10)
{
*this = other;
}
BCommitTransactionResult::~BCommitTransactionResult()
{
}
void
BCommitTransactionResult::Unset()
{
fError = B_TRANSACTION_INTERNAL_ERROR;
fSystemError = B_ERROR;
fErrorPackage.Truncate(0);
fPath1.Truncate(0);
fPath2.Truncate(0);
fString1.Truncate(0);
fString2.Truncate(0);
fOldStateDirectory.Truncate(0);
fIssues.MakeEmpty();
}
int32
BCommitTransactionResult::CountIssues() const
{
return fIssues.CountItems();
}
const BTransactionIssue*
BCommitTransactionResult::IssueAt(int32 index) const
{
if (index < 0 || index >= CountIssues())
return NULL;
return fIssues.ItemAt(index);
}
bool
BCommitTransactionResult::AddIssue(const BTransactionIssue& issue)
{
BTransactionIssue* newIssue = new(std::nothrow) BTransactionIssue(issue);
if (newIssue == NULL || !fIssues.AddItem(newIssue)) {
delete newIssue;
return false;
}
return true;
}
BTransactionError
BCommitTransactionResult::Error() const
{
return fError > 0 ? (BTransactionError)fError : B_TRANSACTION_OK;
}
void
BCommitTransactionResult::SetError(BTransactionError error)
{
fError = error;
}
status_t
BCommitTransactionResult::SystemError() const
{
return fSystemError;
}
void
BCommitTransactionResult::SetSystemError(status_t error)
{
fSystemError = error;
}
const BString&
BCommitTransactionResult::ErrorPackage() const
{
return fErrorPackage;
}
void
BCommitTransactionResult::SetErrorPackage(const BString& packageName)
{
fErrorPackage = packageName;
}
BString
BCommitTransactionResult::FullErrorMessage() const
{
if (fError == 0)
return "no error";
const char* messageTemplate = "";
switch ((BTransactionError)fError) {
case B_TRANSACTION_OK:
messageTemplate = "Everything went fine.";
break;
case B_TRANSACTION_NO_MEMORY:
messageTemplate = "Out of memory.";
break;
case B_TRANSACTION_INTERNAL_ERROR:
messageTemplate = "An internal error occurred. Specifics can be"
" found in the syslog.";
break;
case B_TRANSACTION_INSTALLATION_LOCATION_BUSY:
messageTemplate = "Another package operation is already in"
" progress.";
break;
case B_TRANSACTION_CHANGE_COUNT_MISMATCH:
messageTemplate = "The transaction is out of date.";
break;
case B_TRANSACTION_BAD_REQUEST:
messageTemplate = "The requested transaction is invalid.";
break;
case B_TRANSACTION_NO_SUCH_PACKAGE:
messageTemplate = "No such package \"%package%\".";
break;
case B_TRANSACTION_PACKAGE_ALREADY_EXISTS:
messageTemplate = "The to be activated package \"%package%\" does"
" already exist.";
break;
case B_TRANSACTION_FAILED_TO_GET_ENTRY_PATH:
if (fPath1.IsEmpty()) {
if (fErrorPackage.IsEmpty()) {
messageTemplate = "A file path could not be determined:"
"%error%";
} else {
messageTemplate = "While processing package \"%package%\""
" a file path could not be determined: %error%";
}
} else {
if (fErrorPackage.IsEmpty()) {
messageTemplate = "The file path for \"%path1%\" could not"
" be determined: %error%";
} else {
messageTemplate = "While processing package \"%package%\""
" the file path for \"%path1%\" could not be"
" determined: %error%";
}
}
break;
case B_TRANSACTION_FAILED_TO_OPEN_DIRECTORY:
messageTemplate = "Failed to open directory \"%path1%\": %error%";
break;
case B_TRANSACTION_FAILED_TO_CREATE_DIRECTORY:
messageTemplate = "Failed to create directory \"%path1%\": %error%";
break;
case B_TRANSACTION_FAILED_TO_REMOVE_DIRECTORY:
messageTemplate = "Failed to remove directory \"%path1%\": %error%";
break;
case B_TRANSACTION_FAILED_TO_MOVE_DIRECTORY:
messageTemplate = "Failed to move directory \"%path1%\" to"
" \"%path2%\": %error%";
break;
case B_TRANSACTION_FAILED_TO_WRITE_ACTIVATION_FILE:
messageTemplate = "Failed to write new package activation file"
" \"%path1%\": %error%";
break;
case B_TRANSACTION_FAILED_TO_READ_PACKAGE_FILE:
messageTemplate = "Failed to read package file \"%path1%\":"
" %error%";
break;
case B_TRANSACTION_FAILED_TO_EXTRACT_PACKAGE_FILE:
messageTemplate = "Failed to extract \"%path1%\" from package"
" \"%package%\": %error%";
break;
case B_TRANSACTION_FAILED_TO_OPEN_FILE:
messageTemplate = "Failed to open file \"%path1%\": %error%";
break;
case B_TRANSACTION_FAILED_TO_MOVE_FILE:
messageTemplate = "Failed to move file \"%path1%\" to \"%path2%\":"
" %error%";
break;
case B_TRANSACTION_FAILED_TO_COPY_FILE:
messageTemplate = "Failed to copy file \"%path1%\" to \"%path2%\":"
" %error%";
break;
case B_TRANSACTION_FAILED_TO_WRITE_FILE_ATTRIBUTE:
messageTemplate = "Failed to write attribute \"%string1%\" of file"
" \"%path1%\": %error%";
break;
case B_TRANSACTION_FAILED_TO_ACCESS_ENTRY:
messageTemplate = "Failed to access entry \"%path1%\": %error%";
break;
case B_TRANSACTION_FAILED_TO_ADD_GROUP:
messageTemplate = "Failed to add user group \"%string1%\" required"
" by package \"%package%\".";
break;
case B_TRANSACTION_FAILED_TO_ADD_USER:
messageTemplate = "Failed to add user \"%string1%\" required"
" by package \"%package%\".";
break;
case B_TRANSACTION_FAILED_TO_ADD_USER_TO_GROUP:
messageTemplate = "Failed to add user \"%string1%\" to group"
" \"%string2%\" as required by package \"%package%\".";
break;
case B_TRANSACTION_FAILED_TO_CHANGE_PACKAGE_ACTIVATION:
messageTemplate = "Failed to change the package activation in"
" packagefs: %error%";
break;
}
BString message(messageTemplate);
message.ReplaceAll("%package%", fErrorPackage)
.ReplaceAll("%path1%", fPath1)
.ReplaceAll("%path2%", fPath2)
.ReplaceAll("%string1%", fString1)
.ReplaceAll("%string2%", fString2)
.ReplaceAll("%error%", strerror(fSystemError));
return message;
}
const BString&
BCommitTransactionResult::Path1() const
{
return fPath1;
}
void
BCommitTransactionResult::SetPath1(const BString& path)
{
fPath1 = path;
}
const BString&
BCommitTransactionResult::Path2() const
{
return fPath2;
}
void
BCommitTransactionResult::SetPath2(const BString& path)
{
fPath2 = path;
}
const BString&
BCommitTransactionResult::String1() const
{
return fString1;
}
void
BCommitTransactionResult::SetString1(const BString& string)
{
fString1 = string;
}
const BString&
BCommitTransactionResult::String2() const
{
return fString2;
}
void
BCommitTransactionResult::SetString2(const BString& string)
{
fString2 = string;
}
const BString&
BCommitTransactionResult::OldStateDirectory() const
{
return fOldStateDirectory;
}
void
BCommitTransactionResult::SetOldStateDirectory(const BString& directory)
{
fOldStateDirectory = directory;
}
status_t
BCommitTransactionResult::AddToMessage(BMessage& message) const
{
status_t error;
if ((error = message.AddInt32("error", (int32)fError)) != B_OK
|| (error = message.AddInt32("system error", (int32)fSystemError))
!= B_OK
|| (error = message.AddString("error package", fErrorPackage)) != B_OK
|| (error = message.AddString("path1", fPath1)) != B_OK
|| (error = message.AddString("path2", fPath2)) != B_OK
|| (error = message.AddString("string1", fString1)) != B_OK
|| (error = message.AddString("string2", fString2)) != B_OK
|| (error = message.AddString("old state", fOldStateDirectory))
!= B_OK) {
return error;
}
int32 count = fIssues.CountItems();
for (int32 i = 0; i < count; i++) {
const BTransactionIssue* issue = fIssues.ItemAt(i);
BMessage issueMessage;
if ((error = issue->AddToMessage(issueMessage)) != B_OK
|| (error = message.AddMessage("issues", &issueMessage)) != B_OK) {
return error;
}
}
return B_OK;
}
status_t
BCommitTransactionResult::ExtractFromMessage(const BMessage& message)
{
Unset();
int32 resultError;
int32 systemError;
status_t error;
if ((error = message.FindInt32("error", &resultError)) != B_OK
|| (error = message.FindInt32("system error", &systemError)) != B_OK
|| (error = message.FindString("error package", &fErrorPackage)) != B_OK
|| (error = message.FindString("path1", &fPath1)) != B_OK
|| (error = message.FindString("path2", &fPath2)) != B_OK
|| (error = message.FindString("string1", &fString1)) != B_OK
|| (error = message.FindString("string2", &fString2)) != B_OK
|| (error = message.FindString("old state", &fOldStateDirectory))
!= B_OK) {
return error;
}
fError = (BTransactionError)resultError;
fSystemError = (status_t)systemError;
BMessage issueMessage;
for (int32 i = 0; message.FindMessage("issues", i, &issueMessage) == B_OK;
i++) {
BTransactionIssue issue;
error = issue.ExtractFromMessage(issueMessage);
if (error != B_OK)
return error;
if (!AddIssue(issue))
return B_NO_MEMORY;
}
return B_OK;
}
BCommitTransactionResult&
BCommitTransactionResult::operator=(const BCommitTransactionResult& other)
{
Unset();
fError = other.fError;
fSystemError = other.fSystemError;
fErrorPackage = other.fErrorPackage;
fPath1 = other.fPath1;
fPath2 = other.fPath2;
fString1 = other.fString1;
fString2 = other.fString2;
fOldStateDirectory = other.fOldStateDirectory;
for (int32 i = 0; const BTransactionIssue* issue = other.fIssues.ItemAt(i);
i++) {
AddIssue(*issue);
}
return *this;
}
}