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. 28 BVolume::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. 37 BVolume::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. 46 BVolume::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. 54 BVolume::~BVolume() 55 { 56 } 57 58 59 // Returns the initialization status. 60 status_t 61 BVolume::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. 69 status_t 70 BVolume::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. 91 void 92 BVolume::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. 100 dev_t 101 BVolume::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. 109 status_t 110 BVolume::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. 130 off_t 131 BVolume::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). 144 off_t 145 BVolume::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). 158 off_t 159 BVolume::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. 175 status_t 176 BVolume::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. 192 status_t 193 BVolume::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. 245 status_t 246 BVolume::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 262 status_t 263 BVolume::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. 280 bool 281 BVolume::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. 294 bool 295 BVolume::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. 308 bool 309 BVolume::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. 322 bool 323 BVolume::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. 336 bool 337 BVolume::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. 350 bool 351 BVolume::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. 364 bool 365 BVolume::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. 379 bool 380 BVolume::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. 388 bool 389 BVolume::operator!=(const BVolume &volume) const 390 { 391 return !(*this == volume); 392 } 393 394 395 // Assigns the supplied BVolume object to this volume. 396 BVolume& 397 BVolume::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 408 void BVolume::_TurnUpTheVolume1() {} 409 void BVolume::_TurnUpTheVolume2() {} 410 void BVolume::_TurnUpTheVolume3() {} 411 void BVolume::_TurnUpTheVolume4() {} 412 void BVolume::_TurnUpTheVolume5() {} 413 void BVolume::_TurnUpTheVolume6() {} 414 void BVolume::_TurnUpTheVolume7() {} 415 void BVolume::_TurnUpTheVolume8() {} 416