1// Settings.cpp
2//
3// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
4//
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18//
19// You can alternatively use *this file* under the terms of the the MIT
20// license included in this package.
21
22#include <new>
23
24#include "Settings.h"
25#include "Debug.h"
26
27using std::nothrow;
28
29/*!
30	\class Settings
31	\brief Manages the ReiserFS settings.
32*/
33
34static const char *kFSName = "reiserfs";
35
36// defaults
37static const char *kDefaultDefaultVolumeName = "ReiserFS untitled";
38static const bool kDefaultHideEsoteric	= true;
39
40// constructor
41Settings::Settings()
42	:
43	fDefaultVolumeName(),
44	fVolumeName(),
45	fHideEsoteric(kDefaultHideEsoteric),
46	fHiddenEntries(5)
47{
48}
49
50// destructor
51Settings::~Settings()
52{
53	Unset();
54}
55
56// SetTo
57status_t
58Settings::SetTo(const char *volumeName)
59{
60	// unset
61	Unset();
62	// load the driver settings and find the entry for the volume
63	void *settings = load_driver_settings(kFSName);
64	const driver_parameter *volume = NULL;
65	const driver_settings *ds = get_driver_settings(settings);
66	if (ds && volumeName)
67		volume = _FindVolumeParameter(ds, volumeName);
68	// init the object and unload the settings
69	_Init(ds, volume);
70	unload_driver_settings(settings);
71	return B_OK;
72}
73
74// SetTo
75status_t
76Settings::SetTo(off_t volumeOffset, off_t volumeSize)
77{
78	PRINT(("Settings::SetTo(%" B_PRIdOFF ", %" B_PRIdOFF ")\n", volumeOffset,
79		volumeSize));
80	// unset
81	Unset();
82	// load the driver settings and find the entry for the volume
83	void *settings = load_driver_settings(kFSName);
84	const driver_parameter *volume = NULL;
85	const driver_settings *ds = get_driver_settings(settings);
86	if (ds)
87		volume = _FindVolumeParameter(ds, volumeOffset, volumeSize);
88	// init the object and unload the settings
89	_Init(ds, volume);
90	unload_driver_settings(settings);
91	PRINT(("Settings::SetTo(%" B_PRIdOFF ", %" B_PRIdOFF ") done: B_OK\n",
92		volumeOffset, volumeSize));
93	return B_OK;
94}
95
96// Unset
97void
98Settings::Unset()
99{
100	fDefaultVolumeName.Unset();
101	fVolumeName.Unset();
102	fHideEsoteric = kDefaultHideEsoteric;
103	fHiddenEntries.MakeEmpty();
104}
105
106// GetDefaultVolumeName
107const char *
108Settings::GetDefaultVolumeName() const
109{
110	if (fDefaultVolumeName.GetLength() > 0)
111		return fDefaultVolumeName.GetString();
112	return kDefaultDefaultVolumeName;
113}
114
115// GetVolumeName
116const char *
117Settings::GetVolumeName() const
118{
119	if (fVolumeName.GetLength() > 0)
120		return fVolumeName.GetString();
121	return GetDefaultVolumeName();
122}
123
124// GetHideEsoteric
125bool
126Settings::GetHideEsoteric() const
127{
128	return fHideEsoteric;
129}
130
131// HiddenEntryAt
132const char *
133Settings::HiddenEntryAt(int32 index) const
134{
135	const char *entry = NULL;
136	if (index >= 0 && index < fHiddenEntries.CountItems())
137		entry = fHiddenEntries.ItemAt(index).GetString();
138	return entry;
139}
140
141// Dump
142void
143Settings::Dump()
144{
145#if DEBUG
146	PRINT(("Settings:\n"));
147	PRINT(("  default volume name:   `%s'\n", GetDefaultVolumeName()));
148	PRINT(("  volume name:           `%s'\n", GetVolumeName()));
149	PRINT(("  hide esoteric entries: %d\n", GetHideEsoteric()));
150	PRINT(("  %" B_PRId32 " hidden entries:\n", fHiddenEntries.CountItems()));
151	for (int32 i = 0; const char *entry = HiddenEntryAt(i); i++)
152		PRINT(("    `%s'\n", entry));
153#endif
154}
155
156// _Init
157status_t
158Settings::_Init(const driver_settings *settings,
159				const driver_parameter *volume)
160{
161PRINT(("Settings::_Init(%p, %p)\n", settings, volume));
162	status_t error = B_OK;
163	// get the global values
164	fDefaultVolumeName.SetTo(_GetParameterValue(settings,
165		"default_volume_name", (const char*)NULL, NULL));
166PRINT(("  default_volume_name is: `%s'\n", fDefaultVolumeName.GetString()));
167	fHideEsoteric = _GetParameterValue(settings, "hide_esoteric_entries",
168										kDefaultHideEsoteric,
169										kDefaultHideEsoteric);
170PRINT(("  hide_esoteric_entries is: %d\n", fHideEsoteric));
171	// get the per volume settings
172	if (volume) {
173PRINT(("  getting volume parameters:\n"));
174		fVolumeName.SetTo(_GetParameterValue(volume, "name", (const char*)NULL,
175												NULL));
176PRINT(("    name is: `%s'\n", fVolumeName.GetString()));
177		fHideEsoteric = _GetParameterValue(volume, "hide_esoteric_entries",
178											fHideEsoteric, fHideEsoteric);
179PRINT(("    hide_esoteric_entries is: %d\n", fHideEsoteric));
180		int32 cookie = 0;
181		while (const driver_parameter *parameter
182				= _FindNextParameter(volume, "hide_entries", cookie)) {
183			for (int32 i = 0; i < parameter->value_count; i++)
184{
185				fHiddenEntries.AddItem(parameter->values[i]);
186PRINT(("    hidden entry: `%s'\n", parameter->values[i]));
187}
188		}
189	}
190	// check the values
191PRINT(("  checking volume names...'\n"));
192	_CheckVolumeName(fDefaultVolumeName);
193	_CheckVolumeName(fVolumeName);
194PRINT(("  checking hidden entry names...'\n"));
195	for (int32 i = fHiddenEntries.CountItems(); i >= 0; i--) {
196		String &entry = fHiddenEntries.ItemAt(i);
197		if (!_CheckEntryName(entry.GetString()))
198{
199PRINT(("    ignoring: `%s'\n", entry.GetString()));
200			fHiddenEntries.RemoveItem(i);
201}
202	}
203PRINT(("Settings::_Init() done: %s\n", strerror(error)));
204	return error;
205}
206
207// _FindVolumeParameter
208const driver_parameter *
209Settings::_FindVolumeParameter(const driver_settings *settings,
210								const char *name)
211{
212	if (settings) {
213		int32 cookie = 0;
214		while (const driver_parameter *parameter
215				= _FindNextParameter(settings, "volume", cookie)) {
216			if (parameter->value_count == 1
217				&& !strcmp(parameter->values[0], name)) {
218				return parameter;
219			}
220		}
221	}
222	return NULL;
223}
224
225// _FindVolumeParameter
226const driver_parameter *
227Settings::_FindVolumeParameter(const driver_settings *settings,
228								off_t offset, off_t size)
229{
230	PRINT(("Settings::_FindVolumeParameter(%" B_PRIdOFF ", %" B_PRIdOFF ")\n",
231		offset, size));
232	if (settings) {
233		int32 cookie = 0;
234		while (const driver_parameter *parameter
235				= _FindNextParameter(settings, "volume", cookie)) {
236			if (_GetParameterValue(parameter, "offset", offset + 1, offset + 1)
237					== offset
238				&& _GetParameterValue(parameter, "size", size + 1, size + 1)
239					== size) {
240				PRINT(("Settings::_FindVolumeParameter() done: found parameter:"
241					" index: %" B_PRId32 ", (%p)\n", cookie - 1, parameter));
242				return parameter;
243			}
244		}
245	}
246	PRINT(("Settings::_FindVolumeParameter() done: failed\n"));
247	return NULL;
248}
249
250// _CheckVolumeName
251void
252Settings::_CheckVolumeName(String &name)
253{
254	// truncate, if it is too long
255	if (name.GetLength() >= B_FILE_NAME_LENGTH) {
256		char buffer[B_FILE_NAME_LENGTH];
257		memcpy(buffer, name.GetString(), B_FILE_NAME_LENGTH - 1);
258		name.SetTo(buffer, B_FILE_NAME_LENGTH - 1);
259	}
260	// check for bad characters
261	bool invalid = false;
262	const char *string = name.GetString();
263	for (int32 i = 0; !invalid && i < name.GetLength(); i++) {
264		if (string[i] == '/')	// others?
265			invalid = true;
266	}
267	if (invalid)
268		name.Unset();
269}
270
271// _CheckEntryName
272bool
273Settings::_CheckEntryName(const char *name)
274{
275	int32 len = (name ? strlen(name) : 0);
276	// any further restictions?
277	return (len > 0);
278}
279
280