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