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