/* * 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" static const char* const kBlockedEntriesParameterName = "BlockedEntries"; static const char* const kLegacyBlockedEntriesParameterName = "EntryBlacklist"; // #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 char* name) { if (!fName.SetTo(name) || fEntries.Init() != B_OK) RETURN_ERROR(B_NO_MEMORY); return B_OK; } status_t PackageSettingsItem::ApplySettings(const driver_parameter* parameters, int parameterCount) { for (int i = 0; i < parameterCount; i++) { const driver_parameter& subParameter = parameters[i]; if (strcmp(subParameter.name, kBlockedEntriesParameterName) != 0 && strcmp(subParameter.name, kLegacyBlockedEntriesParameterName) != 0) continue; status_t error = _AddBlockedEntries(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::_AddBlockedEntries(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->SetBlocked(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); // First get the safe mode options. Those apply to the system package. if (mountType == PACKAGE_FS_MOUNT_TYPE_SYSTEM) { void* settingsHandle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); if (settingsHandle != NULL) { if (const driver_settings* settings = get_driver_settings(settingsHandle)) { error = _AddPackageSettingsItem("haiku", settings->parameters, settings->parameter_count); // abort only in case of serious issues (memory shortage) if (error == B_NO_MEMORY) return error; } unload_driver_settings(settingsHandle); } } // 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 DriverSettingsUnloader settingsHandle(load_driver_settings(path.Path())); if (!settingsHandle.IsSet()) return B_ENTRY_NOT_FOUND; const driver_settings* settings = get_driver_settings(settingsHandle.Get()); 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.values[0], parameter.parameters, parameter.parameter_count); // 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 char* name, const driver_parameter* parameters, int parameterCount) { // get/create the package item PackageSettingsItem* packageItem = fPackageItems.Lookup(StringKey(name)); if (packageItem == NULL) { packageItem = new(std::nothrow) PackageSettingsItem; if (packageItem == NULL || packageItem->Init(name) != B_OK) { delete packageItem; RETURN_ERROR(B_NO_MEMORY); } fPackageItems.Insert(packageItem); } // apply the settings return packageItem->ApplySettings(parameters, parameterCount); }