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