1 /* 2 * Copyright 2003-2007, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <errno.h> 7 #include <new> 8 #include <unistd.h> 9 #include <sys/stat.h> 10 11 #include <Directory.h> 12 #include <DiskDevice.h> 13 #include <DiskDevicePrivate.h> 14 #include <DiskDeviceVisitor.h> 15 #include <DiskSystem.h> 16 #include <fs_volume.h> 17 #include <Message.h> 18 #include <Partition.h> 19 #include <PartitioningInfo.h> 20 #include <Path.h> 21 #include <String.h> 22 #include <Volume.h> 23 24 #include <AutoDeleter.h> 25 26 #include <disk_device_manager/ddm_userland_interface.h> 27 #include <syscalls.h> 28 29 #include "PartitionDelegate.h" 30 31 32 using std::nothrow; 33 34 35 /*! \class BPartition 36 \brief A BPartition object represent a partition and provides a lot of 37 methods to retrieve information about it and some to manipulate it. 38 39 Not all BPartitions represent actual on-disk partitions. Some exist only 40 to make all devices fit smoothly into the framework (e.g. for floppies, 41 \see IsVirtual()), others represents merely partition slots 42 (\see IsEmpty()). 43 */ 44 45 46 // compare_string 47 /*! \brief \c NULL aware strcmp(). 48 49 \c NULL is considered the least of all strings. \c NULL equals \c NULL. 50 51 \param str1 First string. 52 \param str2 Second string. 53 \return A value less than 0, if \a str1 is less than \a str2, 54 0, if they are equal, or a value greater than 0, if 55 \a str1 is greater \a str2. 56 */ 57 static inline int 58 compare_string(const char* str1, const char* str2) 59 { 60 if (str1 == NULL) { 61 if (str2 == NULL) 62 return 0; 63 return 1; 64 } else if (str2 == NULL) 65 return -1; 66 return strcmp(str1, str2); 67 } 68 69 70 // constructor 71 BPartition::BPartition() 72 : fDevice(NULL), 73 fParent(NULL), 74 fPartitionData(NULL), 75 fDelegate(NULL) 76 { 77 } 78 79 80 // destructor 81 /*! \brief Frees all resources associated with this object. 82 */ 83 BPartition::~BPartition() 84 { 85 _Unset(); 86 } 87 88 89 // Offset 90 /*! \brief Returns the partition's offset relative to the beginning of the 91 device it resides on. 92 \return The partition's offset in bytes relative to the beginning of the 93 device it resides on. 94 */ 95 off_t 96 BPartition::Offset() const 97 { 98 return _PartitionData()->offset; 99 } 100 101 102 // Size 103 /*! \brief Returns the size of the partition. 104 \return The size of the partition in bytes. 105 */ 106 off_t 107 BPartition::Size() const 108 { 109 return _PartitionData()->size; 110 } 111 112 113 // ContentSize 114 off_t 115 BPartition::ContentSize() const 116 { 117 return _PartitionData()->content_size; 118 } 119 120 // BlockSize 121 /*! \brief Returns the block size of the device. 122 \return The block size of the device in bytes. 123 */ 124 uint32 125 BPartition::BlockSize() const 126 { 127 return _PartitionData()->block_size; 128 } 129 130 131 // Index 132 /*! \brief Returns the index of the partition in its session's list of 133 partitions. 134 \return The index of the partition in its session's list of partitions. 135 */ 136 int32 137 BPartition::Index() const 138 { 139 return _PartitionData()->index; 140 } 141 142 143 // Status 144 uint32 145 BPartition::Status() const 146 { 147 return _PartitionData()->status; 148 } 149 150 151 // ContainsFileSystem 152 bool 153 BPartition::ContainsFileSystem() const 154 { 155 return _PartitionData()->flags & B_PARTITION_FILE_SYSTEM; 156 } 157 158 159 // ContainsPartitioningSystem 160 bool 161 BPartition::ContainsPartitioningSystem() const 162 { 163 return _PartitionData()->flags & B_PARTITION_PARTITIONING_SYSTEM; 164 } 165 166 167 // IsDevice 168 bool 169 BPartition::IsDevice() const 170 { 171 return _PartitionData()->flags & B_PARTITION_IS_DEVICE; 172 } 173 174 175 // IsReadOnly 176 bool 177 BPartition::IsReadOnly() const 178 { 179 return _PartitionData()->flags & B_PARTITION_READ_ONLY; 180 } 181 182 183 // IsMounted 184 /*! \brief Returns whether the volume is mounted. 185 \return \c true, if the volume is mounted, \c false otherwise. 186 */ 187 bool 188 BPartition::IsMounted() const 189 { 190 return _PartitionData()->flags & B_PARTITION_MOUNTED; 191 // alternatively: 192 // return _PartitionData()->volume >= 0; 193 } 194 195 196 // IsBusy 197 bool 198 BPartition::IsBusy() const 199 { 200 return _PartitionData()->flags 201 & (B_PARTITION_BUSY | B_PARTITION_DESCENDANT_BUSY); 202 } 203 204 205 // Flags 206 /*! \brief Returns the flags for this partitions. 207 208 The partition flags are a bitwise combination of: 209 - \c B_HIDDEN_PARTITION: The partition can not contain a file system. 210 - \c B_VIRTUAL_PARTITION: There exists no on-disk partition this object 211 represents. E.g. for floppies there will be a BPartition object spanning 212 the whole floppy disk. 213 - \c B_EMPTY_PARTITION: The partition represents no physical partition, 214 but merely an empty slot. This mainly used to keep the indexing of 215 partitions more persistent. This flag implies also \c B_HIDDEN_PARTITION. 216 217 \return The flags for this partition. 218 */ 219 uint32 220 BPartition::Flags() const 221 { 222 return _PartitionData()->flags; 223 } 224 225 226 // Name 227 /*! \brief Returns the name of the partition. 228 229 Note, that not all partitioning system support names. The method returns 230 \c NULL, if the partition doesn't have a name. 231 232 \return The name of the partition, or \c NULL, if the partitioning system 233 does not support names. 234 */ 235 const char* 236 BPartition::Name() const 237 { 238 return _PartitionData()->name; 239 } 240 241 242 // ContentName 243 const char* 244 BPartition::ContentName() const 245 { 246 return _PartitionData()->content_name; 247 } 248 249 250 // Type 251 /*! \brief Returns a human readable string for the type of the partition. 252 \return A human readable string for the type of the partition. 253 */ 254 const char* 255 BPartition::Type() const 256 { 257 return _PartitionData()->type; 258 } 259 260 261 // ContentType 262 const char* 263 BPartition::ContentType() const 264 { 265 return _PartitionData()->content_type; 266 } 267 268 269 // ID 270 /*! \brief Returns a unique identifier for this partition. 271 272 The ID is not persistent, i.e. in general won't be the same after 273 rebooting. 274 275 \see BDiskDeviceRoster::GetPartitionWithID(). 276 277 \return A unique identifier for this partition. 278 */ 279 int32 280 BPartition::ID() const 281 { 282 return _PartitionData()->id; 283 } 284 285 286 // Parameters 287 const char* 288 BPartition::Parameters() const 289 { 290 return _PartitionData()->parameters; 291 } 292 293 294 // ContentParameters 295 const char* 296 BPartition::ContentParameters() const 297 { 298 return _PartitionData()->content_parameters; 299 } 300 301 302 // GetDiskSystem 303 status_t 304 BPartition::GetDiskSystem(BDiskSystem* diskSystem) const 305 { 306 const user_partition_data* data = _PartitionData(); 307 if (!data || !diskSystem) 308 return B_BAD_VALUE; 309 310 if (data->disk_system < 0) 311 return B_ENTRY_NOT_FOUND; 312 313 return diskSystem->_SetTo(data->disk_system); 314 } 315 316 317 // GetPath 318 status_t 319 BPartition::GetPath(BPath* path) const 320 { 321 // The path is constructed on the fly using our parent 322 if (path == NULL || Parent() == NULL || Index() < 0) 323 return B_BAD_VALUE; 324 325 // get the parent's path 326 status_t error = Parent()->GetPath(path); 327 if (error != B_OK) 328 return error; 329 330 char indexBuffer[24]; 331 332 if (Parent()->IsDevice()) { 333 // Our parent is a device, so we replace `raw' by our index. 334 const char* leaf = path->Leaf(); 335 if (!leaf || strcmp(leaf, "raw") != B_OK) 336 return B_ERROR; 337 338 snprintf(indexBuffer, sizeof(indexBuffer), "%ld", Index()); 339 } else { 340 // Our parent is a normal partition, no device: Append our index. 341 snprintf(indexBuffer, sizeof(indexBuffer), "%s_%ld", path->Leaf(), Index()); 342 } 343 344 error = path->GetParent(path); 345 if (error == B_OK) 346 error = path->Append(indexBuffer); 347 348 return error; 349 } 350 351 352 // GetVolume 353 /*! \brief Returns a BVolume for the partition. 354 355 The can succeed only, if the partition is mounted. 356 357 \param volume Pointer to a pre-allocated BVolume, to be initialized to 358 represent the volume. 359 \return \c B_OK, if the volume is mounted and the parameter could be set 360 accordingly, another error code otherwise. 361 */ 362 status_t 363 BPartition::GetVolume(BVolume* volume) const 364 { 365 if (volume) 366 return B_BAD_VALUE; 367 368 return volume->SetTo(_PartitionData()->volume); 369 } 370 371 372 // GetIcon 373 /*! \brief Returns an icon for this partition. 374 375 Note, that currently there are only per-device icons, i.e. the method 376 returns the same icon for each partition of a device. But this may change 377 in the future. 378 379 \param icon Pointer to a pre-allocated BBitmap to be set to the icon of 380 the partition. 381 \param which Size of the icon to be retrieved. Can be \c B_MINI_ICON or 382 \c B_LARGE_ICON. 383 \return \c B_OK, if everything went fine, another error code otherwise. 384 */ 385 status_t 386 BPartition::GetIcon(BBitmap* icon, icon_size which) const 387 { 388 /* 389 status_t error = (icon ? B_OK : B_BAD_VALUE); 390 if (error == B_OK) { 391 if (IsMounted()) { 392 // mounted: get the icon from the volume 393 BVolume volume; 394 error = GetVolume(&volume); 395 if (error == B_OK) 396 error = volume.GetIcon(icon, which); 397 } else { 398 // not mounted: retrieve the icon ourselves 399 if (BDiskDevice* device = Device()) { 400 // get the icon 401 if (error == B_OK) 402 error = get_device_icon(device->Path(), icon, which); 403 } else 404 error = B_ERROR; 405 } 406 } 407 return error; 408 */ 409 // not implemented 410 return B_ERROR; 411 } 412 413 414 // GetMountPoint 415 /*! \brief Returns the mount point for the partition. 416 417 If the partition is mounted this is the actual mount point. If it is not 418 mounted, but contains a file system, derived from the partition name 419 the name for a not yet existing directory in the root directory is 420 constructed and the path to it returned. 421 422 For partitions not containing a file system the method returns an error. 423 424 \param mountPoint Pointer to the path to be set to refer the mount point 425 (respectively potential mount point) of the partition. 426 \return \c B_OK, if everything went fine, an error code otherwise. 427 */ 428 status_t 429 BPartition::GetMountPoint(BPath* mountPoint) const 430 { 431 if (!mountPoint || !ContainsFileSystem()) 432 return B_BAD_VALUE; 433 434 // if the partition is mounted, return the actual mount point 435 BVolume volume; 436 if (GetVolume(&volume) == B_OK) { 437 BDirectory dir; 438 status_t error = volume.GetRootDirectory(&dir); 439 if (error == B_OK) 440 error = mountPoint->SetTo(&dir, NULL); 441 return error; 442 } 443 444 // partition not mounted 445 // get the volume name 446 const char* volumeName = ContentName(); 447 if (!volumeName || strlen(volumeName) == 0) 448 volumeName = Name(); 449 if (!volumeName || strlen(volumeName) == 0) 450 volumeName = "unnamed volume"; 451 452 // construct a path name from the volume name 453 // replace '/'s and prepend a '/' 454 BString mountPointPath(volumeName); 455 mountPointPath.ReplaceAll('/', '-'); 456 mountPointPath.Insert("/", 0); 457 458 // make the name unique 459 BString basePath(mountPointPath); 460 int counter = 1; 461 while (true) { 462 BEntry entry; 463 status_t error = entry.SetTo(mountPointPath.String()); 464 if (error != B_OK) 465 return error; 466 467 if (!entry.Exists()) 468 break; 469 mountPointPath = basePath; 470 mountPointPath << counter; 471 counter++; 472 } 473 474 return mountPoint->SetTo(mountPointPath.String()); 475 } 476 477 478 // Mount 479 /*! \brief Mounts the volume. 480 481 The volume can only be mounted, if the partition contains a recognized 482 file system (\see ContainsFileSystem()) and it is not already mounted. 483 484 If no mount point is given, one will be created automatically under the 485 root directory (derived from the volume name). If one is given, the 486 directory must already exist. 487 488 \param mountPoint The directory where to mount the file system. May be 489 \c NULL, in which case a mount point in the root directory will be 490 created automatically. 491 \param mountFlags Currently only \c B_MOUNT_READ_ONLY is defined, which 492 forces the volume to be mounted read-only. 493 \param parameters File system specific mount parameters. 494 \return \c B_OK, if everything went fine, another error code otherwise. 495 */ 496 dev_t 497 BPartition::Mount(const char* mountPoint, uint32 mountFlags, 498 const char* parameters) 499 { 500 if (IsMounted() || !ContainsFileSystem()) 501 return B_BAD_VALUE; 502 503 // get the partition path 504 BPath partitionPath; 505 status_t error = GetPath(&partitionPath); 506 if (error != B_OK) 507 return error; 508 509 // create a mount point, if none is given 510 bool deleteMountPoint = false; 511 BPath mountPointPath; 512 if (!mountPoint) { 513 // get a unique mount point 514 error = GetMountPoint(&mountPointPath); 515 if (error != B_OK) 516 return error; 517 518 mountPoint = mountPointPath.Path(); 519 520 // create the directory 521 if (mkdir(mountPoint, S_IRWXU | S_IRWXG | S_IRWXO) < 0) 522 return errno; 523 524 deleteMountPoint = true; 525 } 526 527 // mount the partition 528 dev_t device = fs_mount_volume(mountPoint, partitionPath.Path(), NULL, 529 mountFlags, parameters); 530 531 // delete the mount point on error, if we created it 532 if (device < B_OK && deleteMountPoint) 533 rmdir(mountPoint); 534 535 // update object, if successful 536 if (device >= 0) 537 error = Device()->Update(); 538 539 return device; 540 } 541 542 543 // Unmount 544 /*! \brief Unmounts the volume. 545 546 The volume can of course only be unmounted, if it currently is mounted. 547 548 \param unmountFlags Currently only \c B_FORCE_UNMOUNT is defined, which 549 forces the partition to be unmounted, even if there are still 550 open FDs. Be careful using this flag -- you risk the user's data. 551 552 \return \c B_OK, if everything went fine, another error code otherwise. 553 */ 554 status_t 555 BPartition::Unmount(uint32 unmountFlags) 556 { 557 if (!IsMounted()) 558 return B_BAD_VALUE; 559 560 // get the partition path 561 BPath path; 562 status_t status = GetMountPoint(&path); 563 if (status != B_OK) 564 return status; 565 566 // unmount 567 status = fs_unmount_volume(path.Path(), unmountFlags); 568 569 // update object, if successful 570 if (status == B_OK) 571 status = Device()->Update(); 572 573 return status; 574 } 575 576 577 // Device 578 /*! \brief Returns the device this partition resides on. 579 \return The device this partition resides on. 580 */ 581 BDiskDevice* 582 BPartition::Device() const 583 { 584 return fDevice; 585 } 586 587 588 // Parent 589 BPartition* 590 BPartition::Parent() const 591 { 592 return fParent; 593 } 594 595 596 // ChildAt 597 BPartition* 598 BPartition::ChildAt(int32 index) const 599 { 600 if (fDelegate) { 601 Delegate* child = fDelegate->ChildAt(index); 602 return child ? child->Partition() : NULL; 603 } 604 605 return _ChildAt(index); 606 } 607 608 609 // CountChildren 610 int32 611 BPartition::CountChildren() const 612 { 613 if (fDelegate) 614 return fDelegate->CountChildren(); 615 616 return _CountChildren(); 617 } 618 619 620 // CountDescendants 621 int32 622 BPartition::CountDescendants() const 623 { 624 int32 count = 1; 625 for (int32 i = 0; BPartition* child = ChildAt(i); i++) 626 count += child->CountDescendants(); 627 return count; 628 } 629 630 631 // FindDescendant 632 BPartition* 633 BPartition::FindDescendant(partition_id id) const 634 { 635 IDFinderVisitor visitor(id); 636 return VisitEachDescendant(&visitor); 637 } 638 639 640 // GetPartitioningInfo 641 status_t 642 BPartition::GetPartitioningInfo(BPartitioningInfo* info) const 643 { 644 if (!fDelegate || !info) 645 return B_BAD_VALUE; 646 647 return fDelegate->GetPartitioningInfo(info); 648 } 649 650 651 // VisitEachChild 652 BPartition* 653 BPartition::VisitEachChild(BDiskDeviceVisitor* visitor) const 654 { 655 if (visitor) { 656 int32 level = _Level(); 657 for (int32 i = 0; BPartition* child = ChildAt(i); i++) { 658 if (child->_AcceptVisitor(visitor, level)) 659 return child; 660 } 661 } 662 return NULL; 663 } 664 665 666 // VisitEachDescendant 667 BPartition* 668 BPartition::VisitEachDescendant(BDiskDeviceVisitor* visitor) const 669 { 670 if (visitor) 671 return const_cast<BPartition*>(this)->_VisitEachDescendant(visitor); 672 return NULL; 673 } 674 675 676 // CanDefragment 677 bool 678 BPartition::CanDefragment(bool* whileMounted) const 679 { 680 return _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING, 681 B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING_WHILE_MOUNTED, whileMounted); 682 } 683 684 685 // Defragment 686 status_t 687 BPartition::Defragment() const 688 { 689 if (!fDelegate) 690 return B_BAD_VALUE; 691 692 return fDelegate->Defragment(); 693 } 694 695 696 // CanRepair 697 bool 698 BPartition::CanRepair(bool checkOnly, bool* whileMounted) const 699 { 700 uint32 flag; 701 uint32 whileMountedFlag; 702 if (checkOnly) { 703 flag = B_DISK_SYSTEM_SUPPORTS_CHECKING; 704 whileMountedFlag = B_DISK_SYSTEM_SUPPORTS_CHECKING_WHILE_MOUNTED; 705 } else { 706 flag = B_DISK_SYSTEM_SUPPORTS_REPAIRING; 707 whileMountedFlag = B_DISK_SYSTEM_SUPPORTS_REPAIRING_WHILE_MOUNTED; 708 } 709 710 return _SupportsOperation(flag, whileMountedFlag, whileMounted); 711 } 712 713 714 // Repair 715 status_t 716 BPartition::Repair(bool checkOnly) const 717 { 718 if (!fDelegate) 719 return B_BAD_VALUE; 720 721 return fDelegate->Repair(checkOnly); 722 } 723 724 725 // CanResize 726 bool 727 BPartition::CanResize(bool* canResizeContents, bool* whileMounted) const 728 { 729 BPartition* parent = Parent(); 730 if (!parent) 731 return false; 732 733 if (!parent->_SupportsChildOperation(this, 734 B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD)) { 735 return false; 736 } 737 738 if (!_HasContent()) 739 return true; 740 741 return _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_RESIZING, 742 B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED, whileMounted); 743 } 744 745 746 // ValidateResize 747 status_t 748 BPartition::ValidateResize(off_t* size) const 749 { 750 BPartition* parent = Parent(); 751 if (!parent || !fDelegate) 752 return B_BAD_VALUE; 753 754 status_t error = parent->fDelegate->ValidateResizeChild(fDelegate, size); 755 if (error != B_OK) 756 return error; 757 758 if (_HasContent()) { 759 // TODO: We would actually need the parameter for the content size. 760 off_t contentSize = *size; 761 error = fDelegate->ValidateResize(&contentSize); 762 if (error != B_OK) 763 return error; 764 765 if (contentSize > *size) 766 return B_BAD_VALUE; 767 } 768 769 return B_OK; 770 } 771 772 773 // Resize 774 status_t 775 BPartition::Resize(off_t size) 776 { 777 BPartition* parent = Parent(); 778 if (!parent || !fDelegate) 779 return B_BAD_VALUE; 780 781 status_t error; 782 off_t contentSize = size; 783 if (_HasContent()) { 784 error = fDelegate->ValidateResize(&contentSize); 785 if (error != B_OK) 786 return error; 787 788 if (contentSize > size) 789 return B_BAD_VALUE; 790 } 791 792 // If shrinking the partition, resize content first, otherwise last. 793 bool shrink = (Size() > size); 794 795 if (shrink && ContentType() != NULL) { 796 error = fDelegate->Resize(contentSize); 797 if (error != B_OK) 798 return error; 799 } 800 801 error = parent->fDelegate->ResizeChild(fDelegate, size); 802 if (error != B_OK) 803 return error; 804 805 if (!shrink && ContentType() != NULL) { 806 error = fDelegate->Resize(contentSize); 807 if (error != B_OK) 808 return error; 809 } 810 811 return B_OK; 812 } 813 814 815 // CanMove 816 bool 817 BPartition::CanMove(BObjectList<BPartition>* unmovableDescendants, 818 BObjectList<BPartition>* movableOnlyIfUnmounted) const 819 { 820 BPartition* parent = Parent(); 821 if (!parent || !fDelegate) 822 return false; 823 824 if (!parent->_SupportsChildOperation(this, 825 B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD)) { 826 return false; 827 } 828 829 bool whileMounted; 830 bool movable = _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_MOVING, 831 B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED, &whileMounted); 832 if (!movable) 833 return false; 834 835 if (!whileMounted) 836 movableOnlyIfUnmounted->AddItem(const_cast<BPartition*>(this)); 837 838 // collect descendent partitions 839 // TODO: ... 840 // TODO: Currently there's no interface for asking descendents. They'll still 841 // have the same offset (relative to their parent) after moving. The only thing 842 // we really have to ask is whether they need to be unmounted. 843 844 return true; 845 } 846 847 848 // ValidateMove 849 status_t 850 BPartition::ValidateMove(off_t* offset) const 851 { 852 BPartition* parent = Parent(); 853 if (!parent || !fDelegate) 854 return B_BAD_VALUE; 855 856 status_t error = parent->fDelegate->ValidateMoveChild(fDelegate, offset); 857 if (error != B_OK) 858 return error; 859 860 if (_HasContent()) { 861 off_t contentOffset = *offset; 862 error = fDelegate->ValidateMove(&contentOffset); 863 if (error != B_OK) 864 return error; 865 866 if (contentOffset != *offset) 867 return B_BAD_VALUE; 868 } 869 870 return B_OK; 871 } 872 873 874 // Move 875 status_t 876 BPartition::Move(off_t offset) 877 { 878 BPartition* parent = Parent(); 879 if (!parent || !fDelegate) 880 return B_BAD_VALUE; 881 882 status_t error = parent->fDelegate->MoveChild(fDelegate, offset); 883 if (error != B_OK) 884 return error; 885 886 if (_HasContent()) { 887 error = fDelegate->Move(offset); 888 if (error != B_OK) 889 return error; 890 } 891 892 return B_OK; 893 } 894 895 896 // CanSetName 897 bool 898 BPartition::CanSetName() const 899 { 900 BPartition* parent = Parent(); 901 if (!parent || !fDelegate) 902 return false; 903 904 return parent->_SupportsChildOperation(this, 905 B_DISK_SYSTEM_SUPPORTS_SETTING_NAME); 906 } 907 908 909 // ValidateSetName 910 status_t 911 BPartition::ValidateSetName(BString* name) const 912 { 913 BPartition* parent = Parent(); 914 if (!parent || !fDelegate) 915 return B_BAD_VALUE; 916 917 return parent->fDelegate->ValidateSetName(fDelegate, name); 918 } 919 920 921 // SetName 922 status_t 923 BPartition::SetName(const char* name) 924 { 925 BPartition* parent = Parent(); 926 if (!parent || !fDelegate) 927 return B_BAD_VALUE; 928 929 return parent->fDelegate->SetName(fDelegate, name); 930 } 931 932 933 // CanSetContentName 934 bool 935 BPartition::CanSetContentName(bool* whileMounted) const 936 { 937 return _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME, 938 B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED, 939 whileMounted); 940 } 941 942 943 // ValidateSetContentName 944 status_t 945 BPartition::ValidateSetContentName(BString* name) const 946 { 947 if (!fDelegate) 948 return B_BAD_VALUE; 949 950 return fDelegate->ValidateSetContentName(name); 951 } 952 953 954 // SetContentName 955 status_t 956 BPartition::SetContentName(const char* name) 957 { 958 if (!fDelegate) 959 return B_BAD_VALUE; 960 961 return fDelegate->SetContentName(name); 962 } 963 964 965 // CanSetType 966 bool 967 BPartition::CanSetType() const 968 { 969 BPartition* parent = Parent(); 970 if (!parent) 971 return false; 972 973 return parent->_SupportsChildOperation(this, 974 B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE); 975 } 976 977 978 // ValidateSetType 979 status_t 980 BPartition::ValidateSetType(const char* type) const 981 { 982 BPartition* parent = Parent(); 983 if (!parent || !fDelegate) 984 return B_BAD_VALUE; 985 986 return parent->fDelegate->ValidateSetType(fDelegate, type); 987 } 988 989 990 // SetType 991 status_t 992 BPartition::SetType(const char* type) 993 { 994 BPartition* parent = Parent(); 995 if (!parent || !fDelegate) 996 return B_BAD_VALUE; 997 998 return parent->fDelegate->SetType(fDelegate, type); 999 } 1000 1001 1002 // CanEditParameters 1003 bool 1004 BPartition::CanEditParameters() const 1005 { 1006 BPartition* parent = Parent(); 1007 if (!parent) 1008 return false; 1009 1010 return parent->_SupportsChildOperation(this, 1011 B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS); 1012 } 1013 1014 1015 // GetParameterEditor 1016 status_t 1017 BPartition::GetParameterEditor(BDiskDeviceParameterEditor** editor) 1018 { 1019 BPartition* parent = Parent(); 1020 if (!parent || !fDelegate) 1021 return B_BAD_VALUE; 1022 1023 return parent->fDelegate->GetParameterEditor(fDelegate, editor); 1024 } 1025 1026 1027 // SetParameters 1028 status_t 1029 BPartition::SetParameters(const char* parameters) 1030 { 1031 BPartition* parent = Parent(); 1032 if (!parent || !fDelegate) 1033 return B_BAD_VALUE; 1034 1035 return parent->fDelegate->SetParameters(fDelegate, parameters); 1036 } 1037 1038 1039 // CanEditContentParameters 1040 bool 1041 BPartition::CanEditContentParameters(bool* whileMounted) const 1042 { 1043 return _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS, 1044 B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED, 1045 whileMounted); 1046 } 1047 1048 1049 // GetContentParameterEditor 1050 status_t 1051 BPartition::GetContentParameterEditor(BDiskDeviceParameterEditor** editor) 1052 { 1053 if (!fDelegate) 1054 return B_BAD_VALUE; 1055 1056 return fDelegate->GetContentParameterEditor(editor); 1057 } 1058 1059 1060 // SetContentParameters 1061 status_t 1062 BPartition::SetContentParameters(const char* parameters) 1063 { 1064 if (!fDelegate) 1065 return B_BAD_VALUE; 1066 1067 return fDelegate->SetContentParameters(parameters); 1068 } 1069 1070 1071 // GetNextSupportedType 1072 status_t 1073 BPartition::GetNextSupportedType(int32 *cookie, BString* type) const 1074 { 1075 BPartition* parent = Parent(); 1076 if (!parent || !fDelegate) 1077 return false; 1078 1079 return parent->fDelegate->GetNextSupportedChildType(fDelegate, cookie, 1080 type); 1081 } 1082 1083 1084 // GetNextSupportedChildType 1085 status_t 1086 BPartition::GetNextSupportedChildType(int32 *cookie, BString* type) const 1087 { 1088 if (!fDelegate) 1089 return B_BAD_VALUE; 1090 1091 return fDelegate->GetNextSupportedChildType(NULL, cookie, type); 1092 } 1093 1094 1095 // IsSubSystem 1096 bool 1097 BPartition::BPartition::IsSubSystem(const char* diskSystem) const 1098 { 1099 BPartition* parent = Parent(); 1100 if (!parent || !fDelegate) 1101 return false; 1102 1103 return parent->fDelegate->IsSubSystem(fDelegate, diskSystem); 1104 } 1105 1106 1107 // CanInitialize 1108 bool 1109 BPartition::CanInitialize(const char* diskSystem) const 1110 { 1111 return fDelegate && fDelegate->CanInitialize(diskSystem); 1112 } 1113 1114 1115 // GetInitializationParameterEditor 1116 status_t 1117 BPartition::GetInitializationParameterEditor(const char* diskSystem, 1118 BDiskDeviceParameterEditor** editor) const 1119 { 1120 if (!fDelegate) 1121 return B_BAD_VALUE; 1122 1123 return fDelegate->GetInitializationParameterEditor(diskSystem, editor); 1124 } 1125 1126 1127 // ValidateInitialize 1128 status_t 1129 BPartition::ValidateInitialize(const char* diskSystem, BString* name, 1130 const char* parameters) 1131 { 1132 if (!fDelegate) 1133 return B_BAD_VALUE; 1134 1135 return fDelegate->ValidateInitialize(diskSystem, name, parameters); 1136 } 1137 1138 1139 // Initialize 1140 status_t 1141 BPartition::Initialize(const char* diskSystem, const char* name, 1142 const char* parameters) 1143 { 1144 if (!fDelegate) 1145 return B_BAD_VALUE; 1146 1147 return fDelegate->Initialize(diskSystem, name, parameters); 1148 } 1149 1150 1151 // Uninitialize 1152 status_t 1153 BPartition::Uninitialize() 1154 { 1155 // TODO: Implement! 1156 return B_BAD_VALUE; 1157 } 1158 1159 1160 // CanCreateChild 1161 bool 1162 BPartition::CanCreateChild() const 1163 { 1164 return _SupportsChildOperation(NULL, B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD); 1165 } 1166 1167 1168 // GetChildCreationParameterEditor 1169 status_t 1170 BPartition::GetChildCreationParameterEditor(const char* type, 1171 BDiskDeviceParameterEditor** editor) const 1172 { 1173 if (!fDelegate) 1174 return B_BAD_VALUE; 1175 1176 return fDelegate->GetChildCreationParameterEditor(type, editor); 1177 } 1178 1179 1180 // ValidateCreateChild 1181 status_t 1182 BPartition::ValidateCreateChild(off_t* offset, off_t* size, const char* type, 1183 BString* name, const char* parameters) const 1184 { 1185 if (!fDelegate) 1186 return B_BAD_VALUE; 1187 1188 return fDelegate->ValidateCreateChild(offset, size, type, name, parameters); 1189 } 1190 1191 1192 // CreateChild 1193 status_t 1194 BPartition::CreateChild(off_t offset, off_t size, const char* type, 1195 const char* name, const char* parameters, BPartition** child) 1196 { 1197 if (!fDelegate) 1198 return B_BAD_VALUE; 1199 1200 return fDelegate->CreateChild(offset, size, type, name, parameters, child); 1201 } 1202 1203 1204 // CanDeleteChild 1205 bool 1206 BPartition::CanDeleteChild(int32 index) const 1207 { 1208 BPartition* child = ChildAt(index); 1209 if (!fDelegate || !child) 1210 return false; 1211 1212 return _SupportsChildOperation(child, 1213 B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD); 1214 } 1215 1216 1217 // DeleteChild 1218 status_t 1219 BPartition::DeleteChild(int32 index) 1220 { 1221 BPartition* child = ChildAt(index); 1222 if (!fDelegate || !child || child->Parent() != this) 1223 return B_BAD_VALUE; 1224 1225 return fDelegate->DeleteChild(child->fDelegate); 1226 } 1227 1228 1229 // constructor 1230 /*! \brief Privatized copy constructor to avoid usage. 1231 */ 1232 BPartition::BPartition(const BPartition &) 1233 { 1234 } 1235 1236 1237 // = 1238 /*! \brief Privatized assignment operator to avoid usage. 1239 */ 1240 BPartition & 1241 BPartition::operator=(const BPartition &) 1242 { 1243 return *this; 1244 } 1245 1246 1247 // _SetTo 1248 status_t 1249 BPartition::_SetTo(BDiskDevice* device, BPartition* parent, 1250 user_partition_data* data) 1251 { 1252 _Unset(); 1253 if (!device || !data) 1254 return B_BAD_VALUE; 1255 fPartitionData = data; 1256 fDevice = device; 1257 fParent = parent; 1258 fPartitionData->user_data = this; 1259 1260 // create and init children 1261 status_t error = B_OK; 1262 for (int32 i = 0; error == B_OK && i < fPartitionData->child_count; i++) { 1263 BPartition* child = new(nothrow) BPartition; 1264 if (child) { 1265 error = child->_SetTo(fDevice, this, fPartitionData->children[i]); 1266 if (error != B_OK) 1267 delete child; 1268 } else 1269 error = B_NO_MEMORY; 1270 } 1271 1272 // cleanup on error 1273 if (error != B_OK) 1274 _Unset(); 1275 return error; 1276 } 1277 1278 1279 // _Unset 1280 void 1281 BPartition::_Unset() 1282 { 1283 // delete children 1284 if (fPartitionData) { 1285 for (int32 i = 0; i < fPartitionData->child_count; i++) { 1286 if (BPartition* child = ChildAt(i)) 1287 delete child; 1288 } 1289 fPartitionData->user_data = NULL; 1290 } 1291 1292 fDevice = NULL; 1293 fParent = NULL; 1294 fPartitionData = NULL; 1295 fDelegate = NULL; 1296 } 1297 1298 1299 // _RemoveObsoleteDescendants 1300 status_t 1301 BPartition::_RemoveObsoleteDescendants(user_partition_data* data, bool* updated) 1302 { 1303 // remove all children not longer persistent 1304 // Not exactly efficient: O(n^2), considering BList::RemoveItem() 1305 // O(1). We could do better (O(n*log(n))), when sorting the arrays before, 1306 // but then the list access is more random and we had to find the 1307 // BPartition to remove, which makes the list operation definitely O(n). 1308 int32 count = CountChildren(); 1309 for (int32 i = count - 1; i >= 0; i--) { 1310 BPartition* child = ChildAt(i); 1311 bool found = false; 1312 for (int32 k = data->child_count - 1; k >= 0; k--) { 1313 if (data->children[k]->id == child->ID()) { 1314 // found partition: ask it to remove its obsolete descendants 1315 found = true; 1316 status_t error = child->_RemoveObsoleteDescendants( 1317 data->children[k], updated); 1318 if (error != B_OK) 1319 return error; 1320 1321 // set the user data to the BPartition object to find it 1322 // quicker later 1323 data->children[k]->user_data = child; 1324 break; 1325 } 1326 } 1327 1328 // if partition is obsolete, remove it 1329 if (!found) { 1330 *updated = true; 1331 _RemoveChild(i); 1332 } 1333 } 1334 return B_OK; 1335 } 1336 1337 1338 // _Update 1339 status_t 1340 BPartition::_Update(user_partition_data* data, bool* updated) 1341 { 1342 user_partition_data* oldData = fPartitionData; 1343 fPartitionData = data; 1344 // check for changes 1345 if (data->offset != oldData->offset 1346 || data->size != oldData->size 1347 || data->block_size != oldData->block_size 1348 || data->status != oldData->status 1349 || data->flags != oldData->flags 1350 || data->volume != oldData->volume 1351 || data->disk_system != oldData->disk_system // not needed 1352 || compare_string(data->name, oldData->name) 1353 || compare_string(data->content_name, oldData->content_name) 1354 || compare_string(data->type, oldData->type) 1355 || compare_string(data->content_type, oldData->content_type) 1356 || compare_string(data->parameters, oldData->parameters) 1357 || compare_string(data->content_parameters, 1358 oldData->content_parameters)) { 1359 *updated = true; 1360 } 1361 1362 // add new children and update existing ones 1363 status_t error = B_OK; 1364 for (int32 i = 0; i < data->child_count; i++) { 1365 user_partition_data* childData = data->children[i]; 1366 BPartition* child = (BPartition*)childData->user_data; 1367 if (child) { 1368 // old partition 1369 error = child->_Update(childData, updated); 1370 if (error != B_OK) 1371 return error; 1372 } else { 1373 // new partition 1374 *updated = true; 1375 child = new(nothrow) BPartition; 1376 if (!child) 1377 return B_NO_MEMORY; 1378 1379 error = child->_SetTo(fDevice, this, data->children[i]); 1380 if (error != B_OK) { 1381 delete child; 1382 return error; 1383 } 1384 1385 childData->user_data = child; 1386 } 1387 } 1388 return error; 1389 } 1390 1391 1392 // _RemoveChild 1393 void 1394 BPartition::_RemoveChild(int32 index) 1395 { 1396 int32 count = CountChildren(); 1397 if (!fPartitionData || index < 0 || index >= count) 1398 return; 1399 1400 // delete the BPartition and its children 1401 delete ChildAt(index); 1402 1403 // compact the children array 1404 for (int32 i = index + 1; i < count; i++) 1405 fPartitionData->children[i - 1] = fPartitionData->children[i]; 1406 fPartitionData->child_count--; 1407 } 1408 1409 1410 // _ChildAt 1411 BPartition* 1412 BPartition::_ChildAt(int32 index) const 1413 { 1414 if (index < 0 || index >= fPartitionData->child_count) 1415 return NULL; 1416 return (BPartition*)fPartitionData->children[index]->user_data; 1417 } 1418 1419 1420 // _CountChildren 1421 int32 1422 BPartition::_CountChildren() const 1423 { 1424 return fPartitionData->child_count; 1425 } 1426 1427 1428 // _Level 1429 int32 1430 BPartition::_Level() const 1431 { 1432 int32 level = 0; 1433 const BPartition* ancestor = this; 1434 while ((ancestor = ancestor->Parent())) 1435 level++; 1436 return level; 1437 } 1438 1439 1440 // _AcceptVisitor 1441 bool 1442 BPartition::_AcceptVisitor(BDiskDeviceVisitor* visitor, int32 level) 1443 { 1444 return visitor->Visit(this, level); 1445 } 1446 1447 1448 // _VisitEachDescendant 1449 BPartition* 1450 BPartition::_VisitEachDescendant(BDiskDeviceVisitor* visitor, int32 level) 1451 { 1452 if (level < 0) 1453 level = _Level(); 1454 if (_AcceptVisitor(visitor, level)) 1455 return this; 1456 for (int32 i = 0; BPartition* child = ChildAt(i); i++) { 1457 if (BPartition* result = child->_VisitEachDescendant(visitor, 1458 level + 1)) { 1459 return result; 1460 } 1461 } 1462 return NULL; 1463 } 1464 1465 1466 // _PartitionData 1467 const user_partition_data* 1468 BPartition::_PartitionData() const 1469 { 1470 return fDelegate ? fDelegate->PartitionData() : fPartitionData; 1471 } 1472 1473 1474 // _HasContent 1475 bool 1476 BPartition::_HasContent() const 1477 { 1478 return (ContentType() != NULL); 1479 } 1480 1481 1482 // _SupportsOperation 1483 bool 1484 BPartition::_SupportsOperation(uint32 flag, uint32 whileMountedFlag, 1485 bool* whileMounted) const 1486 { 1487 if (!fDelegate) 1488 return false; 1489 1490 uint32 supported = fDelegate->SupportedOperations(flag | whileMountedFlag); 1491 1492 if (whileMounted) 1493 *whileMounted = supported & whileMountedFlag; 1494 1495 return supported & flag; 1496 } 1497 1498 1499 // _SupportsChildOperation 1500 bool 1501 BPartition::_SupportsChildOperation(const BPartition* child, uint32 flag) const 1502 { 1503 if (!fDelegate || child && !child->fDelegate) 1504 return false; 1505 1506 uint32 supported = fDelegate->SupportedChildOperations( 1507 child ? child->fDelegate : NULL, flag); 1508 1509 return supported & flag; 1510 } 1511 1512 1513 // _CreateDelegates 1514 status_t 1515 BPartition::_CreateDelegates() 1516 { 1517 if (fDelegate || !fPartitionData) 1518 return B_BAD_VALUE; 1519 1520 // create and init delegate 1521 fDelegate = new(nothrow) Delegate(this); 1522 if (!fDelegate) 1523 return B_NO_MEMORY; 1524 1525 status_t error = fDelegate->InitHierarchy(fPartitionData, 1526 fParent ? fParent->fDelegate : NULL); 1527 if (error != B_OK) 1528 return error; 1529 1530 // create child delegates 1531 int32 count = _CountChildren(); 1532 for (int32 i = 0; i < count; i++) { 1533 BPartition* child = _ChildAt(i); 1534 error = child->_CreateDelegates(); 1535 if (error != B_OK) 1536 return error; 1537 } 1538 1539 return B_OK; 1540 } 1541 1542 1543 // _InitDelegates 1544 status_t 1545 BPartition::_InitDelegates() 1546 { 1547 // init delegate 1548 status_t error = fDelegate->InitAfterHierarchy(); 1549 if (error != B_OK) 1550 return error; 1551 1552 // recursively init child delegates 1553 int32 count = CountChildren(); 1554 for (int32 i = 0; i < count; i++) { 1555 error = ChildAt(i)->_InitDelegates(); 1556 if (error != B_OK) 1557 return error; 1558 } 1559 1560 return B_OK; 1561 } 1562 1563 1564 // _DeleteDelegates 1565 void 1566 BPartition::_DeleteDelegates() 1567 { 1568 // recursively delete child delegates 1569 int32 count = CountChildren(); 1570 for (int32 i = count - 1; i >= 0; i--) 1571 ChildAt(i)->_DeleteDelegates(); 1572 1573 // delete delegate 1574 delete fDelegate; 1575 fDelegate = NULL; 1576 1577 // Commit suicide, if the delegate was our only link to reality (i.e. 1578 // there's no physically existing partition we represent). 1579 if (fPartitionData == NULL) 1580 delete this; 1581 } 1582 1583 1584 // _IsModified 1585 bool 1586 BPartition::_IsModified() const 1587 { 1588 if (!fDelegate) 1589 return false; 1590 1591 // TODO: Implement! 1592 return false; 1593 } 1594