xref: /haiku/src/kits/storage/Volume.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
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 
236 /*!	\brief Returns the size of one block (in bytes). It depends on the
237 		underlying file system what this means exactly.
238 	\return
239 	- The block size in bytes.
240 	- \c B_NO_INIT if the volume is not initialized.
241 	- Other errors forwarded from the file system.
242 */
243 off_t
244 BVolume::BlockSize() const
245 {
246 	// check initialization
247 	if (InitCheck() != B_OK)
248 		return B_NO_INIT;
249 
250 	// get FS stat
251 	fs_info info;
252 	if (fs_stat_dev(fDevice, &info) != 0)
253 		return errno;
254 
255 	return info.block_size;
256 }
257 
258 
259 // GetName
260 /*!	\brief Returns the name of the volume.
261 
262 	The name of the volume is copied into the provided buffer.
263 
264 	\param name A pointer to a pre-allocated character buffer of size
265 		   \c B_FILE_NAME_LENGTH or larger into which the name of the
266 		   volume shall be written.
267 	\return
268 	- \c B_OK: Everything went fine.
269 	- \c B_BAD_VALUE: \c NULL \a name or the object is not properly
270 	  initialized.
271 	- another error code
272 */
273 status_t
274 BVolume::GetName(char *name) const
275 {
276 	// check parameter and initialization
277 	status_t error = (name && InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
278 	// get FS stat
279 	fs_info info;
280 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
281 		error = errno;
282 	// copy the name
283 	if (error == B_OK)
284 		strncpy(name, info.volume_name, B_FILE_NAME_LENGTH);
285 	return error;
286 }
287 
288 // SetName
289 /*!	\brief Sets the name of the volume referred to by this object.
290 	\param name The volume's new name. Must not be longer than
291 		   \c B_FILE_NAME_LENGTH (including the terminating null).
292 	\return
293 	- \c B_OK: Everything went fine.
294 	- \c B_BAD_VALUE: \c NULL \a name or the object is not properly
295 	  initialized.
296 	- another error code
297 */
298 status_t
299 BVolume::SetName(const char *name)
300 {
301 	// check initialization
302 	if (!name || InitCheck() != B_OK)
303 		return B_BAD_VALUE;
304 	if (strlen(name) >= B_FILE_NAME_LENGTH)
305 		return B_NAME_TOO_LONG;
306 	// get the FS stat (including the old name) first
307 	fs_info oldInfo;
308 	if (fs_stat_dev(fDevice, &oldInfo) != 0)
309 		return errno;
310 	if (strcmp(name, oldInfo.volume_name) == 0)
311 		return B_OK;
312 	// set the volume name
313 	fs_info newInfo;
314 	strlcpy(newInfo.volume_name, name, sizeof(newInfo.volume_name));
315 	status_t error = _kern_write_fs_info(fDevice, &newInfo,
316 		FS_WRITE_FSINFO_NAME);
317 	if (error != B_OK)
318 		return error;
319 
320 	// change the name of the mount point
321 
322 	// R5 implementation checks, if an entry with the volume's old name
323 	// exists in the root directory and renames that entry, if it is indeed
324 	// the mount point of the volume (or a link referring to it). In all other
325 	// cases, nothing is done (even if the mount point is named like the
326 	// volume, but lives in a different directory).
327 	// We follow suit for the time being.
328 	// NOTE: If the volume name itself is actually "boot", then this code
329 	// tries to rename /boot, but that is prevented in the kernel.
330 
331 	BPath entryPath;
332 	BEntry entry;
333 	BEntry traversedEntry;
334 	node_ref entryNodeRef;
335 	if (BPrivate::Storage::check_entry_name(name) == B_OK
336 		&& BPrivate::Storage::check_entry_name(oldInfo.volume_name) == B_OK
337 		&& entryPath.SetTo("/", oldInfo.volume_name) == B_OK
338 		&& entry.SetTo(entryPath.Path(), false) == B_OK
339 		&& entry.Exists()
340 		&& traversedEntry.SetTo(entryPath.Path(), true) == B_OK
341 		&& traversedEntry.GetNodeRef(&entryNodeRef) == B_OK
342 		&& entryNodeRef.device == fDevice
343 		&& entryNodeRef.node == oldInfo.root) {
344 		entry.Rename(name, false);
345 	}
346 	return error;
347 }
348 
349 // GetIcon
350 /*!	\brief Returns the icon of the volume.
351 	\param icon A pointer to a pre-allocated BBitmap of the correct dimension
352 		   to store the requested icon (16x16 for the mini and 32x32 for the
353 		   large icon).
354 	\param which Specifies the size of the icon to be retrieved:
355 		   \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon.
356 */
357 status_t
358 BVolume::GetIcon(BBitmap *icon, icon_size which) const
359 {
360 	// check initialization
361 	if (InitCheck() != B_OK)
362 		return B_NO_INIT;
363 
364 	// get FS stat for the device name
365 	fs_info info;
366 	if (fs_stat_dev(fDevice, &info) != 0)
367 		return errno;
368 
369 	// get the icon
370 	return get_device_icon(info.device_name, icon, which);
371 }
372 
373 
374 status_t
375 BVolume::GetIcon(uint8** _data, size_t* _size, type_code* _type) const
376 {
377 	// check initialization
378 	if (InitCheck() != B_OK)
379 		return B_NO_INIT;
380 
381 	// get FS stat for the device name
382 	fs_info info;
383 	if (fs_stat_dev(fDevice, &info) != 0)
384 		return errno;
385 
386 	// get the icon
387 	return get_device_icon(info.device_name, _data, _size, _type);
388 }
389 
390 
391 /*!	\brief Returns whether the volume is removable.
392 	\return \c true, when the object is properly initialized and the
393 	referred to volume is removable, \c false otherwise.
394 */
395 bool
396 BVolume::IsRemovable() const
397 {
398 	// check initialization
399 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
400 	// get FS stat
401 	fs_info info;
402 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
403 		error = errno;
404 	return (error == B_OK && (info.flags & B_FS_IS_REMOVABLE));
405 }
406 
407 // IsReadOnly
408 /*!	\brief Returns whether the volume is read only.
409 	\return \c true, when the object is properly initialized and the
410 	referred to volume is read only, \c false otherwise.
411 */
412 bool
413 BVolume::IsReadOnly(void) const
414 {
415 	// check initialization
416 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
417 	// get FS stat
418 	fs_info info;
419 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
420 		error = errno;
421 	return (error == B_OK && (info.flags & B_FS_IS_READONLY));
422 }
423 
424 // IsPersistent
425 /*!	\brief Returns whether the volume is persistent.
426 	\return \c true, when the object is properly initialized and the
427 	referred to volume is persistent, \c false otherwise.
428 */
429 bool
430 BVolume::IsPersistent(void) const
431 {
432 	// check initialization
433 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
434 	// get FS stat
435 	fs_info info;
436 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
437 		error = errno;
438 	return (error == B_OK && (info.flags & B_FS_IS_PERSISTENT));
439 }
440 
441 // IsShared
442 /*!	\brief Returns whether the volume is shared.
443 	\return \c true, when the object is properly initialized and the
444 	referred to volume is shared, \c false otherwise.
445 */
446 bool
447 BVolume::IsShared(void) const
448 {
449 	// check initialization
450 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
451 	// get FS stat
452 	fs_info info;
453 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
454 		error = errno;
455 	return (error == B_OK && (info.flags & B_FS_IS_SHARED));
456 }
457 
458 // KnowsMime
459 /*!	\brief Returns whether the volume supports MIME types.
460 	\return \c true, when the object is properly initialized and the
461 	referred to volume supports MIME types, \c false otherwise.
462 */
463 bool
464 BVolume::KnowsMime(void) const
465 {
466 	// check initialization
467 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
468 	// get FS stat
469 	fs_info info;
470 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
471 		error = errno;
472 	return (error == B_OK && (info.flags & B_FS_HAS_MIME));
473 }
474 
475 // KnowsAttr
476 /*!	\brief Returns whether the volume supports attributes.
477 	\return \c true, when the object is properly initialized and the
478 	referred to volume supports attributes, \c false otherwise.
479 */
480 bool
481 BVolume::KnowsAttr(void) const
482 {
483 	// check initialization
484 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
485 	// get FS stat
486 	fs_info info;
487 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
488 		error = errno;
489 	return (error == B_OK && (info.flags & B_FS_HAS_ATTR));
490 }
491 
492 // KnowsQuery
493 /*!	\brief Returns whether the volume supports queries.
494 	\return \c true, when the object is properly initialized and the
495 	referred to volume supports queries, \c false otherwise.
496 */
497 bool
498 BVolume::KnowsQuery(void) const
499 {
500 	// check initialization
501 	status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE);
502 	// get FS stat
503 	fs_info info;
504 	if (error == B_OK && fs_stat_dev(fDevice, &info) != 0)
505 		error = errno;
506 	return (error == B_OK && (info.flags & B_FS_HAS_QUERY));
507 }
508 
509 // ==
510 /*!	\brief Returns whether two BVolume objects are equal.
511 
512 	Two volume objects are said to be equal, if they either are both
513 	uninitialized, or both are initialized and refer to the same volume.
514 
515 	\param volume The object to be compared with.
516 	\result \c true, if this object and the supplied one are equal, \c false
517 			otherwise.
518 */
519 bool
520 BVolume::operator==(const BVolume &volume) const
521 {
522 	return ((InitCheck() != B_OK && volume.InitCheck() != B_OK)
523 			|| fDevice == volume.fDevice);
524 }
525 
526 // !=
527 /*!	\brief Returns whether two BVolume objects are unequal.
528 
529 	Two volume objects are said to be equal, if they either are both
530 	uninitialized, or both are initialized and refer to the same volume.
531 
532 	\param volume The object to be compared with.
533 	\result \c true, if this object and the supplied one are unequal, \c false
534 			otherwise.
535 */
536 bool
537 BVolume::operator!=(const BVolume &volume) const
538 {
539 	return !(*this == volume);
540 }
541 
542 // =
543 /*!	\brief Assigns another BVolume object to this one.
544 
545 	This object is made an exact clone of the supplied one.
546 
547 	\param volume The volume from which shall be assigned.
548 	\return A reference to this object.
549 */
550 BVolume&
551 BVolume::operator=(const BVolume &volume)
552 {
553 	if (&volume != this) {
554 		this->fDevice = volume.fDevice;
555 		this->fCStatus = volume.fCStatus;
556 	}
557 	return *this;
558 }
559 
560 
561 // FBC
562 void BVolume::_TurnUpTheVolume1() {}
563 void BVolume::_TurnUpTheVolume2() {}
564 void BVolume::_TurnUpTheVolume3() {}
565 void BVolume::_TurnUpTheVolume4() {}
566 void BVolume::_TurnUpTheVolume5() {}
567 void BVolume::_TurnUpTheVolume6() {}
568 void BVolume::_TurnUpTheVolume7() {}
569 void BVolume::_TurnUpTheVolume8() {}
570