From 3a7e0b00147f7a33bc52cb75a56bde8d9652d92a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 19 Nov 2013 15:30:34 +0100 Subject: [PATCH] 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 { EntryBlacklist { ... } } ... is the base name (no version) of the respective package (e.g. "haiku"), 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). --- headers/private/system/directories.h | 2 + .../kernel/file_systems/packagefs/Jamfile | 1 + .../packagefs/package/Package.cpp | 55 ++++- .../file_systems/packagefs/package/Package.h | 5 +- .../packagefs/volume/PackageSettings.cpp | 232 ++++++++++++++++++ .../packagefs/volume/PackageSettings.h | 210 ++++++++++++++++ .../file_systems/packagefs/volume/Volume.cpp | 10 +- .../file_systems/packagefs/volume/Volume.h | 2 + src/system/boot/loader/Jamfile | 3 +- .../loader/file_systems/packagefs/Jamfile | 1 + .../packagefs/PackageSettingsItem.cpp | 182 ++++++++++++++ .../packagefs/PackageSettingsItem.h | 190 ++++++++++++++ .../file_systems/packagefs/packagefs.cpp | 50 +++- .../loader/file_systems/packagefs/packagefs.h | 11 +- src/system/boot/loader/vfs.cpp | 3 +- src/system/kernel/util/Jamfile | 1 + 16 files changed, 929 insertions(+), 29 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.h create mode 100644 src/system/boot/loader/file_systems/packagefs/PackageSettingsItem.cpp create mode 100644 src/system/boot/loader/file_systems/packagefs/PackageSettingsItem.h diff --git a/headers/private/system/directories.h b/headers/private/system/directories.h index d69bb684eb..050b173b83 100644 --- a/headers/private/system/directories.h +++ b/headers/private/system/directories.h @@ -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" diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index d03b2a8236..ee7f3f851b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -50,6 +50,7 @@ HAIKU_PACKAGE_FS_SOURCES = PackageLinkSymlink.cpp PackageNode.cpp PackageNodeAttribute.cpp + PackageSettings.cpp PackageSymlink.cpp Resolvable.cpp ResolvableFamily.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/package/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/package/Package.cpp index 8f881c74eb..8d54f7891a 100644 --- a/src/add-ons/kernel/file_systems/packagefs/package/Package.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/package/Package.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); diff --git a/src/add-ons/kernel/file_systems/packagefs/package/Package.h b/src/add-ons/kernel/file_systems/packagefs/package/Package.h index 210264ed5f..776ffd233b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/package/Package.h +++ b/src/add-ons/kernel/file_systems/packagefs/package/Package.h @@ -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: diff --git a/src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.cpp b/src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.cpp new file mode 100644 index 0000000000..1868b7bd2b --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.cpp @@ -0,0 +1,232 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PackageSettings.h" + +#include + +#include +#include +#include +#include + +#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 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; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.h b/src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.h new file mode 100644 index 0000000000..a1654e6487 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/volume/PackageSettings.h @@ -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 +#include + +#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 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 + PackageItemTable; + +private: + status_t _AddPackageSettingsItem( + const driver_parameter& parameter); + +private: + PackageItemTable fPackageItems; +}; + + +#endif // PACKAGE_SETTINGS_H diff --git a/src/add-ons/kernel/file_systems/packagefs/volume/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/volume/Volume.cpp index 3e99ba6fcb..0fcf1add95 100644 --- a/src/add-ons/kernel/file_systems/packagefs/volume/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/volume/Volume.cpp @@ -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; diff --git a/src/add-ons/kernel/file_systems/packagefs/volume/Volume.h b/src/add-ons/kernel/file_systems/packagefs/volume/Volume.h index 2e34a70f79..4df34f8995 100644 --- a/src/add-ons/kernel/file_systems/packagefs/volume/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/volume/Volume.h @@ -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; diff --git a/src/system/boot/loader/Jamfile b/src/system/boot/loader/Jamfile index 5a21032853..1b24a2edc6 100644 --- a/src/system/boot/loader/Jamfile +++ b/src/system/boot/loader/Jamfile @@ -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 ] diff --git a/src/system/boot/loader/file_systems/packagefs/Jamfile b/src/system/boot/loader/file_systems/packagefs/Jamfile index 07d8c03884..2425fdf443 100644 --- a/src/system/boot/loader/file_systems/packagefs/Jamfile +++ b/src/system/boot/loader/file_systems/packagefs/Jamfile @@ -17,6 +17,7 @@ SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ; BootStaticLibrary boot_packagefs : packagefs.cpp + PackageSettingsItem.cpp # package kit diff --git a/src/system/boot/loader/file_systems/packagefs/PackageSettingsItem.cpp b/src/system/boot/loader/file_systems/packagefs/PackageSettingsItem.cpp new file mode 100644 index 0000000000..d5d54c953f --- /dev/null +++ b/src/system/boot/loader/file_systems/packagefs/PackageSettingsItem.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PackageSettingsItem.h" + +#include + +#include +#include +#include + + +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 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 diff --git a/src/system/boot/loader/file_systems/packagefs/PackageSettingsItem.h b/src/system/boot/loader/file_systems/packagefs/PackageSettingsItem.h new file mode 100644 index 0000000000..94f8b2d713 --- /dev/null +++ b/src/system/boot/loader/file_systems/packagefs/PackageSettingsItem.h @@ -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 + +#include +#include + + +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 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 diff --git a/src/system/boot/loader/file_systems/packagefs/packagefs.cpp b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp index 1ab70be2cc..53d75ad5be 100644 --- a/src/system/boot/loader/file_systems/packagefs/packagefs.cpp +++ b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp @@ -25,6 +25,8 @@ #include +#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 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); diff --git a/src/system/boot/loader/file_systems/packagefs/packagefs.h b/src/system/boot/loader/file_systems/packagefs/packagefs.h index 1ae18a0abe..6c31dbd0ec 100644 --- a/src/system/boot/loader/file_systems/packagefs/packagefs.h +++ b/src/system/boot/loader/file_systems/packagefs/packagefs.h @@ -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 diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index 2aa2ecc022..bb7d5e037d 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -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(); diff --git a/src/system/kernel/util/Jamfile b/src/system/kernel/util/Jamfile index a8f49b9d2a..cb8bf52853 100644 --- a/src/system/kernel/util/Jamfile +++ b/src/system/kernel/util/Jamfile @@ -15,6 +15,7 @@ KernelMergeObject kernel_util.o : ring_buffer.cpp RadixBitmap.cpp Random.cpp + StringHash.cpp : $(TARGET_KERNEL_PIC_CCFLAGS) -DUSING_LIBGCC ;