packagefs: Support blacklisting entries in packages
In each installation location, it is now possible to create a settings file "packages" that allows to blacklist entries contained in packages. The format is: Package <package name> { EntryBlacklist { <entry path> ... } } ... <package name> is the base name (no version) of the respective package (e.g. "haiku"), <entry path> is an installation location relative path (e.g. "add-ons/Translators/FooTranslator"). Blacklisted entries will be ignored by packagefs, i.e. they won't appear in the file system. This addresses the issue that it may be necessary to remove a problematic file (e.g. driver, add-on, or library), which would otherwise require editing the containing package file. The settings file is not not "live". Changes take effect only after reboot (respectively when remounting the concerned packagefs volume).
This commit is contained in:
parent
2fdd1d9ef1
commit
3a7e0b0014
@ -38,6 +38,7 @@
|
||||
#define kSystemPackageLinksDirectory "/boot/system/package-links"
|
||||
#define kSystemPreferencesDirectory "/boot/system/preferences"
|
||||
#define kSystemServersDirectory "/boot/system/servers"
|
||||
#define kSystemSettingsDirectory "/boot/system/settings"
|
||||
|
||||
#define kSystemEtcDirectory "/boot/system/settings/etc"
|
||||
#define kSystemTempDirectory "/boot/system/cache/tmp"
|
||||
@ -55,6 +56,7 @@
|
||||
#define kUserLibDirectory "/boot/home/config/lib"
|
||||
#define kUserPackagesDirectory "/boot/home/config/packages"
|
||||
#define kUserSettingsDirectory "/boot/home/config/settings"
|
||||
#define kUserSettingsGlobalDirectory "/boot/home/config/settings/global"
|
||||
#define kUserNonpackagedDirectory "/boot/home/config/non-packaged"
|
||||
#define kUserNonpackagedAddonsDirectory "/boot/home/config/non-packaged/add-ons"
|
||||
#define kUserNonpackagedBinDirectory "/boot/home/config/non-packaged/bin"
|
||||
|
@ -50,6 +50,7 @@ HAIKU_PACKAGE_FS_SOURCES =
|
||||
PackageLinkSymlink.cpp
|
||||
PackageNode.cpp
|
||||
PackageNodeAttribute.cpp
|
||||
PackageSettings.cpp
|
||||
PackageSymlink.cpp
|
||||
Resolvable.cpp
|
||||
ResolvableFamily.cpp
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "GlobalFactory.h"
|
||||
#include "PackageDirectory.h"
|
||||
#include "PackageFile.h"
|
||||
#include "PackageSettings.h"
|
||||
#include "PackageSymlink.h"
|
||||
#include "Version.h"
|
||||
#include "Volume.h"
|
||||
@ -93,9 +94,13 @@ private:
|
||||
|
||||
|
||||
struct Package::LoaderContentHandler : BPackageContentHandler {
|
||||
LoaderContentHandler(Package* package)
|
||||
LoaderContentHandler(Package* package, const PackageSettings& settings)
|
||||
:
|
||||
fPackage(package),
|
||||
fSettings(settings),
|
||||
fSettingsItem(NULL),
|
||||
fLastSettingsEntry(NULL),
|
||||
fLastSettingsEntryEntry(NULL),
|
||||
fErrorOccurred(false)
|
||||
{
|
||||
}
|
||||
@ -107,8 +112,11 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
|
||||
|
||||
virtual status_t HandleEntry(BPackageEntry* entry)
|
||||
{
|
||||
if (fErrorOccurred)
|
||||
if (fErrorOccurred
|
||||
|| (fLastSettingsEntry != NULL
|
||||
&& fLastSettingsEntry->IsBlackListed())) {
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
PackageDirectory* parentDir = NULL;
|
||||
if (entry->Parent() != NULL) {
|
||||
@ -118,6 +126,19 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
|
||||
RETURN_ERROR(B_BAD_DATA);
|
||||
}
|
||||
|
||||
if (fSettingsItem != NULL
|
||||
&& (parentDir == NULL
|
||||
|| entry->Parent() == fLastSettingsEntryEntry)) {
|
||||
PackageSettingsItem::Entry* settingsEntry
|
||||
= fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name());
|
||||
if (settingsEntry != NULL) {
|
||||
fLastSettingsEntry = settingsEntry;
|
||||
fLastSettingsEntryEntry = entry;
|
||||
if (fLastSettingsEntry->IsBlackListed())
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// get the file mode -- filter out write permissions
|
||||
mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
|
||||
|
||||
@ -174,8 +195,11 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
|
||||
virtual status_t HandleEntryAttribute(BPackageEntry* entry,
|
||||
BPackageEntryAttribute* attribute)
|
||||
{
|
||||
if (fErrorOccurred)
|
||||
if (fErrorOccurred
|
||||
|| (fLastSettingsEntry != NULL
|
||||
&& fLastSettingsEntry->IsBlackListed())) {
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
PackageNode* node = (PackageNode*)entry->UserToken();
|
||||
|
||||
@ -197,6 +221,11 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
|
||||
|
||||
virtual status_t HandleEntryDone(BPackageEntry* entry)
|
||||
{
|
||||
if (entry == fLastSettingsEntryEntry) {
|
||||
fLastSettingsEntryEntry = entry->Parent();
|
||||
fLastSettingsEntry = fLastSettingsEntry->Parent();
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -210,6 +239,9 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
|
||||
if (!name.SetTo(value.string))
|
||||
return B_NO_MEMORY;
|
||||
fPackage->SetName(name);
|
||||
|
||||
fSettingsItem = fSettings.PackageItemFor(fPackage->Name());
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -232,7 +264,6 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
|
||||
RETURN_ERROR(error);
|
||||
|
||||
fPackage->SetVersion(version);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -336,8 +367,12 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
|
||||
}
|
||||
|
||||
private:
|
||||
Package* fPackage;
|
||||
bool fErrorOccurred;
|
||||
Package* fPackage;
|
||||
const PackageSettings& fSettings;
|
||||
const PackageSettingsItem* fSettingsItem;
|
||||
PackageSettingsItem::Entry* fLastSettingsEntry;
|
||||
const BPackageEntry* fLastSettingsEntryEntry;
|
||||
bool fErrorOccurred;
|
||||
};
|
||||
|
||||
|
||||
@ -805,9 +840,9 @@ Package::Init(const char* fileName)
|
||||
|
||||
|
||||
status_t
|
||||
Package::Load()
|
||||
Package::Load(const PackageSettings& settings)
|
||||
{
|
||||
status_t error = _Load();
|
||||
status_t error = _Load(settings);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
@ -947,7 +982,7 @@ Package::CreateDataReader(const PackageData& data,
|
||||
|
||||
|
||||
status_t
|
||||
Package::_Load()
|
||||
Package::_Load(const PackageSettings& settings)
|
||||
{
|
||||
// open package file
|
||||
int fd = Open();
|
||||
@ -965,7 +1000,7 @@ Package::_Load()
|
||||
BHPKG::B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE);
|
||||
if (error == B_OK) {
|
||||
// parse content
|
||||
LoaderContentHandler handler(this);
|
||||
LoaderContentHandler handler(this, settings);
|
||||
error = handler.Init();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
@ -28,6 +28,7 @@ using BPackageKit::BHPKG::BAbstractBufferedDataReader;
|
||||
|
||||
|
||||
class PackageLinkDirectory;
|
||||
class PackageSettings;
|
||||
class Volume;
|
||||
class Version;
|
||||
|
||||
@ -40,7 +41,7 @@ public:
|
||||
~Package();
|
||||
|
||||
status_t Init(const char* fileName);
|
||||
status_t Load();
|
||||
status_t Load(const PackageSettings& settings);
|
||||
|
||||
::Volume* Volume() const { return fVolume; }
|
||||
const String& FileName() const { return fFileName; }
|
||||
@ -106,7 +107,7 @@ private:
|
||||
struct CachingPackageReader;
|
||||
|
||||
private:
|
||||
status_t _Load();
|
||||
status_t _Load(const PackageSettings& settings);
|
||||
bool _InitVersionedName();
|
||||
|
||||
private:
|
||||
|
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageSettings.h"
|
||||
|
||||
#include <driver_settings.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <directories.h>
|
||||
#include <fs/KPath.h>
|
||||
#include <vfs.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
|
||||
|
||||
// #pragma mark - PackageSettingsItem
|
||||
|
||||
|
||||
PackageSettingsItem::PackageSettingsItem()
|
||||
:
|
||||
fName(),
|
||||
fEntries()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageSettingsItem::~PackageSettingsItem()
|
||||
{
|
||||
Entry* entry = fEntries.Clear(true);
|
||||
while (entry != NULL) {
|
||||
Entry* next = entry->HashNext();
|
||||
delete entry;
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageSettingsItem::Init(const driver_parameter& parameter)
|
||||
{
|
||||
if (!fName.SetTo(parameter.values[0]) || fEntries.Init() != B_OK)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
|
||||
for (int i = 0; i < parameter.parameter_count; i++) {
|
||||
const driver_parameter& subParameter = parameter.parameters[i];
|
||||
if (strcmp(subParameter.name, "EntryBlacklist") != 0)
|
||||
continue;
|
||||
|
||||
status_t error = _AddBlackListedEntries(subParameter);
|
||||
// abort only in case of serious issues (memory shortage)
|
||||
if (error == B_NO_MEMORY)
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageSettingsItem::AddEntry(Entry* entry)
|
||||
{
|
||||
fEntries.Insert(entry);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageSettingsItem::AddEntry(const char* path, Entry*& _entry)
|
||||
{
|
||||
Entry* parent = NULL;
|
||||
|
||||
while (*path != '\0') {
|
||||
while (*path == '/') {
|
||||
path++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* componentEnd = strchr(path, '/');
|
||||
if (componentEnd == NULL)
|
||||
componentEnd = path + strlen(path);
|
||||
|
||||
String name;
|
||||
if (!name.SetTo(path, componentEnd - path))
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
|
||||
Entry* entry = FindEntry(parent, name);
|
||||
if (entry == NULL) {
|
||||
entry = new(std::nothrow) Entry(parent, name);
|
||||
if (entry == NULL)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
AddEntry(entry);
|
||||
}
|
||||
|
||||
path = componentEnd;
|
||||
parent = entry;
|
||||
}
|
||||
|
||||
if (parent == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
_entry = parent;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
PackageSettingsItem::Entry*
|
||||
PackageSettingsItem::FindEntry(Entry* parent, const String& name) const
|
||||
{
|
||||
return fEntries.Lookup(EntryKey(parent, name));
|
||||
}
|
||||
|
||||
|
||||
PackageSettingsItem::Entry*
|
||||
PackageSettingsItem::FindEntry(Entry* parent, const char* name) const
|
||||
{
|
||||
return fEntries.Lookup(EntryKey(parent, name));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageSettingsItem::_AddBlackListedEntries(const driver_parameter& parameter)
|
||||
{
|
||||
for (int i = 0; i < parameter.parameter_count; i++) {
|
||||
Entry* entry;
|
||||
status_t error = AddEntry(parameter.parameters[i].name, entry);
|
||||
// abort only in case of serious issues (memory shortage)
|
||||
if (error == B_NO_MEMORY)
|
||||
return error;
|
||||
|
||||
entry->SetBlackListed(true);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - PackageSettings
|
||||
|
||||
|
||||
PackageSettings::PackageSettings()
|
||||
:
|
||||
fPackageItems()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageSettings::~PackageSettings()
|
||||
{
|
||||
PackageSettingsItem* item = fPackageItems.Clear(true);
|
||||
while (item != NULL) {
|
||||
PackageSettingsItem* next = item->HashNext();
|
||||
delete item;
|
||||
item = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageSettings::Load(dev_t mountPointDeviceID, ino_t mountPointNodeID,
|
||||
PackageFSMountType mountType)
|
||||
{
|
||||
status_t error = fPackageItems.Init();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// get the mount point relative settings file path
|
||||
const char* settingsFilePath = mountType == PACKAGE_FS_MOUNT_TYPE_HOME
|
||||
? kUserSettingsGlobalDirectory "/packages"
|
||||
+ strlen(kUserConfigDirectory) + 1
|
||||
: kSystemSettingsDirectory "/packages" + strlen(kSystemDirectory) + 1;
|
||||
|
||||
// get an absolute path
|
||||
KPath path;
|
||||
if (path.InitCheck() != B_OK)
|
||||
RETURN_ERROR(path.InitCheck());
|
||||
|
||||
error = vfs_entry_ref_to_path(mountPointDeviceID, mountPointNodeID,
|
||||
NULL, true, path.LockBuffer(), path.BufferSize());
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
path.UnlockBuffer();
|
||||
|
||||
error = path.Append(settingsFilePath);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// load the driver settings
|
||||
void* settingsHandle = load_driver_settings(path.Path());
|
||||
if (settingsHandle == NULL)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
CObjectDeleter<void, status_t> settingsDeleter(settingsHandle,
|
||||
&unload_driver_settings);
|
||||
|
||||
const driver_settings* settings = get_driver_settings(settingsHandle);
|
||||
for (int i = 0; i < settings->parameter_count; i++) {
|
||||
const driver_parameter& parameter = settings->parameters[i];
|
||||
if (strcmp(parameter.name, "Package") != 0
|
||||
|| parameter.value_count < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
error = _AddPackageSettingsItem(parameter);
|
||||
// abort only in case of serious issues (memory shortage)
|
||||
if (error == B_NO_MEMORY)
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
const PackageSettingsItem*
|
||||
PackageSettings::PackageItemFor(const String& name) const
|
||||
{
|
||||
return fPackageItems.Lookup(name);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageSettings::_AddPackageSettingsItem(const driver_parameter& parameter)
|
||||
{
|
||||
PackageSettingsItem* packageItem = new(std::nothrow) PackageSettingsItem;
|
||||
if (packageItem == NULL || packageItem->Init(parameter) != B_OK) {
|
||||
delete packageItem;
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
}
|
||||
|
||||
fPackageItems.Insert(packageItem);
|
||||
return B_OK;
|
||||
}
|
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef PACKAGE_SETTINGS_H
|
||||
#define PACKAGE_SETTINGS_H
|
||||
|
||||
|
||||
#include <packagefs.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
#include "String.h"
|
||||
|
||||
|
||||
struct driver_parameter;
|
||||
|
||||
|
||||
class PackageSettingsItem {
|
||||
public:
|
||||
class Entry {
|
||||
public:
|
||||
Entry(Entry* parent, const String& name)
|
||||
:
|
||||
fParent(parent),
|
||||
fName(name),
|
||||
fIsBlackListed(false)
|
||||
{
|
||||
}
|
||||
|
||||
Entry* Parent() const
|
||||
{
|
||||
return fParent;
|
||||
}
|
||||
|
||||
const String& Name() const
|
||||
{
|
||||
return fName;
|
||||
}
|
||||
|
||||
bool IsBlackListed() const
|
||||
{
|
||||
return fIsBlackListed;
|
||||
}
|
||||
|
||||
void SetBlackListed(bool blackListed)
|
||||
{
|
||||
fIsBlackListed = blackListed;
|
||||
}
|
||||
|
||||
Entry*& HashNext()
|
||||
{
|
||||
return fHashNext;
|
||||
}
|
||||
|
||||
private:
|
||||
Entry* fParent;
|
||||
String fName;
|
||||
bool fIsBlackListed;
|
||||
Entry* fHashNext;
|
||||
};
|
||||
|
||||
class EntryKey {
|
||||
public:
|
||||
EntryKey(Entry* parent, const char* name)
|
||||
:
|
||||
fParent(parent),
|
||||
fName(name),
|
||||
fHash((addr_t)parent / 8 ^ hash_hash_string(name))
|
||||
{
|
||||
}
|
||||
|
||||
EntryKey(Entry* parent, const String& name)
|
||||
:
|
||||
fParent(parent),
|
||||
fName(name),
|
||||
fHash((addr_t)parent / 8 ^ name.Hash())
|
||||
{
|
||||
}
|
||||
|
||||
Entry* Parent() const
|
||||
{
|
||||
return fParent;
|
||||
}
|
||||
|
||||
const char* Name() const
|
||||
{
|
||||
return fName;
|
||||
}
|
||||
|
||||
size_t Hash() const
|
||||
{
|
||||
return fHash;
|
||||
}
|
||||
|
||||
private:
|
||||
Entry* fParent;
|
||||
const char* fName;
|
||||
size_t fHash;
|
||||
};
|
||||
|
||||
public:
|
||||
PackageSettingsItem();
|
||||
~PackageSettingsItem();
|
||||
|
||||
status_t Init(const driver_parameter& parameter);
|
||||
|
||||
const String& Name() const
|
||||
{ return fName; }
|
||||
|
||||
void AddEntry(Entry* entry);
|
||||
status_t AddEntry(const char* path, Entry*& _entry);
|
||||
Entry* FindEntry(Entry* parent, const String& name)
|
||||
const;
|
||||
Entry* FindEntry(Entry* parent, const char* name)
|
||||
const;
|
||||
|
||||
PackageSettingsItem*& HashNext()
|
||||
{ return fHashNext; }
|
||||
|
||||
private:
|
||||
struct EntryHashDefinition {
|
||||
typedef EntryKey KeyType;
|
||||
typedef Entry ValueType;
|
||||
|
||||
size_t HashKey(const EntryKey& key) const
|
||||
{
|
||||
return key.Hash();
|
||||
}
|
||||
|
||||
size_t Hash(const Entry* value) const
|
||||
{
|
||||
return HashKey(EntryKey(value->Parent(), value->Name()));
|
||||
}
|
||||
|
||||
bool Compare(const EntryKey& key, const Entry* value) const
|
||||
{
|
||||
return key.Parent() == value->Parent()
|
||||
&& strcmp(key.Name(), value->Name()) == 0;
|
||||
}
|
||||
|
||||
Entry*& GetLink(Entry* value) const
|
||||
{
|
||||
return value->HashNext();
|
||||
}
|
||||
};
|
||||
|
||||
typedef BOpenHashTable<EntryHashDefinition> EntryTable;
|
||||
|
||||
private:
|
||||
status_t _AddBlackListedEntries(
|
||||
const driver_parameter& parameter);
|
||||
|
||||
private:
|
||||
String fName;
|
||||
EntryTable fEntries;
|
||||
PackageSettingsItem* fHashNext;
|
||||
};
|
||||
|
||||
|
||||
struct PackageSettingsItemHashDefinition {
|
||||
typedef String KeyType;
|
||||
typedef PackageSettingsItem ValueType;
|
||||
|
||||
size_t HashKey(const String& key) const
|
||||
{
|
||||
return key.Hash();
|
||||
}
|
||||
|
||||
size_t Hash(const PackageSettingsItem* value) const
|
||||
{
|
||||
return HashKey(value->Name());
|
||||
}
|
||||
|
||||
bool Compare(const String& key, const PackageSettingsItem* value) const
|
||||
{
|
||||
return key == value->Name();
|
||||
}
|
||||
|
||||
PackageSettingsItem*& GetLink(PackageSettingsItem* value) const
|
||||
{
|
||||
return value->HashNext();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PackageSettings {
|
||||
public:
|
||||
PackageSettings();
|
||||
~PackageSettings();
|
||||
|
||||
status_t Load(dev_t mountPointDeviceID,
|
||||
ino_t mountPointNodeID,
|
||||
PackageFSMountType mountType);
|
||||
|
||||
const PackageSettingsItem* PackageItemFor(const String& name) const;
|
||||
|
||||
private:
|
||||
typedef BOpenHashTable<PackageSettingsItemHashDefinition>
|
||||
PackageItemTable;
|
||||
|
||||
private:
|
||||
status_t _AddPackageSettingsItem(
|
||||
const driver_parameter& parameter);
|
||||
|
||||
private:
|
||||
PackageItemTable fPackageItems;
|
||||
};
|
||||
|
||||
|
||||
#endif // PACKAGE_SETTINGS_H
|
@ -275,6 +275,7 @@ Volume::Volume(fs_volume* fsVolume)
|
||||
fRootDirectory(NULL),
|
||||
fPackageFSRoot(NULL),
|
||||
fPackagesDirectory(NULL),
|
||||
fPackageSettings(),
|
||||
fNextNodeID(kRootDirectoryID + 1)
|
||||
{
|
||||
rw_lock_init(&fLock, "packagefs volume");
|
||||
@ -450,6 +451,13 @@ Volume::Mount(const char* parameterString)
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// load package settings
|
||||
error = fPackageSettings.Load(fMountPoint.deviceID, fMountPoint.nodeID,
|
||||
fMountType);
|
||||
// abort only in case of serious issues (memory shortage)
|
||||
if (error == B_NO_MEMORY)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// create package domain
|
||||
fPackagesDirectory = new(std::nothrow) PackagesDirectory;
|
||||
if (fPackagesDirectory == NULL)
|
||||
@ -1434,7 +1442,7 @@ Volume::_LoadPackage(const char* name, Package*& _package)
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
error = package->Load();
|
||||
error = package->Load(fPackageSettings);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "NodeListener.h"
|
||||
#include "Package.h"
|
||||
#include "PackageLinksListener.h"
|
||||
#include "PackageSettings.h"
|
||||
#include "Query.h"
|
||||
|
||||
|
||||
@ -179,6 +180,7 @@ private:
|
||||
::PackageFSRoot* fPackageFSRoot;
|
||||
::MountType fMountType;
|
||||
PackagesDirectory* fPackagesDirectory;
|
||||
PackageSettings fPackageSettings;
|
||||
|
||||
struct {
|
||||
dev_t deviceID;
|
||||
|
@ -79,6 +79,7 @@ BootStaticLibrary boot_loader :
|
||||
list.cpp
|
||||
ring_buffer.cpp
|
||||
safemode_settings.cpp
|
||||
StringHash.cpp
|
||||
|
||||
Referenceable.cpp
|
||||
|
||||
@ -105,7 +106,7 @@ BootStaticLibrary boot_partitions :
|
||||
;
|
||||
|
||||
# Tell Jam where to find the utility sources
|
||||
SEARCH on [ FGristFiles kernel_cpp.cpp list.cpp ring_buffer.cpp ]
|
||||
SEARCH on [ FGristFiles kernel_cpp.cpp list.cpp ring_buffer.cpp StringHash.cpp ]
|
||||
= [ FDirName $(HAIKU_TOP) src system kernel util ] ;
|
||||
|
||||
SEARCH on [ FGristFiles KMessage.cpp ]
|
||||
|
@ -17,6 +17,7 @@ SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
|
||||
|
||||
BootStaticLibrary boot_packagefs :
|
||||
packagefs.cpp
|
||||
PackageSettingsItem.cpp
|
||||
|
||||
# package kit
|
||||
|
||||
|
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "PackageSettingsItem.h"
|
||||
|
||||
#include <driver_settings.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <boot/vfs.h>
|
||||
#include <system/directories.h>
|
||||
|
||||
|
||||
namespace PackageFS {
|
||||
|
||||
|
||||
// #pragma mark - PackageSettingsItem
|
||||
|
||||
|
||||
PackageSettingsItem::PackageSettingsItem()
|
||||
:
|
||||
fEntries()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PackageSettingsItem::~PackageSettingsItem()
|
||||
{
|
||||
Entry* entry = fEntries.Clear(true);
|
||||
while (entry != NULL) {
|
||||
Entry* next = entry->HashNext();
|
||||
delete entry;
|
||||
entry = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*static*/ PackageSettingsItem*
|
||||
PackageSettingsItem::Load(::Directory* systemDirectory, const char* name)
|
||||
{
|
||||
// open the driver settings file
|
||||
const char* settingsFilePath
|
||||
= kSystemSettingsDirectory "/packages" + strlen(kSystemDirectory) + 1;
|
||||
|
||||
int fd = open_from(systemDirectory, settingsFilePath, B_READ_ONLY, 0);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
FileDescriptorCloser fdCloser(fd);
|
||||
|
||||
// load the driver settings
|
||||
void* settingsHandle = load_driver_settings_file(fd);
|
||||
if (settingsHandle == NULL)
|
||||
return NULL;
|
||||
CObjectDeleter<void, status_t> settingsDeleter(settingsHandle,
|
||||
&unload_driver_settings);
|
||||
|
||||
const driver_settings* settings = get_driver_settings(settingsHandle);
|
||||
for (int i = 0; i < settings->parameter_count; i++) {
|
||||
const driver_parameter& parameter = settings->parameters[i];
|
||||
if (strcmp(parameter.name, "Package") != 0
|
||||
|| parameter.value_count < 1
|
||||
|| strcmp(parameter.values[0], name) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PackageSettingsItem* settingsItem
|
||||
= new(std::nothrow) PackageSettingsItem;
|
||||
if (settingsItem == NULL || settingsItem->Init(parameter) != B_OK) {
|
||||
delete settingsItem;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return settingsItem;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageSettingsItem::Init(const driver_parameter& parameter)
|
||||
{
|
||||
if (fEntries.Init() != B_OK)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
for (int i = 0; i < parameter.parameter_count; i++) {
|
||||
const driver_parameter& subParameter = parameter.parameters[i];
|
||||
if (strcmp(subParameter.name, "EntryBlacklist") != 0)
|
||||
continue;
|
||||
|
||||
status_t error = _AddBlackListedEntries(subParameter);
|
||||
// abort only in case of serious issues (memory shortage)
|
||||
if (error == B_NO_MEMORY)
|
||||
return error;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PackageSettingsItem::AddEntry(Entry* entry)
|
||||
{
|
||||
fEntries.Insert(entry);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageSettingsItem::AddEntry(const char* path, Entry*& _entry)
|
||||
{
|
||||
Entry* parent = NULL;
|
||||
|
||||
while (*path != '\0') {
|
||||
while (*path == '/') {
|
||||
path++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* componentEnd = strchr(path, '/');
|
||||
if (componentEnd == NULL)
|
||||
componentEnd = path + strlen(path);
|
||||
|
||||
const char* name = path;
|
||||
size_t nameLength = componentEnd - path;
|
||||
|
||||
Entry* entry = FindEntry(parent, name, nameLength);
|
||||
if (entry == NULL) {
|
||||
entry = new(std::nothrow) Entry(parent);
|
||||
if (entry == NULL || !entry->SetName(name, nameLength)) {
|
||||
delete entry;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
AddEntry(entry);
|
||||
}
|
||||
|
||||
path = componentEnd;
|
||||
parent = entry;
|
||||
}
|
||||
|
||||
if (parent == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
_entry = parent;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
PackageSettingsItem::Entry*
|
||||
PackageSettingsItem::FindEntry(Entry* parent, const char* name) const
|
||||
{
|
||||
return fEntries.Lookup(EntryKey(parent, name));
|
||||
}
|
||||
|
||||
|
||||
PackageSettingsItem::Entry*
|
||||
PackageSettingsItem::FindEntry(Entry* parent, const char* name,
|
||||
size_t nameLength) const
|
||||
{
|
||||
return fEntries.Lookup(EntryKey(parent, name, nameLength));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
PackageSettingsItem::_AddBlackListedEntries(const driver_parameter& parameter)
|
||||
{
|
||||
for (int i = 0; i < parameter.parameter_count; i++) {
|
||||
Entry* entry;
|
||||
status_t error = AddEntry(parameter.parameters[i].name, entry);
|
||||
// abort only in case of serious issues (memory shortage)
|
||||
if (error == B_NO_MEMORY)
|
||||
return error;
|
||||
|
||||
entry->SetBlackListed(true);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
} // namespace PackageFS
|
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_PACKAGE_SETTINGS_ITEM_H
|
||||
#define BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_PACKAGE_SETTINGS_ITEM_H
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <util/OpenHashTable.h>
|
||||
#include <util/StringHash.h>
|
||||
|
||||
|
||||
struct driver_parameter;
|
||||
class Directory;
|
||||
|
||||
|
||||
namespace PackageFS {
|
||||
|
||||
|
||||
class PackageSettingsItem {
|
||||
public:
|
||||
class Entry {
|
||||
public:
|
||||
Entry(Entry* parent)
|
||||
:
|
||||
fParent(parent),
|
||||
fName(NULL),
|
||||
fIsBlackListed(false)
|
||||
{
|
||||
}
|
||||
|
||||
~Entry()
|
||||
{
|
||||
free(fName);
|
||||
}
|
||||
|
||||
bool SetName(const char* name, size_t nameLength)
|
||||
{
|
||||
fName = (char*)malloc(nameLength + 1);
|
||||
if (fName == NULL)
|
||||
return false;
|
||||
|
||||
memcpy(fName, name, nameLength);
|
||||
fName[nameLength] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
Entry* Parent() const
|
||||
{
|
||||
return fParent;
|
||||
}
|
||||
|
||||
const char* Name() const
|
||||
{
|
||||
return fName;
|
||||
}
|
||||
|
||||
bool IsBlackListed() const
|
||||
{
|
||||
return fIsBlackListed;
|
||||
}
|
||||
|
||||
void SetBlackListed(bool blackListed)
|
||||
{
|
||||
fIsBlackListed = blackListed;
|
||||
}
|
||||
|
||||
Entry*& HashNext()
|
||||
{
|
||||
return fHashNext;
|
||||
}
|
||||
|
||||
private:
|
||||
Entry* fParent;
|
||||
char* fName;
|
||||
bool fIsBlackListed;
|
||||
Entry* fHashNext;
|
||||
};
|
||||
|
||||
class EntryKey {
|
||||
public:
|
||||
EntryKey(Entry* parent, const char* name, size_t nameLength)
|
||||
:
|
||||
fParent(parent),
|
||||
fName(name),
|
||||
fNameLength(nameLength)
|
||||
{
|
||||
}
|
||||
|
||||
EntryKey(Entry* parent, const char* name)
|
||||
:
|
||||
fParent(parent),
|
||||
fName(name),
|
||||
fNameLength(strlen(name))
|
||||
{
|
||||
}
|
||||
|
||||
Entry* Parent() const
|
||||
{
|
||||
return fParent;
|
||||
}
|
||||
|
||||
const char* Name() const
|
||||
{
|
||||
return fName;
|
||||
}
|
||||
|
||||
size_t NameLength() const
|
||||
{
|
||||
return fNameLength;
|
||||
}
|
||||
|
||||
size_t Hash() const
|
||||
{
|
||||
return (addr_t)fParent / 8
|
||||
^ hash_hash_string_part(fName, fNameLength);
|
||||
}
|
||||
|
||||
private:
|
||||
Entry* fParent;
|
||||
const char* fName;
|
||||
size_t fNameLength;
|
||||
};
|
||||
|
||||
public:
|
||||
PackageSettingsItem();
|
||||
~PackageSettingsItem();
|
||||
|
||||
static PackageSettingsItem* Load(::Directory* systemDirectory,
|
||||
const char* name);
|
||||
|
||||
status_t Init(const driver_parameter& parameter);
|
||||
|
||||
void AddEntry(Entry* entry);
|
||||
status_t AddEntry(const char* path, Entry*& _entry);
|
||||
Entry* FindEntry(Entry* parent, const char* name)
|
||||
const;
|
||||
Entry* FindEntry(Entry* parent, const char* name,
|
||||
size_t nameLength) const;
|
||||
|
||||
PackageSettingsItem*& HashNext()
|
||||
{ return fHashNext; }
|
||||
|
||||
private:
|
||||
struct EntryHashDefinition {
|
||||
typedef EntryKey KeyType;
|
||||
typedef Entry ValueType;
|
||||
|
||||
size_t HashKey(const EntryKey& key) const
|
||||
{
|
||||
return key.Hash();
|
||||
}
|
||||
|
||||
size_t Hash(const Entry* value) const
|
||||
{
|
||||
return HashKey(EntryKey(value->Parent(), value->Name()));
|
||||
}
|
||||
|
||||
bool Compare(const EntryKey& key, const Entry* value) const
|
||||
{
|
||||
const char* name = value->Name();
|
||||
return key.Parent() == value->Parent()
|
||||
&& strncmp(key.Name(), name, key.NameLength()) == 0
|
||||
&& name[key.NameLength()] == '\0';
|
||||
}
|
||||
|
||||
Entry*& GetLink(Entry* value) const
|
||||
{
|
||||
return value->HashNext();
|
||||
}
|
||||
};
|
||||
|
||||
typedef BOpenHashTable<EntryHashDefinition> EntryTable;
|
||||
|
||||
private:
|
||||
status_t _AddBlackListedEntries(
|
||||
const driver_parameter& parameter);
|
||||
|
||||
private:
|
||||
EntryTable fEntries;
|
||||
PackageSettingsItem* fHashNext;
|
||||
};
|
||||
|
||||
|
||||
} // namespace PackageFS
|
||||
|
||||
|
||||
#endif // BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_PACKAGE_SETTINGS_ITEM_H
|
@ -25,6 +25,8 @@
|
||||
|
||||
#include <boot/platform.h>
|
||||
|
||||
#include "PackageSettingsItem.h"
|
||||
|
||||
|
||||
#if 0
|
||||
# define RETURN_ERROR(error) return (error);
|
||||
@ -44,6 +46,8 @@ using namespace BPackageKit::BHPKG;
|
||||
using BPackageKit::BHPKG::BPrivate::PackageFileHeapReader;
|
||||
using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
|
||||
|
||||
using PackageFS::PackageSettingsItem;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
@ -325,9 +329,13 @@ private:
|
||||
|
||||
|
||||
struct PackageLoaderContentHandler : BPackageContentHandler {
|
||||
PackageLoaderContentHandler(PackageVolume* volume)
|
||||
PackageLoaderContentHandler(PackageVolume* volume,
|
||||
PackageSettingsItem* settingsItem)
|
||||
:
|
||||
fVolume(volume),
|
||||
fSettingsItem(settingsItem),
|
||||
fLastSettingsEntry(NULL),
|
||||
fLastSettingsEntryEntry(NULL),
|
||||
fErrorOccurred(false)
|
||||
{
|
||||
}
|
||||
@ -339,8 +347,11 @@ struct PackageLoaderContentHandler : BPackageContentHandler {
|
||||
|
||||
virtual status_t HandleEntry(BPackageEntry* entry)
|
||||
{
|
||||
if (fErrorOccurred)
|
||||
if (fErrorOccurred
|
||||
|| (fLastSettingsEntry != NULL
|
||||
&& fLastSettingsEntry->IsBlackListed())) {
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
PackageDirectory* parentDir = NULL;
|
||||
if (const BPackageEntry* parentEntry = entry->Parent()) {
|
||||
@ -351,6 +362,19 @@ struct PackageLoaderContentHandler : BPackageContentHandler {
|
||||
(PackageNode*)parentEntry->UserToken());
|
||||
}
|
||||
|
||||
if (fSettingsItem != NULL
|
||||
&& (parentDir == NULL
|
||||
|| entry->Parent() == fLastSettingsEntryEntry)) {
|
||||
PackageSettingsItem::Entry* settingsEntry
|
||||
= fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name());
|
||||
if (settingsEntry != NULL) {
|
||||
fLastSettingsEntry = settingsEntry;
|
||||
fLastSettingsEntryEntry = entry;
|
||||
if (fLastSettingsEntry->IsBlackListed())
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (parentDir == NULL)
|
||||
parentDir = fVolume->RootDirectory();
|
||||
|
||||
@ -412,6 +436,11 @@ struct PackageLoaderContentHandler : BPackageContentHandler {
|
||||
|
||||
virtual status_t HandleEntryDone(BPackageEntry* entry)
|
||||
{
|
||||
if (entry == fLastSettingsEntryEntry) {
|
||||
fLastSettingsEntryEntry = entry->Parent();
|
||||
fLastSettingsEntry = fLastSettingsEntry->Parent();
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -428,8 +457,11 @@ struct PackageLoaderContentHandler : BPackageContentHandler {
|
||||
}
|
||||
|
||||
private:
|
||||
PackageVolume* fVolume;
|
||||
bool fErrorOccurred;
|
||||
PackageVolume* fVolume;
|
||||
const PackageSettingsItem* fSettingsItem;
|
||||
PackageSettingsItem::Entry* fLastSettingsEntry;
|
||||
const BPackageEntry* fLastSettingsEntryEntry;
|
||||
bool fErrorOccurred;
|
||||
};
|
||||
|
||||
|
||||
@ -761,7 +793,8 @@ create_node(PackageNode* packageNode, ::Node*& _node)
|
||||
|
||||
|
||||
status_t
|
||||
packagefs_mount_file(int fd, ::Directory*& _mountedDirectory)
|
||||
packagefs_mount_file(int fd, ::Directory* systemDirectory,
|
||||
::Directory*& _mountedDirectory)
|
||||
{
|
||||
PackageLoaderErrorOutput errorOutput;
|
||||
PackageReaderImpl packageReader(&errorOutput);
|
||||
@ -779,8 +812,13 @@ packagefs_mount_file(int fd, ::Directory*& _mountedDirectory)
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// load settings for the package
|
||||
PackageSettingsItem* settings = PackageSettingsItem::Load(systemDirectory,
|
||||
"haiku");
|
||||
ObjectDeleter<PackageSettingsItem> settingsDeleter(settings);
|
||||
|
||||
// parse content -- this constructs the entry/node tree
|
||||
PackageLoaderContentHandler handler(volume);
|
||||
PackageLoaderContentHandler handler(volume, settings);
|
||||
error = handler.Init();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Copyright 2011-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_H
|
||||
@ -15,13 +15,8 @@ class Directory;
|
||||
class Node;
|
||||
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
||||
status_t packagefs_mount_file(int fd, Directory*& _mountedDirectory);
|
||||
|
||||
|
||||
__END_DECLS
|
||||
status_t packagefs_mount_file(int fd, Directory* systemDirectory,
|
||||
Directory*& _mountedDirectory);
|
||||
|
||||
|
||||
#endif // BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_H
|
||||
|
@ -445,7 +445,8 @@ BootVolume::SetTo(Directory* rootDirectory)
|
||||
|
||||
// the system is packaged -- mount the packagefs
|
||||
Directory* packageRootDirectory;
|
||||
status_t error = packagefs_mount_file(packageFD, packageRootDirectory);
|
||||
status_t error = packagefs_mount_file(packageFD, fSystemDirectory,
|
||||
packageRootDirectory);
|
||||
close(packageFD);
|
||||
if (error != B_OK) {
|
||||
Unset();
|
||||
|
@ -15,6 +15,7 @@ KernelMergeObject kernel_util.o :
|
||||
ring_buffer.cpp
|
||||
RadixBitmap.cpp
|
||||
Random.cpp
|
||||
StringHash.cpp
|
||||
|
||||
: $(TARGET_KERNEL_PIC_CCFLAGS) -DUSING_LIBGCC
|
||||
;
|
||||
|
Loading…
Reference in New Issue
Block a user