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