xref: /haiku/src/kits/storage/Volume.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
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 	\file Volume.h
12 	BVolume implementation.
13 */
14 
15 #include <errno.h>
16 #include <string.h>
17 
18 #include <Bitmap.h>
19 #include <Directory.h>
20 #include <fs_info.h>
21 #include <Node.h>
22 #include <Path.h>
23 #include <Volume.h>
24 
25 #include <storage_support.h>
26 #include <syscalls.h>
27 
28 #include <fs_interface.h>
29 
30 
31 /*!
32 	\class BVolume
33 	\brief Represents a disk volume
34 
35 	Provides an interface for querying information about a volume.
36 
37 	The class is a simple wrapper for a \c dev_t and the function
38 	fs_stat_dev. The only exception is the method is SetName(), which
39 	sets the name of the volume.
40 
41 	\author Vincent Dominguez
42 	\author <a href='mailto:bonefish@users.sf.net'>Ingo Weinhold</a>
43 
44 	\version 0.0.0
45 */
46 
47 /*!	\var dev_t BVolume::fDevice
48 	\brief The volume's device ID.
49 */
50 
51 /*!	\var dev_t BVolume::fCStatus
52 	\brief The object's initialization status.
53 */
54 
55 // constructor
56 /*!	\brief Creates an uninitialized BVolume.
57 
58 	InitCheck() will return \c B_NO_INIT.
59 */
60 BVolume::BVolume()
61 	: fDevice((dev_t)-1),
62 	  fCStatus(B_NO_INIT)
63 {
64 }
65 
66 // constructor
67 /*!	\brief Creates a BVolume and initializes it to the volume specified
68 		   by the supplied device ID.
69 
70 	InitCheck() should be called to check whether the initialization was
71 	successful.
72 
73 	\param device The device ID of the volume.
74 */
75 BVolume::BVolume(dev_t device)
76 	: fDevice((dev_t)-1),
77 	  fCStatus(B_NO_INIT)
78 {
79 	SetTo(device);
80 }
81 
82 // copy constructor
83 /*!	\brief Creates a BVolume and makes it a clone of the supplied one.
84 
85 	Afterwards the object refers to the same device the supplied object
86 	does. If the latter is not properly initialized, this object isn't
87 	either.
88 
89 	\param volume The volume object to be cloned.
90 */
91 BVolume::BVolume(const BVolume &volume)
92 	: fDevice(volume.fDevice),
93 	  fCStatus(volume.fCStatus)
94 {
95 }
96 
97 // destructor
98 /*!	\brief Frees all resources associated with the object.
99 
100 	Does nothing.
101 */
102 BVolume::~BVolume()
103 {
104 }
105 
106 // InitCheck
107 /*!	\brief Returns the result of the last initialization.
108 	\return
109 	- \c B_OK: The object is properly initialized.
110 	- an error code otherwise
111 */
112 status_t
113 BVolume::InitCheck(void) const
114 {
115 	return fCStatus;
116 }
117 
118 // SetTo
119 /*!	\brief Re-initializes the object to refer to the volume specified by
120 		   the supplied device ID.
121 	\param device The device ID of the volume.
122 	\param
123 	- \c B_OK: Everything went fine.
124 	- an error code otherwise
125 */
126 status_t
127 BVolume::SetTo(dev_t device)
128 {
129 	// uninitialize
130 	Unset();
131 	// check the parameter
132 	status_t error = (device >= 0 ? B_OK : B_BAD_VALUE);
133 	if (error == B_OK) {
134 		fs_info info;
135 		if (fs_stat_dev(device, &info) != 0)
136 			error = errno;
137 	}
138 	// set the new value
139 	if (error == B_OK)
140 		fDevice = device;
141 	// set the init status variable
142 	fCStatus = error;
143 	return fCStatus;
144 }
145 
146 // Unset
147 /*!	\brief Uninitialized the BVolume.
148 */
149 void
150 BVolume::Unset()
151 {
152 	fDevice = (dev_t)-1;
153 	fCStatus = B_NO_INIT;
154 }
155 
156 // Device
157 /*!	\brief Returns the device ID of the volume the object refers to.
158 	\return Returns the device ID of the volume the object refers to
159 			or -1, if the object is not properly initialized.
160 */
161 dev_t
162 BVolume::Device() const
163 {
164 	return fDevice;
165 }
166 
167 // GetRootDirectory
168 /*!	\brief Returns the root directory of the volume referred to by the object.
169 	\param directory A pointer to a pre-allocated BDirectory to be initialized
170 		   to the volume's root directory.
171 	\return
172 	- \c B_OK: Everything went fine.
173 	- \c B_BAD_VALUE: \c NULL \a directory or the object is not properly
174 	  initialized.
175 	- another error code
176 */
177 status_t
178 BVolume::GetRootDirectory(BDirectory *directory) const
179 {
180 	// check parameter and initialization
181 	status_t error = (directory && InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
182 	// get FS stat
183 	fs_info info;
184 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
185 		error = errno;
186 	// init the directory
187 	if (error == B_OK) {
188 		node_ref ref;
189 		ref.device = info.dev;
190 		ref.node = info.root;
191 		error = directory->SetTo(&ref);
192 	}
193 	return error;
194 }
195 
196 // Capacity
197 /*!	\brief Returns the volume's total storage capacity.
198 	\return
199 	- The volume's total storage capacity (in bytes), when the object is
200 	  properly initialized.
201 	- \c B_BAD_VALUE otherwise.
202 */
203 off_t
204 BVolume::Capacity() const
205 {
206 	// check initialization
207 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
208 	// get FS stat
209 	fs_info info;
210 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
211 		error = errno;
212 	return (error == B_OK ? info.total_blocks * info.block_size : error);
213 }
214 
215 // FreeBytes
216 /*!	\brief Returns the amount of storage that's currently unused on the
217 		   volume (in bytes).
218 	\return
219 	- The amount of storage that's currently unused on the volume (in bytes),
220 	  when the object is properly initialized.
221 	- \c B_BAD_VALUE otherwise.
222 */
223 off_t
224 BVolume::FreeBytes() const
225 {
226 	// check initialization
227 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
228 	// get FS stat
229 	fs_info info;
230 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
231 		error = errno;
232 	return (error == B_OK ? info.free_blocks * info.block_size : error);
233 }
234 
235 // GetName
236 /*!	\brief Returns the name of the volume.
237 
238 	The name of the volume is copied into the provided buffer.
239 
240 	\param name A pointer to a pre-allocated character buffer of size
241 		   \c B_FILE_NAME_LENGTH or larger into which the name of the
242 		   volume shall be written.
243 	\return
244 	- \c B_OK: Everything went fine.
245 	- \c B_BAD_VALUE: \c NULL \a name or the object is not properly
246 	  initialized.
247 	- another error code
248 */
249 status_t
250 BVolume::GetName(char *name) const
251 {
252 	// check parameter and initialization
253 	status_t error = (name && InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
254 	// get FS stat
255 	fs_info info;
256 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
257 		error = errno;
258 	// copy the name
259 	if (error == B_OK)
260 		strncpy(name, info.volume_name, B_FILE_NAME_LENGTH);
261 	return error;
262 }
263 
264 // SetName
265 /*!	\brief Sets the name of the volume referred to by this object.
266 	\param name The volume's new name. Must not be longer than
267 		   \c B_FILE_NAME_LENGTH (including the terminating null).
268 	\return
269 	- \c B_OK: Everything went fine.
270 	- \c B_BAD_VALUE: \c NULL \a name or the object is not properly
271 	  initialized.
272 	- another error code
273 */
274 status_t
275 BVolume::SetName(const char *name)
276 {
277 	// check initialization
278 	if (!name || InitCheck() != B_OK)
279 		return B_BAD_VALUE;
280 	if (strlen(name) >= B_FILE_NAME_LENGTH)
281 		return B_NAME_TOO_LONG;
282 	// get the FS stat (including the old name) first
283 	fs_info oldInfo;
284 	if (fs_stat_dev(fDevice, &oldInfo) != 0)
285 		return errno;
286 	if (strcmp(name, oldInfo.volume_name) == 0)
287 		return B_OK;
288 	// set the volume name
289 	fs_info newInfo;
290 	strlcpy(newInfo.volume_name, name, sizeof(newInfo.volume_name));
291 	status_t error = _kern_write_fs_info(fDevice, &newInfo,
292 		FS_WRITE_FSINFO_NAME);
293 	if (error != B_OK)
294 		return error;
295 
296 	// change the name of the mount point
297 
298 	// R5 implementation checks, if an entry with the volume's old name
299 	// exists in the root directory and renames that entry, if it is indeed
300 	// the mount point of the volume (or a link referring to it). In all other
301 	// cases, nothing is done (even if the mount point is named like the
302 	// volume, but lives in a different directory).
303 	// We follow suit for the time being.
304 	// NOTE: If the volume name itself is actually "boot", then this code
305 	// tries to rename /boot, but that is prevented in the kernel.
306 
307 	BPath entryPath;
308 	BEntry entry;
309 	BEntry traversedEntry;
310 	node_ref entryNodeRef;
311 	if (BPrivate::Storage::check_entry_name(name) == B_OK
312 		&& BPrivate::Storage::check_entry_name(oldInfo.volume_name) == B_OK
313 		&& entryPath.SetTo("/", oldInfo.volume_name) == B_OK
314 		&& entry.SetTo(entryPath.Path(), false) == B_OK
315 		&& entry.Exists()
316 		&& traversedEntry.SetTo(entryPath.Path(), true) == B_OK
317 		&& traversedEntry.GetNodeRef(&entryNodeRef) == B_OK
318 		&& entryNodeRef.device == fDevice
319 		&& entryNodeRef.node == oldInfo.root) {
320 		entry.Rename(name, false);
321 	}
322 	return error;
323 }
324 
325 // GetIcon
326 /*!	\brief Returns the icon of the volume.
327 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
328 		   to store the requested icon (16x16 for the mini and 32x32 for the
329 		   large icon).
330 	\param which Specifies the size of the icon to be retrieved:
331 		   \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon.
332 */
333 status_t
334 BVolume::GetIcon(BBitmap *icon, icon_size which) const
335 {
336 	// check initialization
337 	if (InitCheck() != B_OK)
338 		return B_NO_INIT;
339 
340 	// get FS stat for the device name
341 	fs_info info;
342 	if (fs_stat_dev(fDevice, &info) != 0)
343 		return errno;
344 
345 	// get the icon
346 	return get_device_icon(info.device_name, icon, which);
347 }
348 
349 
350 status_t
351 BVolume::GetIcon(uint8** _data, size_t* _size, type_code* _type) const
352 {
353 	// check initialization
354 	if (InitCheck() != B_OK)
355 		return B_NO_INIT;
356 
357 	// get FS stat for the device name
358 	fs_info info;
359 	if (fs_stat_dev(fDevice, &info) != 0)
360 		return errno;
361 
362 	// get the icon
363 	return get_device_icon(info.device_name, _data, _size, _type);
364 }
365 
366 
367 /*!	\brief Returns whether the volume is removable.
368 	\return \c true, when the object is properly initialized and the
369 	referred to volume is removable, \c false otherwise.
370 */
371 bool
372 BVolume::IsRemovable() const
373 {
374 	// check initialization
375 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
376 	// get FS stat
377 	fs_info info;
378 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
379 		error = errno;
380 	return (error == B_OK && (info.flags & B_FS_IS_REMOVABLE));
381 }
382 
383 // IsReadOnly
384 /*!	\brief Returns whether the volume is read only.
385 	\return \c true, when the object is properly initialized and the
386 	referred to volume is read only, \c false otherwise.
387 */
388 bool
389 BVolume::IsReadOnly(void) const
390 {
391 	// check initialization
392 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
393 	// get FS stat
394 	fs_info info;
395 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
396 		error = errno;
397 	return (error == B_OK && (info.flags & B_FS_IS_READONLY));
398 }
399 
400 // IsPersistent
401 /*!	\brief Returns whether the volume is persistent.
402 	\return \c true, when the object is properly initialized and the
403 	referred to volume is persistent, \c false otherwise.
404 */
405 bool
406 BVolume::IsPersistent(void) const
407 {
408 	// check initialization
409 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
410 	// get FS stat
411 	fs_info info;
412 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
413 		error = errno;
414 	return (error == B_OK && (info.flags & B_FS_IS_PERSISTENT));
415 }
416 
417 // IsShared
418 /*!	\brief Returns whether the volume is shared.
419 	\return \c true, when the object is properly initialized and the
420 	referred to volume is shared, \c false otherwise.
421 */
422 bool
423 BVolume::IsShared(void) const
424 {
425 	// check initialization
426 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
427 	// get FS stat
428 	fs_info info;
429 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
430 		error = errno;
431 	return (error == B_OK && (info.flags & B_FS_IS_SHARED));
432 }
433 
434 // KnowsMime
435 /*!	\brief Returns whether the volume supports MIME types.
436 	\return \c true, when the object is properly initialized and the
437 	referred to volume supports MIME types, \c false otherwise.
438 */
439 bool
440 BVolume::KnowsMime(void) const
441 {
442 	// check initialization
443 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
444 	// get FS stat
445 	fs_info info;
446 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
447 		error = errno;
448 	return (error == B_OK && (info.flags & B_FS_HAS_MIME));
449 }
450 
451 // KnowsAttr
452 /*!	\brief Returns whether the volume supports attributes.
453 	\return \c true, when the object is properly initialized and the
454 	referred to volume supports attributes, \c false otherwise.
455 */
456 bool
457 BVolume::KnowsAttr(void) const
458 {
459 	// check initialization
460 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
461 	// get FS stat
462 	fs_info info;
463 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
464 		error = errno;
465 	return (error == B_OK && (info.flags & B_FS_HAS_ATTR));
466 }
467 
468 // KnowsQuery
469 /*!	\brief Returns whether the volume supports queries.
470 	\return \c true, when the object is properly initialized and the
471 	referred to volume supports queries, \c false otherwise.
472 */
473 bool
474 BVolume::KnowsQuery(void) const
475 {
476 	// check initialization
477 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
478 	// get FS stat
479 	fs_info info;
480 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
481 		error = errno;
482 	return (error == B_OK && (info.flags & B_FS_HAS_QUERY));
483 }
484 
485 // ==
486 /*!	\brief Returns whether two BVolume objects are equal.
487 
488 	Two volume objects are said to be equal, if they either are both
489 	uninitialized, or both are initialized and refer to the same volume.
490 
491 	\param volume The object to be compared with.
492 	\result \c true, if this object and the supplied one are equal, \c false
493 			otherwise.
494 */
495 bool
496 BVolume::operator==(const BVolume &volume) const
497 {
498 	return ((InitCheck() != B_OK && volume.InitCheck() != B_OK)
499 			|| fDevice == volume.fDevice);
500 }
501 
502 // !=
503 /*!	\brief Returns whether two BVolume objects are unequal.
504 
505 	Two volume objects are said to be equal, if they either are both
506 	uninitialized, or both are initialized and refer to the same volume.
507 
508 	\param volume The object to be compared with.
509 	\result \c true, if this object and the supplied one are unequal, \c false
510 			otherwise.
511 */
512 bool
513 BVolume::operator!=(const BVolume &volume) const
514 {
515 	return !(*this == volume);
516 }
517 
518 // =
519 /*!	\brief Assigns another BVolume object to this one.
520 
521 	This object is made an exact clone of the supplied one.
522 
523 	\param volume The volume from which shall be assigned.
524 	\return A reference to this object.
525 */
526 BVolume&
527 BVolume::operator=(const BVolume &volume)
528 {
529 	if (&volume != this) {
530 		this->fDevice = volume.fDevice;
531 		this->fCStatus = volume.fCStatus;
532 	}
533 	return *this;
534 }
535 
536 
537 // FBC
538 void BVolume::_TurnUpTheVolume1() {}
539 void BVolume::_TurnUpTheVolume2() {}
540 void BVolume::_TurnUpTheVolume3() {}
541 void BVolume::_TurnUpTheVolume4() {}
542 void BVolume::_TurnUpTheVolume5() {}
543 void BVolume::_TurnUpTheVolume6() {}
544 void BVolume::_TurnUpTheVolume7() {}
545 void BVolume::_TurnUpTheVolume8() {}
546