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