1 /* 2 * Copyright 2003-2008, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold, bonefish@cs.tu-berlin.de 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 #include <new> 11 12 #include <Directory.h> 13 #include <DiskDevice.h> 14 #include <DiskDevicePrivate.h> 15 #include <DiskDeviceRoster.h> 16 #include <DiskSystem.h> 17 #include <Entry.h> 18 #include <FindDirectory.h> 19 #include <Message.h> 20 #include <Partition.h> 21 #include <Path.h> 22 #include <Volume.h> 23 24 #include <syscalls.h> 25 #include <ddm_userland_interface_defs.h> 26 27 //#include "AddOnImage.h" 28 29 /*! \class BDiskDeviceRoster 30 \brief An interface for iterating through the disk devices known to the 31 system and for a notification mechanism provided to listen to their 32 changes. 33 */ 34 35 /*! \brief find_directory constants of the add-on dirs to be searched. */ 36 static const directory_which kAddOnDirs[] = { 37 B_USER_ADDONS_DIRECTORY, 38 // B_COMMON_ADDONS_DIRECTORY, 39 B_BEOS_ADDONS_DIRECTORY 40 }; 41 /*! \brief Size of the kAddOnDirs array. */ 42 static const int32 kAddOnDirCount 43 = sizeof(kAddOnDirs) / sizeof(directory_which); 44 45 46 // constructor 47 /*! \brief Creates a BDiskDeviceRoster object. 48 49 The object is ready to be used after construction. 50 */ 51 BDiskDeviceRoster::BDiskDeviceRoster() 52 : fDeviceCookie(0), 53 fDiskSystemCookie(0), 54 fJobCookie(0) 55 // fPartitionAddOnDir(NULL), 56 // fFSAddOnDir(NULL), 57 // fPartitionAddOnDirIndex(0), 58 // fFSAddOnDirIndex(0) 59 { 60 } 61 62 // destructor 63 /*! \brief Frees all resources associated with the object. 64 */ 65 BDiskDeviceRoster::~BDiskDeviceRoster() 66 { 67 // if (fPartitionAddOnDir) 68 // delete fPartitionAddOnDir; 69 // if (fFSAddOnDir) 70 // delete fFSAddOnDir; 71 } 72 73 // GetNextDevice 74 /*! \brief Returns the next BDiskDevice. 75 \param device Pointer to a pre-allocated BDiskDevice to be initialized to 76 represent the next device. 77 \return 78 - \c B_OK: Everything went fine. 79 - \c B_ENTRY_NOT_FOUND: The end of the list of devices had already been 80 reached. 81 - another error code 82 */ 83 status_t 84 BDiskDeviceRoster::GetNextDevice(BDiskDevice *device) 85 { 86 if (!device) 87 return B_BAD_VALUE; 88 size_t neededSize = 0; 89 partition_id id = _kern_get_next_disk_device_id(&fDeviceCookie, 90 &neededSize); 91 if (id < 0) 92 return id; 93 return device->_SetTo(id, true, neededSize); 94 } 95 96 // RewindDevices 97 /*! \brief Rewinds the device list iterator. 98 \return \c B_OK, if everything went fine, another error code otherwise. 99 */ 100 status_t 101 BDiskDeviceRoster::RewindDevices() 102 { 103 fDeviceCookie = 0; 104 return B_OK; 105 } 106 107 108 status_t 109 BDiskDeviceRoster::GetNextDiskSystem(BDiskSystem* system) 110 { 111 if (!system) 112 return B_BAD_VALUE; 113 user_disk_system_info info; 114 status_t error = _kern_get_next_disk_system_info(&fDiskSystemCookie, 115 &info); 116 if (error == B_OK) 117 error = system->_SetTo(&info); 118 return error; 119 } 120 121 122 status_t 123 BDiskDeviceRoster::RewindDiskSystems() 124 { 125 fDiskSystemCookie = 0; 126 return B_OK; 127 } 128 129 130 status_t 131 BDiskDeviceRoster::GetDiskSystem(BDiskSystem* system, const char* name) 132 { 133 if (!system) 134 return B_BAD_VALUE; 135 136 int32 cookie = 0; 137 user_disk_system_info info; 138 while (_kern_get_next_disk_system_info(&cookie, &info) == B_OK) { 139 if (!strcmp(name, info.name) 140 || !strcmp(name, info.short_name) 141 || !strcmp(name, info.pretty_name)) 142 return system->_SetTo(&info); 143 } 144 145 return B_ENTRY_NOT_FOUND; 146 } 147 148 149 partition_id 150 BDiskDeviceRoster::RegisterFileDevice(const char *filename) 151 { 152 if (!filename) 153 return B_BAD_VALUE; 154 return _kern_register_file_device(filename); 155 } 156 157 // UnregisterFileDevice 158 status_t 159 BDiskDeviceRoster::UnregisterFileDevice(const char *filename) 160 { 161 if (!filename) 162 return B_BAD_VALUE; 163 return _kern_unregister_file_device(-1, filename); 164 } 165 166 // UnregisterFileDevice 167 status_t 168 BDiskDeviceRoster::UnregisterFileDevice(partition_id device) 169 { 170 if (device < 0) 171 return B_BAD_VALUE; 172 return _kern_unregister_file_device(device, NULL); 173 } 174 175 // VisitEachDevice 176 /*! \brief Iterates through the all devices. 177 178 The supplied visitor's Visit(BDiskDevice*) is invoked for each device. 179 If Visit() returns \c true, the iteration is terminated and this method 180 returns \c true. If supplied, \a device is set to the concerned device. 181 182 \param visitor The visitor. 183 \param device Pointer to a pre-allocated BDiskDevice to be initialized 184 to the device at which the iteration was terminated. 185 May be \c NULL. 186 \return \c true, if the iteration was terminated, \c false otherwise. 187 */ 188 bool 189 BDiskDeviceRoster::VisitEachDevice(BDiskDeviceVisitor *visitor, 190 BDiskDevice *device) 191 { 192 bool terminatedEarly = false; 193 if (visitor) { 194 int32 oldCookie = fDeviceCookie; 195 fDeviceCookie = 0; 196 BDiskDevice deviceOnStack; 197 BDiskDevice *useDevice = (device ? device : &deviceOnStack); 198 while (!terminatedEarly && GetNextDevice(useDevice) == B_OK) 199 terminatedEarly = visitor->Visit(useDevice); 200 fDeviceCookie = oldCookie; 201 if (!terminatedEarly) 202 useDevice->Unset(); 203 } 204 return terminatedEarly; 205 } 206 207 // VisitEachPartition 208 /*! \brief Pre-order traverses the trees spanned by the BDiskDevices and their 209 subobjects. 210 211 The supplied visitor's Visit(BDiskDevice*) method is invoked for each 212 disk device and Visit(BPartition*) for each (non-disk device) partition. 213 If Visit() returns \c true, the iteration is terminated and this method 214 returns \c true. If supplied, \a device is set to the concerned device 215 and in \a partition the pointer to the partition object is returned. 216 217 \param visitor The visitor. 218 \param device Pointer to a pre-allocated BDiskDevice to be initialized 219 to the device at which the iteration was terminated. 220 May be \c NULL. 221 \param partition Pointer to a pre-allocated BPartition pointer to be set 222 to the partition at which the iteration was terminated. 223 May be \c NULL. 224 \return \c true, if the iteration was terminated, \c false otherwise. 225 */ 226 bool 227 BDiskDeviceRoster::VisitEachPartition(BDiskDeviceVisitor *visitor, 228 BDiskDevice *device, BPartition **partition) 229 { 230 bool terminatedEarly = false; 231 if (visitor) { 232 int32 oldCookie = fDeviceCookie; 233 fDeviceCookie = 0; 234 BDiskDevice deviceOnStack; 235 BDiskDevice *useDevice = (device ? device : &deviceOnStack); 236 BPartition *foundPartition = NULL; 237 while (GetNextDevice(useDevice) == B_OK) { 238 foundPartition = useDevice->VisitEachDescendant(visitor); 239 if (foundPartition) { 240 terminatedEarly = true; 241 break; 242 } 243 } 244 fDeviceCookie = oldCookie; 245 if (!terminatedEarly) 246 useDevice->Unset(); 247 else if (device && partition) 248 *partition = foundPartition; 249 } 250 return terminatedEarly; 251 } 252 253 // VisitEachMountedPartition 254 /*! \brief Iterates through the all devices' partitions that are mounted. 255 256 The supplied visitor's Visit(BPartition*) is invoked for each mounted 257 partition. 258 If Visit() returns \c true, the iteration is terminated and this method 259 returns \c true. If supplied, \a device is set to the concerned device 260 and in \a partition the pointer to the partition object is returned. 261 262 \param visitor The visitor. 263 \param device Pointer to a pre-allocated BDiskDevice to be initialized 264 to the device at which the iteration was terminated. 265 May be \c NULL. 266 \param partition Pointer to a pre-allocated BPartition pointer to be set 267 to the partition at which the iteration was terminated. 268 May be \c NULL. 269 \return \c true, if the iteration was terminated, \c false otherwise. 270 */ 271 bool 272 BDiskDeviceRoster::VisitEachMountedPartition(BDiskDeviceVisitor *visitor, 273 BDiskDevice *device, BPartition **partition) 274 { 275 bool terminatedEarly = false; 276 if (visitor) { 277 struct MountedPartitionFilter : public PartitionFilter { 278 virtual bool Filter(BPartition *partition, int32) 279 { return partition->IsMounted(); } 280 } filter; 281 PartitionFilterVisitor filterVisitor(visitor, &filter); 282 terminatedEarly 283 = VisitEachPartition(&filterVisitor, device, partition); 284 } 285 return terminatedEarly; 286 } 287 288 // VisitEachMountablePartition 289 /*! \brief Iterates through the all devices' partitions that are mountable. 290 291 The supplied visitor's Visit(BPartition*) is invoked for each mountable 292 partition. 293 If Visit() returns \c true, the iteration is terminated and this method 294 returns \c true. If supplied, \a device is set to the concerned device 295 and in \a partition the pointer to the partition object is returned. 296 297 \param visitor The visitor. 298 \param device Pointer to a pre-allocated BDiskDevice to be initialized 299 to the device at which the iteration was terminated. 300 May be \c NULL. 301 \param partition Pointer to a pre-allocated BPartition pointer to be set 302 to the partition at which the iteration was terminated. 303 May be \c NULL. 304 \return \c true, if the iteration was terminated, \c false otherwise. 305 */ 306 bool 307 BDiskDeviceRoster::VisitEachMountablePartition(BDiskDeviceVisitor *visitor, 308 BDiskDevice *device, BPartition **partition) 309 { 310 bool terminatedEarly = false; 311 if (visitor) { 312 struct MountablePartitionFilter : public PartitionFilter { 313 virtual bool Filter(BPartition *partition, int32) 314 { return partition->ContainsFileSystem(); } 315 } filter; 316 PartitionFilterVisitor filterVisitor(visitor, &filter); 317 terminatedEarly 318 = VisitEachPartition(&filterVisitor, device, partition); 319 } 320 return terminatedEarly; 321 } 322 323 324 /*! \brief Finds a BPartition by BVolume. 325 */ 326 status_t 327 BDiskDeviceRoster::FindPartitionByVolume(BVolume* volume, BDiskDevice* device, 328 BPartition** _partition) 329 { 330 class FindPartitionVisitor : public BDiskDeviceVisitor { 331 public: 332 FindPartitionVisitor(dev_t volume) 333 : 334 fVolume(volume) 335 { 336 } 337 338 virtual bool Visit(BDiskDevice* device) 339 { 340 return Visit(device, 0); 341 } 342 343 virtual bool Visit(BPartition* partition, int32 level) 344 { 345 BVolume volume; 346 return partition->GetVolume(&volume) == B_OK 347 && volume.Device() == fVolume; 348 } 349 350 private: 351 dev_t fVolume; 352 } visitor(volume->Device()); 353 354 if (VisitEachMountedPartition(&visitor, device, _partition)) 355 return B_OK; 356 357 return B_ENTRY_NOT_FOUND; 358 } 359 360 361 /*! \brief Finds a BPartition by mount path. 362 */ 363 status_t 364 BDiskDeviceRoster::FindPartitionByMountPoint(const char* mountPoint, 365 BDiskDevice* device, BPartition** _partition) 366 { 367 BVolume volume(dev_for_path(mountPoint)); 368 if (volume.InitCheck() == B_OK 369 && FindPartitionByVolume(&volume, device, _partition)) 370 return B_OK; 371 372 return B_ENTRY_NOT_FOUND; 373 } 374 375 376 /*! \brief Returns a BDiskDevice for a given ID. 377 378 The supplied \a device is initialized to the device identified by \a id. 379 380 \param id The ID of the device to be retrieved. 381 \param device Pointer to a pre-allocated BDiskDevice to be initialized 382 to the device identified by \a id. 383 \return 384 - \c B_OK: Everything went fine. 385 - \c B_ENTRY_NOT_FOUND: A device with ID \a id could not be found. 386 - other error codes 387 */ 388 status_t 389 BDiskDeviceRoster::GetDeviceWithID(int32 id, BDiskDevice *device) const 390 { 391 if (!device) 392 return B_BAD_VALUE; 393 return device->_SetTo(id, true, 0); 394 } 395 396 // GetPartitionWithID 397 /*! \brief Returns a BPartition for a given ID. 398 399 The supplied \a device is initialized to the device the partition 400 identified by \a id resides on, and \a partition is set to point to the 401 respective BPartition. 402 403 \param id The ID of the partition to be retrieved. 404 \param device Pointer to a pre-allocated BDiskDevice to be initialized 405 to the device the partition identified by \a id resides on. 406 \param partition Pointer to a pre-allocated BPartition pointer to be set 407 to the partition identified by \a id. 408 \return 409 - \c B_OK: Everything went fine. 410 - \c B_ENTRY_NOT_FOUND: A partition with ID \a id could not be found. 411 - other error codes 412 */ 413 status_t 414 BDiskDeviceRoster::GetPartitionWithID(int32 id, BDiskDevice *device, 415 BPartition **partition) const 416 { 417 if (!device || !partition) 418 return B_BAD_VALUE; 419 // download the device data 420 status_t error = device->_SetTo(id, false, 0); 421 if (error != B_OK) 422 return error; 423 // find the partition object 424 *partition = device->FindDescendant(id); 425 if (!*partition) // should never happen! 426 return B_ENTRY_NOT_FOUND; 427 return B_OK; 428 } 429 430 431 status_t 432 BDiskDeviceRoster::GetDeviceForPath(const char *filename, BDiskDevice *device) 433 { 434 if (!filename || !device) 435 return B_BAD_VALUE; 436 // get the device ID 437 size_t neededSize = 0; 438 partition_id id = _kern_find_disk_device(filename, &neededSize); 439 if (id < 0) 440 return id; 441 // download the device data 442 return device->_SetTo(id, true, neededSize); 443 } 444 445 446 status_t 447 BDiskDeviceRoster::GetPartitionForPath(const char *filename, 448 BDiskDevice *device, BPartition **partition) 449 { 450 if (!filename || !device || !partition) 451 return B_BAD_VALUE; 452 // get the partition ID 453 size_t neededSize = 0; 454 partition_id id = _kern_find_partition(filename, &neededSize); 455 if (id < 0) 456 return id; 457 // download the device data 458 status_t error = device->_SetTo(id, false, neededSize); 459 if (error != B_OK) 460 return error; 461 // find the partition object 462 *partition = device->FindDescendant(id); 463 if (!*partition) // should never happen! 464 return B_ENTRY_NOT_FOUND; 465 return B_OK; 466 } 467 468 469 status_t 470 BDiskDeviceRoster::GetFileDeviceForPath(const char *filename, 471 BDiskDevice *device) 472 { 473 if (!filename || !device) 474 return B_BAD_VALUE; 475 476 // get the device ID 477 size_t neededSize = 0; 478 partition_id id = _kern_find_file_disk_device(filename, &neededSize); 479 if (id < 0) 480 return id; 481 482 // download the device data 483 return device->_SetTo(id, true, neededSize); 484 } 485 486 487 // StartWatching 488 /*! \brief Adds a target to the list of targets to be notified on disk device 489 events. 490 491 \todo List the event mask flags, the events and describe the layout of the 492 notification message. 493 494 If \a target is already listening to events, this method replaces the 495 former event mask with \a eventMask. 496 497 \param target A BMessenger identifying the target to which the events 498 shall be sent. 499 \param eventMask A mask specifying on which events the target shall be 500 notified. 501 \return \c B_OK, if everything went fine, another error code otherwise. 502 */ 503 status_t 504 BDiskDeviceRoster::StartWatching(BMessenger target, uint32 eventMask) 505 { 506 /* status_t error = B_OK; 507 // compose request message 508 BMessage request(B_REG_DEVICE_START_WATCHING); 509 if (error == B_OK) 510 error = request.AddMessenger("target", target); 511 if (error == B_OK) 512 error = request.AddInt32("events", (int32)eventMask); 513 // send request 514 BMessage reply; 515 if (error == B_OK) 516 error = fManager.SendMessage(&request, &reply); 517 // analyze reply 518 if (error == B_OK) { 519 // result 520 status_t result = B_OK; 521 error = reply.FindInt32("result", &result); 522 if (error == B_OK) 523 error = result; 524 } 525 return error; 526 */ 527 // not implemented 528 return B_ERROR; 529 } 530 531 532 // StopWatching 533 /*! \brief Remove a target from the list of targets to be notified on disk 534 device events. 535 \param target A BMessenger identifying the target to which notfication 536 message shall not longer be sent. 537 \return \c B_OK, if everything went fine, another error code otherwise. 538 */ 539 status_t 540 BDiskDeviceRoster::StopWatching(BMessenger target) 541 { 542 /* status_t error = B_OK; 543 // compose request message 544 BMessage request(B_REG_DEVICE_STOP_WATCHING); 545 if (error == B_OK) 546 error = request.AddMessenger("target", target); 547 // send request 548 BMessage reply; 549 if (error == B_OK) 550 error = fManager.SendMessage(&request, &reply); 551 // analyze reply 552 if (error == B_OK) { 553 // result 554 status_t result = B_OK; 555 error = reply.FindInt32("result", &result); 556 if (error == B_OK) 557 error = result; 558 } 559 return error; 560 */ 561 // not implemented 562 return B_ERROR; 563 } 564 565 566 #if 0 567 568 // GetNextPartitioningSystem 569 /*! \brief Returns the next partitioning system capable of partitioning. 570 571 The returned \a shortName can be passed to BSession::Partition(). 572 573 \param shortName Pointer to a pre-allocation char buffer, of size 574 \c B_FILE_NAME_LENGTH or larger into which the short name of the 575 partitioning system shall be written. 576 \param longName Pointer to a pre-allocation char buffer, of size 577 \c B_FILE_NAME_LENGTH or larger into which the long name of the 578 partitioning system shall be written. May be \c NULL. 579 \return 580 - \c B_OK: Everything went fine. 581 - \c B_BAD_VALUE: \c NULL \a shortName. 582 - \c B_ENTRY_NOT_FOUND: End of the list has been reached. 583 - other error codes 584 */ 585 status_t 586 BDiskDeviceRoster::GetNextPartitioningSystem(char *shortName, char *longName) 587 { 588 status_t error = (shortName ? B_OK : B_BAD_VALUE); 589 if (error == B_OK) { 590 // search until an add-on has been found or the end of all directories 591 // has been reached 592 bool found = false; 593 do { 594 // get the next add-on in the current dir 595 AddOnImage image; 596 error = _GetNextAddOn(fPartitionAddOnDir, &image); 597 if (error == B_OK) { 598 // add-on loaded: get the function that creates an add-on 599 // object 600 BDiskScannerPartitionAddOn *(*create_add_on)(); 601 if (get_image_symbol(image.ID(), "create_ds_partition_add_on", 602 B_SYMBOL_TYPE_TEXT, 603 (void**)&create_add_on) == B_OK) { 604 // create the add-on object and copy the requested data 605 if (BDiskScannerPartitionAddOn *addOn 606 = (*create_add_on)()) { 607 const char *addOnShortName = addOn->ShortName(); 608 const char *addOnLongName = addOn->LongName(); 609 if (addOnShortName && addOnLongName) { 610 strcpy(shortName, addOnShortName); 611 if (longName) 612 strcpy(longName, addOnLongName); 613 found = true; 614 } 615 delete addOn; 616 } 617 } 618 } else if (error == B_ENTRY_NOT_FOUND) { 619 // end of the current directory has been reached, try next dir 620 error = _GetNextAddOnDir(&fPartitionAddOnDir, 621 &fPartitionAddOnDirIndex, 622 "partition"); 623 } 624 } while (error == B_OK && !found); 625 } 626 return error; 627 } 628 629 // GetNextFileSystem 630 /*! \brief Returns the next file system capable of initializing. 631 632 The returned \a shortName can be passed to BPartition::Initialize(). 633 634 \param shortName Pointer to a pre-allocation char buffer, of size 635 \c B_FILE_NAME_LENGTH or larger into which the short name of the 636 file system shall be written. 637 \param longName Pointer to a pre-allocation char buffer, of size 638 \c B_FILE_NAME_LENGTH or larger into which the long name of the 639 file system shall be written. May be \c NULL. 640 \return 641 - \c B_OK: Everything went fine. 642 - \c B_BAD_VALUE: \c NULL \a shortName. 643 - \c B_ENTRY_NOT_FOUND: End of the list has been reached. 644 - other error codes 645 */ 646 status_t 647 BDiskDeviceRoster::GetNextFileSystem(char *shortName, char *longName) 648 { 649 status_t error = (shortName ? B_OK : B_BAD_VALUE); 650 if (error == B_OK) { 651 // search until an add-on has been found or the end of all directories 652 // has been reached 653 bool found = false; 654 do { 655 // get the next add-on in the current dir 656 AddOnImage image; 657 error = _GetNextAddOn(fFSAddOnDir, &image); 658 if (error == B_OK) { 659 // add-on loaded: get the function that creates an add-on 660 // object 661 BDiskScannerFSAddOn *(*create_add_on)(); 662 if (get_image_symbol(image.ID(), "create_ds_fs_add_on", 663 B_SYMBOL_TYPE_TEXT, 664 (void**)&create_add_on) == B_OK) { 665 // create the add-on object and copy the requested data 666 if (BDiskScannerFSAddOn *addOn = (*create_add_on)()) { 667 const char *addOnShortName = addOn->ShortName(); 668 const char *addOnLongName = addOn->LongName(); 669 if (addOnShortName && addOnLongName) { 670 strcpy(shortName, addOnShortName); 671 if (longName) 672 strcpy(longName, addOnLongName); 673 found = true; 674 } 675 delete addOn; 676 } 677 } 678 } else if (error == B_ENTRY_NOT_FOUND) { 679 // end of the current directory has been reached, try next dir 680 error = _GetNextAddOnDir(&fFSAddOnDir, &fFSAddOnDirIndex, 681 "fs"); 682 } 683 } while (error == B_OK && !found); 684 } 685 return error; 686 } 687 688 // RewindPartitiningSystems 689 /*! \brief Rewinds the partitioning system list iterator. 690 \return \c B_OK, if everything went fine, another error code otherwise. 691 */ 692 status_t 693 BDiskDeviceRoster::RewindPartitiningSystems() 694 { 695 if (fPartitionAddOnDir) { 696 delete fPartitionAddOnDir; 697 fPartitionAddOnDir = NULL; 698 } 699 fPartitionAddOnDirIndex = 0; 700 return B_OK; 701 } 702 703 // RewindFileSystems 704 /*! \brief Rewinds the file system list iterator. 705 \return \c B_OK, if everything went fine, another error code otherwise. 706 */ 707 status_t 708 BDiskDeviceRoster::RewindFileSystems() 709 { 710 if (fFSAddOnDir) { 711 delete fFSAddOnDir; 712 fFSAddOnDir = NULL; 713 } 714 fFSAddOnDirIndex = 0; 715 return B_OK; 716 } 717 718 // _GetObjectWithID 719 /*! \brief Returns a BDiskDevice for a given device, session or partition ID. 720 721 The supplied \a device is initialized to the device the object identified 722 by \a id belongs to. 723 724 \param fieldName "device_id", "sesison_id" or "partition_id" according to 725 the type of object the device shall be retrieved for. 726 \param id The ID of the device, session or partition to be retrieved. 727 \param device Pointer to a pre-allocated BDiskDevice to be initialized 728 to the device to be retrieved. 729 \return 730 - \c B_OK: Everything went fine. 731 - \c B_ENTRY_NOT_FOUND: A device, session or partition respectively with 732 ID \a id could not be found. 733 - other error codes 734 */ 735 status_t 736 BDiskDeviceRoster::_GetObjectWithID(const char *fieldName, int32 id, 737 BDiskDevice *device) const 738 { 739 status_t error = (device ? B_OK : B_BAD_VALUE); 740 // compose request message 741 BMessage request(B_REG_GET_DISK_DEVICE); 742 if (error == B_OK) 743 error = request.AddInt32(fieldName, id); 744 // send request 745 BMessage reply; 746 if (error == B_OK) 747 error = fManager.SendMessage(&request, &reply); 748 // analyze reply 749 if (error == B_OK) { 750 // result 751 status_t result = B_OK; 752 error = reply.FindInt32("result", &result); 753 if (error == B_OK) 754 error = result; 755 // device 756 BMessage archive; 757 if (error == B_OK) 758 error = reply.FindMessage("device", &archive); 759 if (error == B_OK) 760 error = device->_Unarchive(&archive); 761 } 762 return error; 763 } 764 765 766 // _GetNextAddOn 767 /*! \brief Finds and loads the next add-on of an add-on subdirectory. 768 \param directory The add-on directory. 769 \param image Pointer to an image_id into which the image ID of the loaded 770 add-on shall be written. 771 \return 772 - \c B_OK: Everything went fine. 773 - \c B_ENTRY_NOT_FOUND: End of directory. 774 - other error codes 775 */ 776 status_t 777 BDiskDeviceRoster::_GetNextAddOn(BDirectory **directory, int32 *index, 778 const char *subdir, AddOnImage *image) 779 { 780 status_t error = (directory && index && subdir && image 781 ? B_OK : B_BAD_VALUE); 782 if (error == B_OK) { 783 // search until an add-on has been found or the end of all directories 784 // has been reached 785 bool found = false; 786 do { 787 // get the next add-on in the current dir 788 error = _GetNextAddOn(*directory, image); 789 if (error == B_OK) { 790 found = true; 791 } else if (error == B_ENTRY_NOT_FOUND) { 792 // end of the current directory has been reached, try next dir 793 error = _GetNextAddOnDir(directory, index, subdir); 794 } 795 } while (error == B_OK && !found); 796 } 797 return error; 798 } 799 800 // _GetNextAddOn 801 /*! \brief Finds and loads the next add-on of an add-on subdirectory. 802 \param directory The add-on directory. 803 \param image Pointer to an image_id into which the image ID of the loaded 804 add-on shall be written. 805 \return 806 - \c B_OK: Everything went fine. 807 - \c B_ENTRY_NOT_FOUND: End of directory. 808 - other error codes 809 */ 810 status_t 811 BDiskDeviceRoster::_GetNextAddOn(BDirectory *directory, AddOnImage *image) 812 { 813 status_t error = (directory ? B_OK : B_ENTRY_NOT_FOUND); 814 if (error == B_OK) { 815 // iterate through the entry list and try to load the entries 816 bool found = false; 817 while (error == B_OK && !found) { 818 BEntry entry; 819 error = directory->GetNextEntry(&entry); 820 BPath path; 821 if (error == B_OK && entry.GetPath(&path) == B_OK) 822 found = (image->Load(path.Path()) == B_OK); 823 } 824 } 825 return error; 826 } 827 828 // _GetNextAddOnDir 829 /*! \brief Gets the next add-on directory path. 830 \param path Pointer to a BPath to be set to the found directory. 831 \param index Pointer to an index into the kAddOnDirs array indicating 832 which add-on dir shall be retrieved next. 833 \param subdir Name of the subdirectory (in the "disk_scanner" subdirectory 834 of the add-on directory) \a directory shall be set to. 835 \return 836 - \c B_OK: Everything went fine. 837 - \c B_ENTRY_NOT_FOUND: End of directory list. 838 - other error codes 839 */ 840 status_t 841 BDiskDeviceRoster::_GetNextAddOnDir(BPath *path, int32 *index, 842 const char *subdir) 843 { 844 status_t error = (*index < kAddOnDirCount ? B_OK : B_ENTRY_NOT_FOUND); 845 // get the add-on dir path 846 if (error == B_OK) { 847 error = find_directory(kAddOnDirs[*index], path); 848 (*index)++; 849 } 850 // construct the subdirectory path 851 if (error == B_OK) { 852 error = path->Append("disk_scanner"); 853 if (error == B_OK) 854 error = path->Append(subdir); 855 } 856 if (error == B_OK) 857 printf(" next add-on dir: `%s'\n", path->Path()); 858 return error; 859 } 860 861 // _GetNextAddOnDir 862 /*! \brief Gets the next add-on directory. 863 \param directory Pointer to a BDirectory* to be set to the found directory. 864 \param index Pointer to an index into the kAddOnDirs array indicating 865 which add-on dir shall be retrieved next. 866 \param subdir Name of the subdirectory (in the "disk_scanner" subdirectory 867 of the add-on directory) \a directory shall be set to. 868 \return 869 - \c B_OK: Everything went fine. 870 - \c B_ENTRY_NOT_FOUND: End of directory list. 871 - other error codes 872 */ 873 status_t 874 BDiskDeviceRoster::_GetNextAddOnDir(BDirectory **directory, int32 *index, 875 const char *subdir) 876 { 877 BPath path; 878 status_t error = _GetNextAddOnDir(&path, index, subdir); 879 // create a BDirectory object, if there is none yet. 880 if (error == B_OK && !*directory) { 881 *directory = new BDirectory; 882 if (!*directory) 883 error = B_NO_MEMORY; 884 } 885 // init the directory 886 if (error == B_OK) 887 error = (*directory)->SetTo(path.Path()); 888 // cleanup on error 889 if (error != B_OK && *directory) { 890 delete *directory; 891 *directory = NULL; 892 } 893 return error; 894 } 895 896 // _LoadPartitionAddOn 897 status_t 898 BDiskDeviceRoster::_LoadPartitionAddOn(const char *partitioningSystem, 899 AddOnImage *image, 900 BDiskScannerPartitionAddOn **_addOn) 901 { 902 status_t error = (partitioningSystem && image && _addOn 903 ? B_OK : B_BAD_VALUE); 904 // load the image 905 bool found = false; 906 BPath path; 907 BDirectory *directory = NULL; 908 int32 index = 0; 909 while (error == B_OK && !found) { 910 error = _GetNextAddOn(&directory, &index, "partition", image); 911 if (error == B_OK) { 912 // add-on loaded: get the function that creates an add-on 913 // object 914 BDiskScannerPartitionAddOn *(*create_add_on)(); 915 if (get_image_symbol(image->ID(), "create_ds_partition_add_on", 916 B_SYMBOL_TYPE_TEXT, 917 (void**)&create_add_on) == B_OK) { 918 // create the add-on object and copy the requested data 919 if (BDiskScannerPartitionAddOn *addOn = (*create_add_on)()) { 920 if (!strcmp(addOn->ShortName(), partitioningSystem)) { 921 *_addOn = addOn; 922 found = true; 923 } else 924 delete addOn; 925 } 926 } 927 } 928 } 929 // cleanup 930 if (directory) 931 delete directory; 932 if (error != B_OK && image) 933 image->Unload(); 934 return error; 935 } 936 937 #endif // 0 938