1 // ---------------------------------------------------------------------- 2 // This software is part of the OpenBeOS distribution and is covered 3 // by the OpenBeOS license. 4 // 5 // File Name: Volume.cpp 6 // 7 // Description: BVolume class 8 // ---------------------------------------------------------------------- 9 /*! 10 \file Volume.h 11 BVolume implementation. 12 */ 13 14 #include <errno.h> 15 #include <string.h> 16 17 #include <Bitmap.h> 18 #include <Directory.h> 19 #include <fs_info.h> 20 #include <Node.h> 21 #include <Path.h> 22 #include <Volume.h> 23 24 #include <storage_support.h> 25 #include <syscalls.h> 26 27 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST 28 #include <fs_interface.h> 29 #endif 30 31 #ifdef USE_OPENBEOS_NAMESPACE 32 namespace OpenBeOS { 33 #endif 34 35 /*! 36 \class BVolume 37 \brief Represents a disk volume 38 39 Provides an interface for querying information about a volume. 40 41 The class is a simple wrapper for a \c dev_t and the function 42 fs_stat_dev. The only exception is the method is SetName(), which 43 sets the name of the volume. 44 45 \author Vincent Dominguez 46 \author <a href='mailto:bonefish@users.sf.net'>Ingo Weinhold</a> 47 48 \version 0.0.0 49 */ 50 51 /*! \var dev_t BVolume::fDevice 52 \brief The volume's device ID. 53 */ 54 55 /*! \var dev_t BVolume::fCStatus 56 \brief The object's initialization status. 57 */ 58 59 // constructor 60 /*! \brief Creates an uninitialized BVolume. 61 62 InitCheck() will return \c B_NO_INIT. 63 */ 64 BVolume::BVolume() 65 : fDevice((dev_t)-1), 66 fCStatus(B_NO_INIT) 67 { 68 } 69 70 // constructor 71 /*! \brief Creates a BVolume and initializes it to the volume specified 72 by the supplied device ID. 73 74 InitCheck() should be called to check whether the initialization was 75 successful. 76 77 \param device The device ID of the volume. 78 */ 79 BVolume::BVolume(dev_t device) 80 : fDevice((dev_t)-1), 81 fCStatus(B_NO_INIT) 82 { 83 SetTo(device); 84 } 85 86 // copy constructor 87 /*! \brief Creates a BVolume and makes it a clone of the supplied one. 88 89 Afterwards the object refers to the same device the supplied object 90 does. If the latter is not properly initialized, this object isn't 91 either. 92 93 \param volume The volume object to be cloned. 94 */ 95 BVolume::BVolume(const BVolume &volume) 96 : fDevice(volume.fDevice), 97 fCStatus(volume.fCStatus) 98 { 99 } 100 101 // destructor 102 /*! \brief Frees all resources associated with the object. 103 104 Does nothing. 105 */ 106 BVolume::~BVolume() 107 { 108 } 109 110 // InitCheck 111 /*! \brief Returns the result of the last initialization. 112 \return 113 - \c B_OK: The object is properly initialized. 114 - an error code otherwise 115 */ 116 status_t 117 BVolume::InitCheck(void) const 118 { 119 return fCStatus; 120 } 121 122 // SetTo 123 /*! \brief Re-initializes the object to refer to the volume specified by 124 the supplied device ID. 125 \param device The device ID of the volume. 126 \param 127 - \c B_OK: Everything went fine. 128 - an error code otherwise 129 */ 130 status_t 131 BVolume::SetTo(dev_t device) 132 { 133 // uninitialize 134 Unset(); 135 // check the parameter 136 status_t error = (device >= 0 ? B_OK : B_BAD_VALUE); 137 if (error == B_OK) { 138 fs_info info; 139 if (fs_stat_dev(device, &info) != 0) 140 error = errno; 141 } 142 // set the new value 143 if (error == B_OK) 144 fDevice = device; 145 // set the init status variable 146 fCStatus = error; 147 return fCStatus; 148 } 149 150 // Unset 151 /*! \brief Uninitialized the BVolume. 152 */ 153 void 154 BVolume::Unset() 155 { 156 fDevice = (dev_t)-1; 157 fCStatus = B_NO_INIT; 158 } 159 160 // Device 161 /*! \brief Returns the device ID of the volume the object refers to. 162 \return Returns the device ID of the volume the object refers to 163 or -1, if the object is not properly initialized. 164 */ 165 dev_t 166 BVolume::Device() const 167 { 168 return fDevice; 169 } 170 171 // GetRootDirectory 172 /*! \brief Returns the root directory of the volume referred to by the object. 173 \param directory A pointer to a pre-allocated BDirectory to be initialized 174 to the volume's root directory. 175 \return 176 - \c B_OK: Everything went fine. 177 - \c B_BAD_VALUE: \c NULL \a directory or the object is not properly 178 initialized. 179 - another error code 180 */ 181 status_t 182 BVolume::GetRootDirectory(BDirectory *directory) const 183 { 184 // check parameter and initialization 185 status_t error = (directory && InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 186 // get FS stat 187 fs_info info; 188 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 189 error = errno; 190 // init the directory 191 if (error == B_OK) { 192 node_ref ref; 193 ref.device = info.dev; 194 ref.node = info.root; 195 error = directory->SetTo(&ref); 196 } 197 return error; 198 } 199 200 // Capacity 201 /*! \brief Returns the volume's total storage capacity. 202 \return 203 - The volume's total storage capacity (in bytes), when the object is 204 properly initialized. 205 - \c B_BAD_VALUE otherwise. 206 */ 207 off_t 208 BVolume::Capacity() const 209 { 210 // check initialization 211 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 212 // get FS stat 213 fs_info info; 214 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 215 error = errno; 216 return (error == B_OK ? info.total_blocks * info.block_size : error); 217 } 218 219 // FreeBytes 220 /*! \brief Returns the amount of storage that's currently unused on the 221 volume (in bytes). 222 \return 223 - The amount of storage that's currently unused on the volume (in bytes), 224 when the object is properly initialized. 225 - \c B_BAD_VALUE otherwise. 226 */ 227 off_t 228 BVolume::FreeBytes() const 229 { 230 // check initialization 231 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 232 // get FS stat 233 fs_info info; 234 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 235 error = errno; 236 return (error == B_OK ? info.free_blocks * info.block_size : error); 237 } 238 239 // GetName 240 /*! \brief Returns the name of the volume. 241 242 The name of the volume is copied into the provided buffer. 243 244 \param name A pointer to a pre-allocated character buffer of size 245 \c B_FILE_NAME_LENGTH or larger into which the name of the 246 volume shall be written. 247 \return 248 - \c B_OK: Everything went fine. 249 - \c B_BAD_VALUE: \c NULL \a name or the object is not properly 250 initialized. 251 - another error code 252 */ 253 status_t 254 BVolume::GetName(char *name) const 255 { 256 // check parameter and initialization 257 status_t error = (name && InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 258 // get FS stat 259 fs_info info; 260 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 261 error = errno; 262 // copy the name 263 if (error == B_OK) 264 strncpy(name, info.volume_name, B_FILE_NAME_LENGTH); 265 return error; 266 } 267 268 // SetName 269 /*! \brief Sets the name of the volume referred to by this object. 270 \param name The volume's new name. Must not be longer than 271 \c B_FILE_NAME_LENGTH (including the terminating null). 272 \return 273 - \c B_OK: Everything went fine. 274 - \c B_BAD_VALUE: \c NULL \a name or the object is not properly 275 initialized. 276 - another error code 277 */ 278 status_t 279 BVolume::SetName(const char *name) 280 { 281 // check initialization 282 if (!name || InitCheck() != B_OK) 283 return B_BAD_VALUE; 284 if (strlen(name) >= B_FILE_NAME_LENGTH) 285 return B_NAME_TOO_LONG; 286 // get the FS stat (including the old name) first 287 fs_info oldInfo; 288 if (fs_stat_dev(fDevice, &oldInfo) != 0) 289 return errno; 290 if (strcmp(name, oldInfo.volume_name) == 0) 291 return B_OK; 292 // set the volume name 293 fs_info newInfo; 294 strlcpy(newInfo.volume_name, name, sizeof(newInfo.volume_name)); 295 status_t error = _kern_write_fs_info(fDevice, &newInfo, 296 FS_WRITE_FSINFO_NAME); 297 if (error != B_OK) 298 return error; 299 // change the name of the mount point 300 // R5 implementation checks, if an entry with the volume's old name 301 // exists in the root directory and renames that entry, if it is indeed 302 // the mount point of the volume (or a link referring to it). In all other 303 // cases, nothing is done (even if the mount point is named like the 304 // volume, but lives in a different directory). 305 // We follow suit for the time being. 306 // create the entry 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 traversedEntry.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 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 338 // get FS stat 339 fs_info info; 340 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 341 error = errno; 342 // get the icon 343 if (error == B_OK) 344 error = get_device_icon(info.device_name, icon, which); 345 return error; 346 } 347 348 // IsRemovable 349 /*! \brief Returns whether the volume is removable. 350 \return \c true, when the object is properly initialized and the 351 referred to volume is removable, \c false otherwise. 352 */ 353 bool 354 BVolume::IsRemovable() const 355 { 356 // check initialization 357 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 358 // get FS stat 359 fs_info info; 360 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 361 error = errno; 362 return (error == B_OK && (info.flags & B_FS_IS_REMOVABLE)); 363 } 364 365 // IsReadOnly 366 /*! \brief Returns whether the volume is read only. 367 \return \c true, when the object is properly initialized and the 368 referred to volume is read only, \c false otherwise. 369 */ 370 bool 371 BVolume::IsReadOnly(void) const 372 { 373 // check initialization 374 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 375 // get FS stat 376 fs_info info; 377 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 378 error = errno; 379 return (error == B_OK && (info.flags & B_FS_IS_READONLY)); 380 } 381 382 // IsPersistent 383 /*! \brief Returns whether the volume is persistent. 384 \return \c true, when the object is properly initialized and the 385 referred to volume is persistent, \c false otherwise. 386 */ 387 bool 388 BVolume::IsPersistent(void) const 389 { 390 // check initialization 391 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 392 // get FS stat 393 fs_info info; 394 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 395 error = errno; 396 return (error == B_OK && (info.flags & B_FS_IS_PERSISTENT)); 397 } 398 399 // IsShared 400 /*! \brief Returns whether the volume is shared. 401 \return \c true, when the object is properly initialized and the 402 referred to volume is shared, \c false otherwise. 403 */ 404 bool 405 BVolume::IsShared(void) const 406 { 407 // check initialization 408 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 409 // get FS stat 410 fs_info info; 411 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 412 error = errno; 413 return (error == B_OK && (info.flags & B_FS_IS_SHARED)); 414 } 415 416 // KnowsMime 417 /*! \brief Returns whether the volume supports MIME types. 418 \return \c true, when the object is properly initialized and the 419 referred to volume supports MIME types, \c false otherwise. 420 */ 421 bool 422 BVolume::KnowsMime(void) const 423 { 424 // check initialization 425 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 426 // get FS stat 427 fs_info info; 428 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 429 error = errno; 430 return (error == B_OK && (info.flags & B_FS_HAS_MIME)); 431 } 432 433 // KnowsAttr 434 /*! \brief Returns whether the volume supports attributes. 435 \return \c true, when the object is properly initialized and the 436 referred to volume supports attributes, \c false otherwise. 437 */ 438 bool 439 BVolume::KnowsAttr(void) const 440 { 441 // check initialization 442 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 443 // get FS stat 444 fs_info info; 445 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 446 error = errno; 447 return (error == B_OK && (info.flags & B_FS_HAS_ATTR)); 448 } 449 450 // KnowsQuery 451 /*! \brief Returns whether the volume supports queries. 452 \return \c true, when the object is properly initialized and the 453 referred to volume supports queries, \c false otherwise. 454 */ 455 bool 456 BVolume::KnowsQuery(void) const 457 { 458 // check initialization 459 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 460 // get FS stat 461 fs_info info; 462 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 463 error = errno; 464 return (error == B_OK && (info.flags & B_FS_HAS_QUERY)); 465 } 466 467 // == 468 /*! \brief Returns whether two BVolume objects are equal. 469 470 Two volume objects are said to be equal, if they either are both 471 uninitialized, or both are initialized and refer to the same volume. 472 473 \param volume The object to be compared with. 474 \result \c true, if this object and the supplied one are equal, \c false 475 otherwise. 476 */ 477 bool 478 BVolume::operator==(const BVolume &volume) const 479 { 480 return (InitCheck() != B_OK && volume.InitCheck() != B_OK 481 || fDevice == volume.fDevice); 482 } 483 484 // != 485 /*! \brief Returns whether two BVolume objects are unequal. 486 487 Two volume objects are said to be equal, if they either are both 488 uninitialized, or both are initialized and refer to the same volume. 489 490 \param volume The object to be compared with. 491 \result \c true, if this object and the supplied one are unequal, \c false 492 otherwise. 493 */ 494 bool 495 BVolume::operator!=(const BVolume &volume) const 496 { 497 return !(*this == volume); 498 } 499 500 // = 501 /*! \brief Assigns another BVolume object to this one. 502 503 This object is made an exact clone of the supplied one. 504 505 \param volume The volume from which shall be assigned. 506 \return A reference to this object. 507 */ 508 BVolume& 509 BVolume::operator=(const BVolume &volume) 510 { 511 if (&volume != this) { 512 this->fDevice = volume.fDevice; 513 this->fCStatus = volume.fCStatus; 514 } 515 return *this; 516 } 517 518 519 // FBC 520 void BVolume::_TurnUpTheVolume1() {} 521 void BVolume::_TurnUpTheVolume2() {} 522 void BVolume::_TurnUpTheVolume3() {} 523 void BVolume::_TurnUpTheVolume4() {} 524 void BVolume::_TurnUpTheVolume5() {} 525 void BVolume::_TurnUpTheVolume6() {} 526 void BVolume::_TurnUpTheVolume7() {} 527 void BVolume::_TurnUpTheVolume8() {} 528 529 #ifdef USE_OPENBEOS_NAMESPACE 530 } 531 #endif 532