144f919daSRyan Leavengood/*
244f919daSRyan Leavengood * Copyright (c) 2007, Haiku, Inc.
344f919daSRyan Leavengood * Distributed under the terms of the MIT license.
444f919daSRyan Leavengood *
544f919daSRyan Leavengood * Author:
644f919daSRyan Leavengood *		��ukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
744f919daSRyan Leavengood */
844f919daSRyan Leavengood
944f919daSRyan Leavengood
1044f919daSRyan Leavengood#include "InstalledPackageInfo.h"
1122df5cfaSAxel Dörfler
1244f919daSRyan Leavengood#include <stdio.h>
1344f919daSRyan Leavengood#include <string.h>
1422df5cfaSAxel Dörfler
1522df5cfaSAxel Dörfler#include <Directory.h>
1622df5cfaSAxel Dörfler#include <Entry.h>
1722df5cfaSAxel Dörfler#include <FindDirectory.h>
1844f919daSRyan Leavengood
1944f919daSRyan Leavengood
2044f919daSRyan Leavengoodconst char * kPackagesDir = "packages";
2144f919daSRyan Leavengood
2244f919daSRyan Leavengood
2344f919daSRyan Leavengoodstatic status_t
2444f919daSRyan Leavengoodinfo_prepare(const char *filename, BFile *file, BMessage *info)
2544f919daSRyan Leavengood{
26714c386aSStephan Aßmus	if (filename == NULL || file == NULL || info == NULL)
27714c386aSStephan Aßmus		return B_BAD_VALUE;
2844f919daSRyan Leavengood
2944f919daSRyan Leavengood	BPath path;
30714c386aSStephan Aßmus	status_t ret = find_directory(B_USER_CONFIG_DIRECTORY, &path);
31714c386aSStephan Aßmus	if (ret == B_OK)
32714c386aSStephan Aßmus		ret = path.Append(kPackagesDir);
33714c386aSStephan Aßmus	if (ret == B_OK)
34714c386aSStephan Aßmus		ret = path.Append(filename);
35714c386aSStephan Aßmus	if (ret == B_OK)
36714c386aSStephan Aßmus		ret = file->SetTo(path.Path(), B_READ_ONLY);
37714c386aSStephan Aßmus	if (ret == B_OK)
38714c386aSStephan Aßmus		ret = info->Unflatten(file);
39714c386aSStephan Aßmus	if (ret == B_OK && info->what != P_PACKAGE_INFO)
40714c386aSStephan Aßmus		ret = B_ERROR;
41714c386aSStephan Aßmus
42714c386aSStephan Aßmus	return ret;
4344f919daSRyan Leavengood}
4444f919daSRyan Leavengood
4544f919daSRyan Leavengood
46714c386aSStephan Aßmusstatus_t
47714c386aSStephan Aßmusinfo_get_package_name(const char *filename, BString &name)
4844f919daSRyan Leavengood{
4944f919daSRyan Leavengood	BFile file;
5044f919daSRyan Leavengood	BMessage info;
51714c386aSStephan Aßmus	status_t ret = info_prepare(filename, &file, &info);
52714c386aSStephan Aßmus	if (ret == B_OK)
53714c386aSStephan Aßmus		ret = info.FindString("package_name", &name);
54714c386aSStephan Aßmus	return ret;
5544f919daSRyan Leavengood}
5644f919daSRyan Leavengood
5744f919daSRyan Leavengood
58714c386aSStephan Aßmusstatus_t
59714c386aSStephan Aßmusinfo_get_package_version(const char *filename, BString &version)
6044f919daSRyan Leavengood{
6144f919daSRyan Leavengood	BFile file;
6244f919daSRyan Leavengood	BMessage info;
63714c386aSStephan Aßmus	status_t ret = info_prepare(filename, &file, &info);
64714c386aSStephan Aßmus	if (ret == B_OK)
65714c386aSStephan Aßmus		ret = info.FindString("package_version", &version);
66714c386aSStephan Aßmus	return ret;
6744f919daSRyan Leavengood}
6844f919daSRyan Leavengood
6944f919daSRyan Leavengood
7044f919daSRyan LeavengoodInstalledPackageInfo::InstalledPackageInfo()
7144f919daSRyan Leavengood	:
7244f919daSRyan Leavengood	fStatus(B_NO_INIT),
7344f919daSRyan Leavengood	fIsUpToDate(false),
7444f919daSRyan Leavengood	fCreate(false),
7565cd35f0SRyan Leavengood	fSpaceNeeded(0),
7644f919daSRyan Leavengood	fInstalledItems(10)
7744f919daSRyan Leavengood{
7844f919daSRyan Leavengood}
7944f919daSRyan Leavengood
8044f919daSRyan Leavengood
8144f919daSRyan LeavengoodInstalledPackageInfo::InstalledPackageInfo(const char *packageName,
8244f919daSRyan Leavengood		const char *version, bool create)
8344f919daSRyan Leavengood	:
8444f919daSRyan Leavengood	fStatus(B_NO_INIT),
8544f919daSRyan Leavengood	fIsUpToDate(false),
8665cd35f0SRyan Leavengood	fSpaceNeeded(0),
8744f919daSRyan Leavengood	fInstalledItems(10)
8844f919daSRyan Leavengood{
8944f919daSRyan Leavengood	SetTo(packageName, version, create);
9044f919daSRyan Leavengood}
9144f919daSRyan Leavengood
9244f919daSRyan Leavengood
9344f919daSRyan LeavengoodInstalledPackageInfo::~InstalledPackageInfo()
9444f919daSRyan Leavengood{
9544f919daSRyan Leavengood	_ClearItemList();
9644f919daSRyan Leavengood}
9744f919daSRyan Leavengood
9844f919daSRyan Leavengood
9944f919daSRyan Leavengoodstatus_t
10044f919daSRyan LeavengoodInstalledPackageInfo::InitCheck()
10144f919daSRyan Leavengood{
10244f919daSRyan Leavengood	return fStatus;
10344f919daSRyan Leavengood}
10444f919daSRyan Leavengood
10544f919daSRyan Leavengood
10644f919daSRyan Leavengoodstatus_t
10744f919daSRyan LeavengoodInstalledPackageInfo::SetTo(const char *packageName, const char *version,
10844507374SStephan Aßmus	bool create)
10944f919daSRyan Leavengood{
11044f919daSRyan Leavengood	_ClearItemList();
11144507374SStephan Aßmus
11244f919daSRyan Leavengood	fCreate = create;
11344f919daSRyan Leavengood	fStatus = B_NO_INIT;
11444f919daSRyan Leavengood	fVersion = version;
11544f919daSRyan Leavengood
11644f919daSRyan Leavengood	if (!packageName)
11744f919daSRyan Leavengood		return fStatus;
11844f919daSRyan Leavengood
11944f919daSRyan Leavengood	BPath configPath;
12044f919daSRyan Leavengood	if (find_directory(B_USER_CONFIG_DIRECTORY, &configPath) != B_OK) {
12144f919daSRyan Leavengood		fStatus = B_ERROR;
12244f919daSRyan Leavengood		return fStatus;
12344f919daSRyan Leavengood	}
12444f919daSRyan Leavengood
12544f919daSRyan Leavengood	if (fPathToInfo.SetTo(configPath.Path(), kPackagesDir) != B_OK) {
12644f919daSRyan Leavengood		fStatus = B_ERROR;
12744f919daSRyan Leavengood		return fStatus;
12844f919daSRyan Leavengood	}
12944f919daSRyan Leavengood
13044f919daSRyan Leavengood	// Check whether the directory exists
13144f919daSRyan Leavengood	BDirectory packageDir(fPathToInfo.Path());
13244f919daSRyan Leavengood	fStatus = packageDir.InitCheck();
13344f919daSRyan Leavengood	if (fStatus == B_ENTRY_NOT_FOUND) {
13444f919daSRyan Leavengood		// If not, create it
13544f919daSRyan Leavengood		packageDir.SetTo(configPath.Path());
13644f919daSRyan Leavengood		if (packageDir.CreateDirectory(kPackagesDir, &packageDir) != B_OK) {
13744f919daSRyan Leavengood			fStatus = B_ERROR;
13844f919daSRyan Leavengood			return fStatus;
13944f919daSRyan Leavengood		}
14044f919daSRyan Leavengood	}
14144f919daSRyan Leavengood
14244f919daSRyan Leavengood	BString filename = packageName;
14344f919daSRyan Leavengood	filename << version << ".pdb";
14444f919daSRyan Leavengood	if (fPathToInfo.Append(filename.String()) != B_OK) {
14544f919daSRyan Leavengood		fStatus = B_ERROR;
14644f919daSRyan Leavengood		return fStatus;
14744f919daSRyan Leavengood	}
14844f919daSRyan Leavengood
14944f919daSRyan Leavengood	BFile package(fPathToInfo.Path(), B_READ_ONLY);
15044f919daSRyan Leavengood	fStatus = package.InitCheck();
15144f919daSRyan Leavengood	if (fStatus == B_OK) {
15244f919daSRyan Leavengood		// The given package exists, so we can unflatten the data to a message
15344f919daSRyan Leavengood		// and then pass it further
15444f919daSRyan Leavengood		BMessage info;
15544f919daSRyan Leavengood		if (info.Unflatten(&package) != B_OK || info.what != P_PACKAGE_INFO) {
15644f919daSRyan Leavengood			fStatus = B_ERROR;
15744f919daSRyan Leavengood			return fStatus;
15844f919daSRyan Leavengood		}
15944f919daSRyan Leavengood
16044f919daSRyan Leavengood		int32 count;
16144f919daSRyan Leavengood		fStatus = info.FindString("package_name", &fName);
16244f919daSRyan Leavengood		fStatus |= info.FindString("package_desc", &fDescription);
16344f919daSRyan Leavengood		fStatus |= info.FindString("package_version", &fVersion);
16444f919daSRyan Leavengood		int64 spaceNeeded = 0;
16544f919daSRyan Leavengood		fStatus |= info.FindInt64("package_size", &spaceNeeded);
16644f919daSRyan Leavengood		fSpaceNeeded = static_cast<uint64>(spaceNeeded);
16744f919daSRyan Leavengood		fStatus |= info.FindInt32("file_count", &count);
16844f919daSRyan Leavengood		if (fStatus != B_OK) {
16944f919daSRyan Leavengood			fStatus = B_ERROR;
17044f919daSRyan Leavengood			return fStatus;
17144f919daSRyan Leavengood		}
17244f919daSRyan Leavengood
17344f919daSRyan Leavengood		int32 i;
17444f919daSRyan Leavengood		BString itemPath;
17544f919daSRyan Leavengood		for (i = 0; i < count; i++) {
17644f919daSRyan Leavengood			if (info.FindString("items", i, &itemPath) != B_OK) {
17744f919daSRyan Leavengood				fStatus = B_ERROR;
17844f919daSRyan Leavengood				return fStatus;
17944f919daSRyan Leavengood			}
18044f919daSRyan Leavengood			fInstalledItems.AddItem(new BString(itemPath)); // Or maybe BPath better?
18144f919daSRyan Leavengood		}
18244f919daSRyan Leavengood		fIsUpToDate = true;
18344507374SStephan Aßmus	} else if (fStatus == B_ENTRY_NOT_FOUND) {
18444f919daSRyan Leavengood		if (create) {
18544f919daSRyan Leavengood			fStatus = B_OK;
18644f919daSRyan Leavengood			fIsUpToDate = false;
18744f919daSRyan Leavengood		}
18844f919daSRyan Leavengood	}
18944f919daSRyan Leavengood
19044f919daSRyan Leavengood	return fStatus;
19144f919daSRyan Leavengood}
19244f919daSRyan Leavengood
19344f919daSRyan Leavengood
19444f919daSRyan Leavengoodstatus_t
19544f919daSRyan LeavengoodInstalledPackageInfo::AddItem(const char *itemName)
19644f919daSRyan Leavengood{
19744f919daSRyan Leavengood	if (!itemName)
19844f919daSRyan Leavengood		return B_ERROR;
19944f919daSRyan Leavengood
20044f919daSRyan Leavengood	return fInstalledItems.AddItem(new BString(itemName));
20144f919daSRyan Leavengood}
20244f919daSRyan Leavengood
20344f919daSRyan Leavengood
20444f919daSRyan Leavengoodstatus_t
20544f919daSRyan LeavengoodInstalledPackageInfo::Uninstall()
20644f919daSRyan Leavengood{
20744f919daSRyan Leavengood	if (fStatus != B_OK)
20844f919daSRyan Leavengood		return fStatus;
20944f919daSRyan Leavengood
21044f919daSRyan Leavengood	BString *iter;
21144f919daSRyan Leavengood	uint32 i, count = fInstalledItems.CountItems();
21244f919daSRyan Leavengood	BEntry entry;
21344f919daSRyan Leavengood	status_t ret;
21444f919daSRyan Leavengood
21544f919daSRyan Leavengood	// Try to remove all entries that are present in the list
21644f919daSRyan Leavengood	for (i = 0; i < count; i++) {
21744f919daSRyan Leavengood		iter = static_cast<BString *>(fInstalledItems.ItemAt(count - i - 1));
21844f919daSRyan Leavengood		ret = entry.SetTo(iter->String());
21944f919daSRyan Leavengood		if (ret == B_BUSY) {
22044f919daSRyan Leavengood			// The entry's directory is locked - wait a few cycles for it to
22144f919daSRyan Leavengood			// unlock itself
22244f919daSRyan Leavengood			int32 tries = 0;
22344f919daSRyan Leavengood			for (tries = 0; tries < P_BUSY_TRIES; tries++) {
22444f919daSRyan Leavengood				ret = entry.SetTo(iter->String());
22544f919daSRyan Leavengood				if (ret != B_BUSY)
22644f919daSRyan Leavengood					break;
22744f919daSRyan Leavengood				// Wait a moment
22844f919daSRyan Leavengood				usleep(1000);
22944f919daSRyan Leavengood			}
23044f919daSRyan Leavengood		}
23144f919daSRyan Leavengood
23244f919daSRyan Leavengood		if (ret == B_ENTRY_NOT_FOUND)
23344f919daSRyan Leavengood			continue;
23444f919daSRyan Leavengood		else if (ret != B_OK) {
23544f919daSRyan Leavengood			fStatus = B_ERROR;
23644f919daSRyan Leavengood			return fStatus;
23744f919daSRyan Leavengood		}
23844f919daSRyan Leavengood
23944f919daSRyan Leavengood		if (entry.Exists() && entry.Remove() != B_OK) {
24044f919daSRyan Leavengood			fStatus = B_ERROR;
24144f919daSRyan Leavengood			return fStatus;
24244f919daSRyan Leavengood		}
24344f919daSRyan Leavengood		fInstalledItems.RemoveItem(count - i - 1);
24444f919daSRyan Leavengood	}
24544f919daSRyan Leavengood
24644f919daSRyan Leavengood	if (entry.SetTo(fPathToInfo.Path()) != B_OK) {
24744f919daSRyan Leavengood		fStatus = B_ERROR;
24844f919daSRyan Leavengood		return fStatus;
24944f919daSRyan Leavengood	}
25044f919daSRyan Leavengood	if (entry.Exists() && entry.Remove() != B_OK) {
25144f919daSRyan Leavengood		fStatus = B_ERROR;
25244f919daSRyan Leavengood		return fStatus;
25344f919daSRyan Leavengood	}
25444f919daSRyan Leavengood
25544f919daSRyan Leavengood	return fStatus;
25644f919daSRyan Leavengood}
25744f919daSRyan Leavengood
25844f919daSRyan Leavengood
25944f919daSRyan Leavengoodstatus_t
26044f919daSRyan LeavengoodInstalledPackageInfo::Save()
26144f919daSRyan Leavengood{
26244f919daSRyan Leavengood	// If the package info is not up to date and everything till now was
26344f919daSRyan Leavengood	// done correctly, we will save all data as a flattened BMessage to the
26444f919daSRyan Leavengood	// package info file
26544f919daSRyan Leavengood	if (fIsUpToDate || fStatus != B_OK)
26644f919daSRyan Leavengood		return fStatus;
26744f919daSRyan Leavengood
26844f919daSRyan Leavengood	BFile package;
26944f919daSRyan Leavengood	if (fCreate) {
27044f919daSRyan Leavengood		fStatus = package.SetTo(fPathToInfo.Path(), B_WRITE_ONLY | B_CREATE_FILE
27144f919daSRyan Leavengood			| B_ERASE_FILE);
27244f919daSRyan Leavengood	}
27344f919daSRyan Leavengood	else {
27444f919daSRyan Leavengood		fStatus = package.SetTo(fPathToInfo.Path(), B_WRITE_ONLY | B_ERASE_FILE);
27544f919daSRyan Leavengood	}
27644f919daSRyan Leavengood
27744f919daSRyan Leavengood	if (fStatus != B_OK)
27844f919daSRyan Leavengood		return fStatus;
27944f919daSRyan Leavengood
28044f919daSRyan Leavengood	status_t ret;
28144f919daSRyan Leavengood	int32 i, count = fInstalledItems.CountItems();
28244f919daSRyan Leavengood	BMessage info(P_PACKAGE_INFO);
28344f919daSRyan Leavengood	ret = info.AddString("package_name", fName);
28444f919daSRyan Leavengood	ret |= info.AddString("package_desc", fDescription);
28544f919daSRyan Leavengood	ret |= info.AddString("package_version", fVersion);
28644f919daSRyan Leavengood	ret |= info.AddInt64("package_size", fSpaceNeeded);
28744f919daSRyan Leavengood	ret |= info.AddInt32("file_count", count);
28844f919daSRyan Leavengood	if (ret != B_OK) {
28944f919daSRyan Leavengood		fStatus = B_ERROR;
29044f919daSRyan Leavengood		return fStatus;
29144f919daSRyan Leavengood	}
29244f919daSRyan Leavengood
29344f919daSRyan Leavengood	BString *iter;
29444f919daSRyan Leavengood	for (i = 0; i < count; i++) {
29544f919daSRyan Leavengood		iter = static_cast<BString *>(fInstalledItems.ItemAt(i));
29644f919daSRyan Leavengood		if (info.AddString("items", *iter) != B_OK) {
29744f919daSRyan Leavengood			fStatus = B_ERROR;
29844f919daSRyan Leavengood			return fStatus;
29944f919daSRyan Leavengood		}
30044f919daSRyan Leavengood	}
30144f919daSRyan Leavengood
30244f919daSRyan Leavengood	if (info.Flatten(&package) != B_OK) {
30344f919daSRyan Leavengood		fStatus = B_ERROR;
30444f919daSRyan Leavengood		return fStatus;
30544f919daSRyan Leavengood	}
30644f919daSRyan Leavengood	fIsUpToDate = true;
30744f919daSRyan Leavengood
30844f919daSRyan Leavengood	return fStatus;
30944f919daSRyan Leavengood}
31044f919daSRyan Leavengood
31144f919daSRyan Leavengood
31244f919daSRyan Leavengood// #pragma mark -
31344f919daSRyan Leavengood
31444f919daSRyan Leavengood
31544f919daSRyan Leavengoodvoid
31644f919daSRyan LeavengoodInstalledPackageInfo::_ClearItemList()
31744f919daSRyan Leavengood{
31844507374SStephan Aßmus	for (int32 i = fInstalledItems.CountItems() - 1; i >= 0; i--)
31944507374SStephan Aßmus		delete static_cast<BString*>(fInstalledItems.ItemAtFast(i));
32044507374SStephan Aßmus	fInstalledItems.MakeEmpty();
32144f919daSRyan Leavengood}
32244f919daSRyan Leavengood
323