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