1/*
2 * Copyright 2002-2009, Haiku Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Tyler Dauwalder
7 *		Ingo Weinhold
8 */
9
10
11#include <errno.h>
12#include <string.h>
13
14#include <Bitmap.h>
15#include <Directory.h>
16#include <fs_info.h>
17#include <Node.h>
18#include <Path.h>
19#include <Volume.h>
20
21#include <storage_support.h>
22#include <syscalls.h>
23
24#include <fs_interface.h>
25
26
27// Creates an uninitialized BVolume object.
28BVolume::BVolume()
29	: fDevice((dev_t)-1),
30	  fCStatus(B_NO_INIT)
31{
32}
33
34
35// Creates a BVolume and initializes it to the volume specified by the
36// supplied device ID.
37BVolume::BVolume(dev_t device)
38	: fDevice((dev_t)-1),
39	  fCStatus(B_NO_INIT)
40{
41	SetTo(device);
42}
43
44
45// Creates a copy of the supplied BVolume object.
46BVolume::BVolume(const BVolume &volume)
47	: fDevice(volume.fDevice),
48	  fCStatus(volume.fCStatus)
49{
50}
51
52
53// Destroys the object and frees all associated resources.
54BVolume::~BVolume()
55{
56}
57
58
59// Returns the initialization status.
60status_t
61BVolume::InitCheck(void) const
62{
63	return fCStatus;
64}
65
66
67// Initializes the object to refer to the volume specified by the supplied
68// device ID.
69status_t
70BVolume::SetTo(dev_t device)
71{
72	// uninitialize
73	Unset();
74	// check the parameter
75	status_t error = (device >= 0 ? B_OK : B_BAD_VALUE);
76	if (error == B_OK) {
77		fs_info info;
78		if (fs_stat_dev(device, &info) != 0)
79			error = errno;
80	}
81	// set the new value
82	if (error == B_OK)
83		fDevice = device;
84	// set the init status variable
85	fCStatus = error;
86	return fCStatus;
87}
88
89
90// Brings the BVolume object to an uninitialized state.
91void
92BVolume::Unset()
93{
94	fDevice = (dev_t)-1;
95	fCStatus = B_NO_INIT;
96}
97
98
99// Returns the device ID of the volume the object refers to.
100dev_t
101BVolume::Device() const
102{
103	return fDevice;
104}
105
106
107// Writes the root directory of the volume referred to by this object into
108// directory.
109status_t
110BVolume::GetRootDirectory(BDirectory *directory) const
111{
112	// check parameter and initialization
113	status_t error = (directory && InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
114	// get FS stat
115	fs_info info;
116	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
117		error = errno;
118	// init the directory
119	if (error == B_OK) {
120		node_ref ref;
121		ref.device = info.dev;
122		ref.node = info.root;
123		error = directory->SetTo(&ref);
124	}
125	return error;
126}
127
128
129// Returns the total storage capacity of the volume.
130off_t
131BVolume::Capacity() const
132{
133	// check initialization
134	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
135	// get FS stat
136	fs_info info;
137	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
138		error = errno;
139	return (error == B_OK ? info.total_blocks * info.block_size : error);
140}
141
142
143// Returns the amount of unused space on the volume (in bytes).
144off_t
145BVolume::FreeBytes() const
146{
147	// check initialization
148	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
149	// get FS stat
150	fs_info info;
151	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
152		error = errno;
153	return (error == B_OK ? info.free_blocks * info.block_size : error);
154}
155
156
157// Returns the size of one block (in bytes).
158off_t
159BVolume::BlockSize() const
160{
161	// check initialization
162	if (InitCheck() != B_OK)
163		return B_NO_INIT;
164
165	// get FS stat
166	fs_info info;
167	if (fs_stat_dev(fDevice, &info) != 0)
168		return errno;
169
170	return info.block_size;
171}
172
173
174// Copies the name of the volume into the provided buffer.
175status_t
176BVolume::GetName(char *name) const
177{
178	// check parameter and initialization
179	status_t error = (name && InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
180	// get FS stat
181	fs_info info;
182	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
183		error = errno;
184	// copy the name
185	if (error == B_OK)
186		strncpy(name, info.volume_name, B_FILE_NAME_LENGTH);
187	return error;
188}
189
190
191// Sets the name of the volume.
192status_t
193BVolume::SetName(const char *name)
194{
195	// check initialization
196	if (!name || InitCheck() != B_OK)
197		return B_BAD_VALUE;
198	if (strlen(name) >= B_FILE_NAME_LENGTH)
199		return B_NAME_TOO_LONG;
200	// get the FS stat (including the old name) first
201	fs_info oldInfo;
202	if (fs_stat_dev(fDevice, &oldInfo) != 0)
203		return errno;
204	if (strcmp(name, oldInfo.volume_name) == 0)
205		return B_OK;
206	// set the volume name
207	fs_info newInfo;
208	strlcpy(newInfo.volume_name, name, sizeof(newInfo.volume_name));
209	status_t error = _kern_write_fs_info(fDevice, &newInfo,
210		FS_WRITE_FSINFO_NAME);
211	if (error != B_OK)
212		return error;
213
214	// change the name of the mount point
215
216	// R5 implementation checks if an entry with the volume's old name
217	// exists in the root directory and renames that entry, if it is indeed
218	// the mount point of the volume (or a link referring to it). In all other
219	// cases, nothing is done (even if the mount point is named like the
220	// volume, but lives in a different directory).
221	// We follow suit for the time being.
222	// NOTE: If the volume name itself is actually "boot", then this code
223	// tries to rename /boot, but that is prevented in the kernel.
224
225	BPath entryPath;
226	BEntry entry;
227	BEntry traversedEntry;
228	node_ref entryNodeRef;
229	if (BPrivate::Storage::check_entry_name(name) == B_OK
230		&& BPrivate::Storage::check_entry_name(oldInfo.volume_name) == B_OK
231		&& entryPath.SetTo("/", oldInfo.volume_name) == B_OK
232		&& entry.SetTo(entryPath.Path(), false) == B_OK
233		&& entry.Exists()
234		&& traversedEntry.SetTo(entryPath.Path(), true) == B_OK
235		&& traversedEntry.GetNodeRef(&entryNodeRef) == B_OK
236		&& entryNodeRef.device == fDevice
237		&& entryNodeRef.node == oldInfo.root) {
238		entry.Rename(name, false);
239	}
240	return error;
241}
242
243
244// Writes the volume's icon into icon.
245status_t
246BVolume::GetIcon(BBitmap *icon, icon_size which) const
247{
248	// check initialization
249	if (InitCheck() != B_OK)
250		return B_NO_INIT;
251
252	// get FS stat for the device name
253	fs_info info;
254	if (fs_stat_dev(fDevice, &info) != 0)
255		return errno;
256
257	// get the icon
258	return get_device_icon(info.device_name, icon, which);
259}
260
261
262status_t
263BVolume::GetIcon(uint8** _data, size_t* _size, type_code* _type) const
264{
265	// check initialization
266	if (InitCheck() != B_OK)
267		return B_NO_INIT;
268
269	// get FS stat for the device name
270	fs_info info;
271	if (fs_stat_dev(fDevice, &info) != 0)
272		return errno;
273
274	// get the icon
275	return get_device_icon(info.device_name, _data, _size, _type);
276}
277
278
279// Returns whether or not the volume is removable.
280bool
281BVolume::IsRemovable() const
282{
283	// check initialization
284	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
285	// get FS stat
286	fs_info info;
287	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
288		error = errno;
289	return (error == B_OK && (info.flags & B_FS_IS_REMOVABLE));
290}
291
292
293// Returns whether or not the volume is read-only.
294bool
295BVolume::IsReadOnly(void) const
296{
297	// check initialization
298	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
299	// get FS stat
300	fs_info info;
301	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
302		error = errno;
303	return (error == B_OK && (info.flags & B_FS_IS_READONLY));
304}
305
306
307// Returns whether or not the volume is persistent.
308bool
309BVolume::IsPersistent(void) const
310{
311	// check initialization
312	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
313	// get FS stat
314	fs_info info;
315	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
316		error = errno;
317	return (error == B_OK && (info.flags & B_FS_IS_PERSISTENT));
318}
319
320
321// Returns whether or not the volume is shared.
322bool
323BVolume::IsShared(void) const
324{
325	// check initialization
326	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
327	// get FS stat
328	fs_info info;
329	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
330		error = errno;
331	return (error == B_OK && (info.flags & B_FS_IS_SHARED));
332}
333
334
335// Returns whether or not the volume supports MIME-types.
336bool
337BVolume::KnowsMime(void) const
338{
339	// check initialization
340	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
341	// get FS stat
342	fs_info info;
343	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
344		error = errno;
345	return (error == B_OK && (info.flags & B_FS_HAS_MIME));
346}
347
348
349// Returns whether or not the volume supports attributes.
350bool
351BVolume::KnowsAttr(void) const
352{
353	// check initialization
354	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
355	// get FS stat
356	fs_info info;
357	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
358		error = errno;
359	return (error == B_OK && (info.flags & B_FS_HAS_ATTR));
360}
361
362
363// Returns whether or not the volume supports queries.
364bool
365BVolume::KnowsQuery(void) const
366{
367	// check initialization
368	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
369	// get FS stat
370	fs_info info;
371	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
372		error = errno;
373	return (error == B_OK && (info.flags & B_FS_HAS_QUERY));
374}
375
376
377// Returns whether or not the supplied BVolume object is a equal
378// to this object.
379bool
380BVolume::operator==(const BVolume &volume) const
381{
382	return ((InitCheck() != B_OK && volume.InitCheck() != B_OK)
383			|| fDevice == volume.fDevice);
384}
385
386// Returns whether or not the supplied BVolume object is NOT equal
387// to this object.
388bool
389BVolume::operator!=(const BVolume &volume) const
390{
391	return !(*this == volume);
392}
393
394
395// Assigns the supplied BVolume object to this volume.
396BVolume&
397BVolume::operator=(const BVolume &volume)
398{
399	if (&volume != this) {
400		this->fDevice = volume.fDevice;
401		this->fCStatus = volume.fCStatus;
402	}
403	return *this;
404}
405
406
407// FBC
408void BVolume::_TurnUpTheVolume1() {}
409void BVolume::_TurnUpTheVolume2() {}
410void BVolume::_TurnUpTheVolume3() {}
411void BVolume::_TurnUpTheVolume4() {}
412void BVolume::_TurnUpTheVolume5() {}
413void BVolume::_TurnUpTheVolume6() {}
414void BVolume::_TurnUpTheVolume7() {}
415void BVolume::_TurnUpTheVolume8() {}
416