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