1/*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "PackageSettingsItem.h"
8
9#include <driver_settings.h>
10
11#include <AutoDeleterDrivers.h>
12#include <boot/vfs.h>
13#include <system/directories.h>
14
15
16namespace PackageFS {
17
18
19// #pragma mark - PackageSettingsItem
20
21
22PackageSettingsItem::PackageSettingsItem()
23	:
24	fEntries(),
25	fHashNext(NULL)
26{
27}
28
29
30PackageSettingsItem::~PackageSettingsItem()
31{
32	Entry* entry = fEntries.Clear(true);
33	while (entry != NULL) {
34		Entry* next = entry->HashNext();
35		delete entry;
36		entry = next;
37	}
38}
39
40
41/*static*/ PackageSettingsItem*
42PackageSettingsItem::Load(::Directory* systemDirectory, const char* name)
43{
44	// open the driver settings file
45	const char* settingsFilePath
46		= &(kSystemSettingsDirectory "/packages")[strlen(kSystemDirectory) + 1];
47
48	FileDescriptorCloser fd(open_from(systemDirectory, settingsFilePath,
49		B_READ_ONLY, 0));
50	if (!fd.IsSet())
51		return NULL;
52
53	// load the driver settings
54	DriverSettingsUnloader settingsHandle(load_driver_settings_file(fd.Get()));
55	if (!settingsHandle.IsSet())
56		return NULL;
57
58	const driver_settings* settings = get_driver_settings(settingsHandle.Get());
59	for (int i = 0; i < settings->parameter_count; i++) {
60		const driver_parameter& parameter = settings->parameters[i];
61		if (strcmp(parameter.name, "Package") != 0
62			|| parameter.value_count < 1
63			|| strcmp(parameter.values[0], name) != 0) {
64			continue;
65		}
66
67		PackageSettingsItem* settingsItem
68			= new(std::nothrow) PackageSettingsItem;
69		if (settingsItem == NULL || settingsItem->Init(parameter) != B_OK) {
70			delete settingsItem;
71			return NULL;
72		}
73
74		return settingsItem;
75	}
76
77	return NULL;
78}
79
80
81status_t
82PackageSettingsItem::Init(const driver_parameter& parameter)
83{
84	if (fEntries.Init() != B_OK)
85		return B_NO_MEMORY;
86
87	for (int i = 0; i < parameter.parameter_count; i++) {
88		const driver_parameter& subParameter = parameter.parameters[i];
89		if (strcmp(subParameter.name, "EntryBlacklist") != 0)
90			continue;
91
92		status_t error = _AddBlockedEntries(subParameter);
93		// abort only in case of serious issues (memory shortage)
94		if (error == B_NO_MEMORY)
95			return error;
96	}
97
98	return B_OK;
99}
100
101
102void
103PackageSettingsItem::AddEntry(Entry* entry)
104{
105	fEntries.Insert(entry);
106}
107
108
109status_t
110PackageSettingsItem::AddEntry(const char* path, Entry*& _entry)
111{
112	Entry* parent = NULL;
113
114	while (*path != '\0') {
115		while (*path == '/') {
116			path++;
117			continue;
118		}
119
120		const char* componentEnd = strchr(path, '/');
121		if (componentEnd == NULL)
122			componentEnd = path + strlen(path);
123
124		const char* name = path;
125		size_t nameLength = componentEnd - path;
126
127		Entry* entry = FindEntry(parent, name, nameLength);
128		if (entry == NULL) {
129			entry = new(std::nothrow) Entry(parent);
130			if (entry == NULL || !entry->SetName(name, nameLength)) {
131				delete entry;
132				return B_NO_MEMORY;
133			}
134			AddEntry(entry);
135		}
136
137		path = componentEnd;
138		parent = entry;
139	}
140
141	if (parent == NULL)
142		return B_BAD_VALUE;
143
144	_entry = parent;
145	return B_OK;
146}
147
148
149PackageSettingsItem::Entry*
150PackageSettingsItem::FindEntry(Entry* parent, const char* name) const
151{
152	return fEntries.Lookup(EntryKey(parent, name));
153}
154
155
156PackageSettingsItem::Entry*
157PackageSettingsItem::FindEntry(Entry* parent, const char* name,
158	size_t nameLength) const
159{
160	return fEntries.Lookup(EntryKey(parent, name, nameLength));
161}
162
163
164status_t
165PackageSettingsItem::_AddBlockedEntries(const driver_parameter& parameter)
166{
167	for (int i = 0; i < parameter.parameter_count; i++) {
168		Entry* entry;
169		status_t error = AddEntry(parameter.parameters[i].name, entry);
170		// abort only in case of serious issues (memory shortage)
171		if (error == B_NO_MEMORY)
172			return error;
173
174		entry->SetBlocked(true);
175	}
176
177	return B_OK;
178}
179
180
181}	// namespace PackageFS
182