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#include <errno.h> 12#include <string.h> 13 14#include <Bitmap.h> 15#include <Directory.h> 16#include <fs_info.h> 17#include <Node.h> 18#include <Path.h> 19#include <Volume.h> 20 21#include <storage_support.h> 22#include <syscalls.h> 23 24#include <fs_interface.h> 25 26 27// Creates an uninitialized BVolume object. 28BVolume::BVolume() 29 : fDevice((dev_t)-1), 30 fCStatus(B_NO_INIT) 31{ 32} 33 34 35// Creates a BVolume and initializes it to the volume specified by the 36// supplied device ID. 37BVolume::BVolume(dev_t device) 38 : fDevice((dev_t)-1), 39 fCStatus(B_NO_INIT) 40{ 41 SetTo(device); 42} 43 44 45// Creates a copy of the supplied BVolume object. 46BVolume::BVolume(const BVolume &volume) 47 : fDevice(volume.fDevice), 48 fCStatus(volume.fCStatus) 49{ 50} 51 52 53// Destroys the object and frees all associated resources. 54BVolume::~BVolume() 55{ 56} 57 58 59// Returns the initialization status. 60status_t 61BVolume::InitCheck(void) const 62{ 63 return fCStatus; 64} 65 66 67// Initializes the object to refer to the volume specified by the supplied 68// device ID. 69status_t 70BVolume::SetTo(dev_t device) 71{ 72 // uninitialize 73 Unset(); 74 // check the parameter 75 status_t error = (device >= 0 ? B_OK : B_BAD_VALUE); 76 if (error == B_OK) { 77 fs_info info; 78 if (fs_stat_dev(device, &info) != 0) 79 error = errno; 80 } 81 // set the new value 82 if (error == B_OK) 83 fDevice = device; 84 // set the init status variable 85 fCStatus = error; 86 return fCStatus; 87} 88 89 90// Brings the BVolume object to an uninitialized state. 91void 92BVolume::Unset() 93{ 94 fDevice = (dev_t)-1; 95 fCStatus = B_NO_INIT; 96} 97 98 99// Returns the device ID of the volume the object refers to. 100dev_t 101BVolume::Device() const 102{ 103 return fDevice; 104} 105 106 107// Writes the root directory of the volume referred to by this object into 108// directory. 109status_t 110BVolume::GetRootDirectory(BDirectory *directory) const 111{ 112 // check parameter and initialization 113 status_t error = (directory && InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 114 // get FS stat 115 fs_info info; 116 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 117 error = errno; 118 // init the directory 119 if (error == B_OK) { 120 node_ref ref; 121 ref.device = info.dev; 122 ref.node = info.root; 123 error = directory->SetTo(&ref); 124 } 125 return error; 126} 127 128 129// Returns the total storage capacity of the volume. 130off_t 131BVolume::Capacity() const 132{ 133 // check initialization 134 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 135 // get FS stat 136 fs_info info; 137 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 138 error = errno; 139 return (error == B_OK ? info.total_blocks * info.block_size : error); 140} 141 142 143// Returns the amount of unused space on the volume (in bytes). 144off_t 145BVolume::FreeBytes() const 146{ 147 // check initialization 148 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 149 // get FS stat 150 fs_info info; 151 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 152 error = errno; 153 return (error == B_OK ? info.free_blocks * info.block_size : error); 154} 155 156 157// Returns the size of one block (in bytes). 158off_t 159BVolume::BlockSize() const 160{ 161 // check initialization 162 if (InitCheck() != B_OK) 163 return B_NO_INIT; 164 165 // get FS stat 166 fs_info info; 167 if (fs_stat_dev(fDevice, &info) != 0) 168 return errno; 169 170 return info.block_size; 171} 172 173 174// Copies the name of the volume into the provided buffer. 175status_t 176BVolume::GetName(char *name) const 177{ 178 // check parameter and initialization 179 status_t error = (name && InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 180 // get FS stat 181 fs_info info; 182 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 183 error = errno; 184 // copy the name 185 if (error == B_OK) 186 strncpy(name, info.volume_name, B_FILE_NAME_LENGTH); 187 return error; 188} 189 190 191// Sets the name of the volume. 192status_t 193BVolume::SetName(const char *name) 194{ 195 // check initialization 196 if (!name || InitCheck() != B_OK) 197 return B_BAD_VALUE; 198 if (strlen(name) >= B_FILE_NAME_LENGTH) 199 return B_NAME_TOO_LONG; 200 // get the FS stat (including the old name) first 201 fs_info oldInfo; 202 if (fs_stat_dev(fDevice, &oldInfo) != 0) 203 return errno; 204 if (strcmp(name, oldInfo.volume_name) == 0) 205 return B_OK; 206 // set the volume name 207 fs_info newInfo; 208 strlcpy(newInfo.volume_name, name, sizeof(newInfo.volume_name)); 209 status_t error = _kern_write_fs_info(fDevice, &newInfo, 210 FS_WRITE_FSINFO_NAME); 211 if (error != B_OK) 212 return error; 213 214 // change the name of the mount point 215 216 // R5 implementation checks if an entry with the volume's old name 217 // exists in the root directory and renames that entry, if it is indeed 218 // the mount point of the volume (or a link referring to it). In all other 219 // cases, nothing is done (even if the mount point is named like the 220 // volume, but lives in a different directory). 221 // We follow suit for the time being. 222 // NOTE: If the volume name itself is actually "boot", then this code 223 // tries to rename /boot, but that is prevented in the kernel. 224 225 BPath entryPath; 226 BEntry entry; 227 BEntry traversedEntry; 228 node_ref entryNodeRef; 229 if (BPrivate::Storage::check_entry_name(name) == B_OK 230 && BPrivate::Storage::check_entry_name(oldInfo.volume_name) == B_OK 231 && entryPath.SetTo("/", oldInfo.volume_name) == B_OK 232 && entry.SetTo(entryPath.Path(), false) == B_OK 233 && entry.Exists() 234 && traversedEntry.SetTo(entryPath.Path(), true) == B_OK 235 && traversedEntry.GetNodeRef(&entryNodeRef) == B_OK 236 && entryNodeRef.device == fDevice 237 && entryNodeRef.node == oldInfo.root) { 238 entry.Rename(name, false); 239 } 240 return error; 241} 242 243 244// Writes the volume's icon into icon. 245status_t 246BVolume::GetIcon(BBitmap *icon, icon_size which) const 247{ 248 // check initialization 249 if (InitCheck() != B_OK) 250 return B_NO_INIT; 251 252 // get FS stat for the device name 253 fs_info info; 254 if (fs_stat_dev(fDevice, &info) != 0) 255 return errno; 256 257 // get the icon 258 return get_device_icon(info.device_name, icon, which); 259} 260 261 262status_t 263BVolume::GetIcon(uint8** _data, size_t* _size, type_code* _type) const 264{ 265 // check initialization 266 if (InitCheck() != B_OK) 267 return B_NO_INIT; 268 269 // get FS stat for the device name 270 fs_info info; 271 if (fs_stat_dev(fDevice, &info) != 0) 272 return errno; 273 274 // get the icon 275 return get_device_icon(info.device_name, _data, _size, _type); 276} 277 278 279// Returns whether or not the volume is removable. 280bool 281BVolume::IsRemovable() const 282{ 283 // check initialization 284 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 285 // get FS stat 286 fs_info info; 287 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 288 error = errno; 289 return (error == B_OK && (info.flags & B_FS_IS_REMOVABLE)); 290} 291 292 293// Returns whether or not the volume is read-only. 294bool 295BVolume::IsReadOnly(void) const 296{ 297 // check initialization 298 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 299 // get FS stat 300 fs_info info; 301 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 302 error = errno; 303 return (error == B_OK && (info.flags & B_FS_IS_READONLY)); 304} 305 306 307// Returns whether or not the volume is persistent. 308bool 309BVolume::IsPersistent(void) const 310{ 311 // check initialization 312 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 313 // get FS stat 314 fs_info info; 315 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 316 error = errno; 317 return (error == B_OK && (info.flags & B_FS_IS_PERSISTENT)); 318} 319 320 321// Returns whether or not the volume is shared. 322bool 323BVolume::IsShared(void) const 324{ 325 // check initialization 326 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 327 // get FS stat 328 fs_info info; 329 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 330 error = errno; 331 return (error == B_OK && (info.flags & B_FS_IS_SHARED)); 332} 333 334 335// Returns whether or not the volume supports MIME-types. 336bool 337BVolume::KnowsMime(void) const 338{ 339 // check initialization 340 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 341 // get FS stat 342 fs_info info; 343 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 344 error = errno; 345 return (error == B_OK && (info.flags & B_FS_HAS_MIME)); 346} 347 348 349// Returns whether or not the volume supports attributes. 350bool 351BVolume::KnowsAttr(void) const 352{ 353 // check initialization 354 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 355 // get FS stat 356 fs_info info; 357 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 358 error = errno; 359 return (error == B_OK && (info.flags & B_FS_HAS_ATTR)); 360} 361 362 363// Returns whether or not the volume supports queries. 364bool 365BVolume::KnowsQuery(void) const 366{ 367 // check initialization 368 status_t error = (InitCheck() == B_OK ? B_OK : B_BAD_VALUE); 369 // get FS stat 370 fs_info info; 371 if (error == B_OK && fs_stat_dev(fDevice, &info) != 0) 372 error = errno; 373 return (error == B_OK && (info.flags & B_FS_HAS_QUERY)); 374} 375 376 377// Returns whether or not the supplied BVolume object is a equal 378// to this object. 379bool 380BVolume::operator==(const BVolume &volume) const 381{ 382 return ((InitCheck() != B_OK && volume.InitCheck() != B_OK) 383 || fDevice == volume.fDevice); 384} 385 386// Returns whether or not the supplied BVolume object is NOT equal 387// to this object. 388bool 389BVolume::operator!=(const BVolume &volume) const 390{ 391 return !(*this == volume); 392} 393 394 395// Assigns the supplied BVolume object to this volume. 396BVolume& 397BVolume::operator=(const BVolume &volume) 398{ 399 if (&volume != this) { 400 this->fDevice = volume.fDevice; 401 this->fCStatus = volume.fCStatus; 402 } 403 return *this; 404} 405 406 407// FBC 408void BVolume::_TurnUpTheVolume1() {} 409void BVolume::_TurnUpTheVolume2() {} 410void BVolume::_TurnUpTheVolume3() {} 411void BVolume::_TurnUpTheVolume4() {} 412void BVolume::_TurnUpTheVolume5() {} 413void BVolume::_TurnUpTheVolume6() {} 414void BVolume::_TurnUpTheVolume7() {} 415void BVolume::_TurnUpTheVolume8() {} 416