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 // change the name of the mount point 296 // R5 implementation checks, if an entry with the volume's old name 297 // exists in the root directory and renames that entry, if it is indeed 298 // the mount point of the volume (or a link referring to it). In all other 299 // cases, nothing is done (even if the mount point is named like the 300 // volume, but lives in a different directory). 301 // We follow suit for the time being. 302 // create the entry 303 BPath entryPath; 304 BEntry entry; 305 BEntry traversedEntry; 306 node_ref entryNodeRef; 307 if (BPrivate::Storage::check_entry_name(name) == B_OK 308 && BPrivate::Storage::check_entry_name(oldInfo.volume_name) == B_OK 309 && entryPath.SetTo("/", oldInfo.volume_name) == B_OK 310 && entry.SetTo(entryPath.Path(), false) == B_OK 311 && entry.Exists() 312 && traversedEntry.SetTo(entryPath.Path(), true) == B_OK 313 && traversedEntry.GetNodeRef(&entryNodeRef) == B_OK 314 && entryNodeRef.device == fDevice 315 && entryNodeRef.node == oldInfo.root) { 316 traversedEntry.Rename(name, false); 317 } 318 return error; 319 } 320 321 // GetIcon 322 /*! \brief Returns the icon of the volume. 323 \param icon A pointer to a pre-allocated BBitmap of the correct dimension 324 to store the requested icon (16x16 for the mini and 32x32 for the 325 large icon). 326 \param which Specifies the size of the icon to be retrieved: 327 \c B_MINI_ICON for the mini and \c B_LARGE_ICON for the large icon. 328 */ 329 status_t 330 BVolume::GetIcon(BBitmap *icon, icon_size which) const 331 { 332 // check initialization 333 if (InitCheck() != B_OK) 334 return B_NO_INIT; 335 336 // get FS stat for the device name 337 fs_info info; 338 if (fs_stat_dev(fDevice, &info) != 0) 339 return errno; 340 341 // get the icon 342 return get_device_icon(info.device_name, icon, which); 343 } 344 345 346 status_t 347 BVolume::GetIcon(uint8** _data, size_t* _size, type_code* _type) const 348 { 349 // check initialization 350 if (InitCheck() != B_OK) 351 return B_NO_INIT; 352 353 // get FS stat for the device name 354 fs_info info; 355 if (fs_stat_dev(fDevice, &info) != 0) 356 return errno; 357 358 // get the icon 359 return get_device_icon(info.device_name, _data, _size, _type); 360 } 361 362 363 /*! \brief Returns whether the volume is removable. 364 \return \c true, when the object is properly initialized and the 365 referred to volume is removable, \c false otherwise. 366 */ 367 bool 368 BVolume::IsRemovable() const 369 { 370 // check initialization 371 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 372 // get FS stat 373 fs_info info; 374 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 375 error = errno; 376 return (error == B_OK && (info.flags & B_FS_IS_REMOVABLE)); 377 } 378 379 // IsReadOnly 380 /*! \brief Returns whether the volume is read only. 381 \return \c true, when the object is properly initialized and the 382 referred to volume is read only, \c false otherwise. 383 */ 384 bool 385 BVolume::IsReadOnly(void) const 386 { 387 // check initialization 388 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 389 // get FS stat 390 fs_info info; 391 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 392 error = errno; 393 return (error == B_OK && (info.flags & B_FS_IS_READONLY)); 394 } 395 396 // IsPersistent 397 /*! \brief Returns whether the volume is persistent. 398 \return \c true, when the object is properly initialized and the 399 referred to volume is persistent, \c false otherwise. 400 */ 401 bool 402 BVolume::IsPersistent(void) const 403 { 404 // check initialization 405 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 406 // get FS stat 407 fs_info info; 408 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 409 error = errno; 410 return (error == B_OK && (info.flags & B_FS_IS_PERSISTENT)); 411 } 412 413 // IsShared 414 /*! \brief Returns whether the volume is shared. 415 \return \c true, when the object is properly initialized and the 416 referred to volume is shared, \c false otherwise. 417 */ 418 bool 419 BVolume::IsShared(void) const 420 { 421 // check initialization 422 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 423 // get FS stat 424 fs_info info; 425 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 426 error = errno; 427 return (error == B_OK && (info.flags & B_FS_IS_SHARED)); 428 } 429 430 // KnowsMime 431 /*! \brief Returns whether the volume supports MIME types. 432 \return \c true, when the object is properly initialized and the 433 referred to volume supports MIME types, \c false otherwise. 434 */ 435 bool 436 BVolume::KnowsMime(void) const 437 { 438 // check initialization 439 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 440 // get FS stat 441 fs_info info; 442 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 443 error = errno; 444 return (error == B_OK && (info.flags & B_FS_HAS_MIME)); 445 } 446 447 // KnowsAttr 448 /*! \brief Returns whether the volume supports attributes. 449 \return \c true, when the object is properly initialized and the 450 referred to volume supports attributes, \c false otherwise. 451 */ 452 bool 453 BVolume::KnowsAttr(void) const 454 { 455 // check initialization 456 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 457 // get FS stat 458 fs_info info; 459 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 460 error = errno; 461 return (error == B_OK && (info.flags & B_FS_HAS_ATTR)); 462 } 463 464 // KnowsQuery 465 /*! \brief Returns whether the volume supports queries. 466 \return \c true, when the object is properly initialized and the 467 referred to volume supports queries, \c false otherwise. 468 */ 469 bool 470 BVolume::KnowsQuery(void) const 471 { 472 // check initialization 473 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 474 // get FS stat 475 fs_info info; 476 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 477 error = errno; 478 return (error == B_OK && (info.flags & B_FS_HAS_QUERY)); 479 } 480 481 // == 482 /*! \brief Returns whether two BVolume objects are equal. 483 484 Two volume objects are said to be equal, if they either are both 485 uninitialized, or both are initialized and refer to the same volume. 486 487 \param volume The object to be compared with. 488 \result \c true, if this object and the supplied one are equal, \c false 489 otherwise. 490 */ 491 bool 492 BVolume::operator==(const BVolume &volume) const 493 { 494 return ((InitCheck() != B_OK && volume.InitCheck() != B_OK) 495 || fDevice == volume.fDevice); 496 } 497 498 // != 499 /*! \brief Returns whether two BVolume objects are unequal. 500 501 Two volume objects are said to be equal, if they either are both 502 uninitialized, or both are initialized and refer to the same volume. 503 504 \param volume The object to be compared with. 505 \result \c true, if this object and the supplied one are unequal, \c false 506 otherwise. 507 */ 508 bool 509 BVolume::operator!=(const BVolume &volume) const 510 { 511 return !(*this == volume); 512 } 513 514 // = 515 /*! \brief Assigns another BVolume object to this one. 516 517 This object is made an exact clone of the supplied one. 518 519 \param volume The volume from which shall be assigned. 520 \return A reference to this object. 521 */ 522 BVolume& 523 BVolume::operator=(const BVolume &volume) 524 { 525 if (&volume != this) { 526 this->fDevice = volume.fDevice; 527 this->fCStatus = volume.fCStatus; 528 } 529 return *this; 530 } 531 532 533 // FBC 534 void BVolume::_TurnUpTheVolume1() {} 535 void BVolume::_TurnUpTheVolume2() {} 536 void BVolume::_TurnUpTheVolume3() {} 537 void BVolume::_TurnUpTheVolume4() {} 538 void BVolume::_TurnUpTheVolume5() {} 539 void BVolume::_TurnUpTheVolume6() {} 540 void BVolume::_TurnUpTheVolume7() {} 541 void BVolume::_TurnUpTheVolume8() {} 542