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