1 // KPartition.cpp 2 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 9 #include <KernelExport.h> 10 #include <Drivers.h> 11 #include <Errors.h> 12 #include <fs_volume.h> 13 #include <util/kernel_cpp.h> 14 15 #include <ddm_userland_interface.h> 16 #include <fs/devfs.h> 17 #include <KDiskDevice.h> 18 #include <KDiskDeviceManager.h> 19 #include <KDiskDeviceUtils.h> 20 #include <KDiskSystem.h> 21 #include <KPartition.h> 22 #include <KPartitionListener.h> 23 #include <KPartitionVisitor.h> 24 #include <KPath.h> 25 #include <VectorSet.h> 26 #include <vfs.h> 27 28 #include "UserDataWriter.h" 29 30 using namespace std; 31 32 // debugging 33 //#define DBG(x) 34 #define DBG(x) x 35 #define OUT dprintf 36 37 // ListenerSet 38 struct KPartition::ListenerSet : VectorSet<KPartitionListener*> {}; 39 40 // constructor 41 KPartition::KPartition(partition_id id) 42 : fPartitionData(), 43 fChildren(), 44 fDevice(NULL), 45 fParent(NULL), 46 fDiskSystem(NULL), 47 fListeners(NULL), 48 fChangeFlags(0), 49 fChangeCounter(0), 50 fAlgorithmData(0), 51 fReferenceCount(0), 52 fObsolete(false), 53 fPublished(false) 54 { 55 fPartitionData.id = (id >= 0 ? id : _NextID()); 56 fPartitionData.offset = 0; 57 fPartitionData.size = 0; 58 fPartitionData.content_size = 0; 59 fPartitionData.block_size = 0; 60 fPartitionData.child_count = 0; 61 fPartitionData.index = -1; 62 fPartitionData.status = B_PARTITION_UNRECOGNIZED; 63 fPartitionData.flags = B_PARTITION_BUSY; 64 fPartitionData.volume = -1; 65 fPartitionData.mount_cookie = NULL; 66 fPartitionData.name = NULL; 67 fPartitionData.content_name = NULL; 68 fPartitionData.type = NULL; 69 fPartitionData.content_type = NULL; 70 fPartitionData.parameters = NULL; 71 fPartitionData.content_parameters = NULL; 72 fPartitionData.cookie = NULL; 73 fPartitionData.content_cookie = NULL; 74 } 75 76 // destructor 77 KPartition::~KPartition() 78 { 79 delete fListeners; 80 SetDiskSystem(NULL); 81 free(fPartitionData.name); 82 free(fPartitionData.content_name); 83 free(fPartitionData.type); 84 free(fPartitionData.parameters); 85 free(fPartitionData.content_parameters); 86 } 87 88 // Register 89 void 90 KPartition::Register() 91 { 92 fReferenceCount++; 93 } 94 95 // Unregister 96 void 97 KPartition::Unregister() 98 { 99 KDiskDeviceManager *manager = KDiskDeviceManager::Default(); 100 ManagerLocker locker(manager); 101 fReferenceCount--; 102 if (IsObsolete() && fReferenceCount == 0) { 103 // let the manager delete object 104 manager->DeletePartition(this); 105 } 106 } 107 108 // CountReferences 109 int32 110 KPartition::CountReferences() const 111 { 112 return fReferenceCount; 113 } 114 115 // MarkObsolete 116 void 117 KPartition::MarkObsolete() 118 { 119 fObsolete = true; 120 } 121 122 // IsObsolete 123 bool 124 KPartition::IsObsolete() const 125 { 126 return fObsolete; 127 } 128 129 // PrepareForRemoval 130 bool 131 KPartition::PrepareForRemoval() 132 { 133 bool result = RemoveAllChildren(); 134 UninitializeContents(); 135 UnpublishDevice(); 136 if (ParentDiskSystem()) 137 ParentDiskSystem()->FreeCookie(this); 138 if (DiskSystem()) 139 DiskSystem()->FreeContentCookie(this); 140 return result; 141 } 142 143 // PrepareForDeletion 144 bool 145 KPartition::PrepareForDeletion() 146 { 147 return true; 148 } 149 150 // Open 151 status_t 152 KPartition::Open(int flags, int *fd) 153 { 154 if (!fd) 155 return B_BAD_VALUE; 156 157 // get the path 158 KPath path; 159 status_t error = GetPath(&path); 160 if (error != B_OK) 161 return error; 162 163 // open the device 164 *fd = open(path.Path(), flags); 165 if (*fd < 0) 166 return errno; 167 168 return B_OK; 169 } 170 171 // PublishDevice 172 status_t 173 KPartition::PublishDevice() 174 { 175 if (fPublished) 176 return B_OK; 177 178 // get the path 179 KPath path; 180 status_t error = GetPath(&path); 181 if (error != B_OK) 182 return error; 183 184 // prepare a partition_info 185 partition_info info; 186 info.offset = Offset(); 187 info.size = Size(); 188 info.logical_block_size = BlockSize(); 189 info.session = 0; 190 info.partition = ID(); 191 if (strlcpy(info.device, Device()->Path(), B_PATH_NAME_LENGTH) 192 >= B_PATH_NAME_LENGTH) { 193 return B_NAME_TOO_LONG; 194 } 195 196 error = devfs_publish_partition(path.Path() + 5, &info); 197 // we need to remove the "/dev/" part from the path 198 if (error != B_OK) 199 return error; 200 201 fPublished = true; 202 203 return B_OK; 204 } 205 206 // UnpublishDevice 207 status_t 208 KPartition::UnpublishDevice() 209 { 210 if (!fPublished) 211 return B_OK; 212 213 // get the path 214 KPath path; 215 status_t error = GetPath(&path); 216 if (error != B_OK) 217 return error; 218 219 fPublished = false; 220 221 return devfs_unpublish_partition(path.Path() + 5); 222 // we need to remove the "/dev/" part from the path 223 } 224 225 226 // IsPublished 227 bool 228 KPartition::IsPublished() const 229 { 230 return fPublished; 231 } 232 233 234 // SetBusy 235 void 236 KPartition::SetBusy(bool busy) 237 { 238 if (busy) 239 SetFlags(B_PARTITION_BUSY); 240 else 241 ClearFlags(B_PARTITION_BUSY); 242 } 243 244 245 // IsBusy 246 bool 247 KPartition::IsBusy() const 248 { 249 return (fPartitionData.flags & B_PARTITION_BUSY); 250 } 251 252 253 // IsBusy 254 bool 255 KPartition::IsBusy(bool includeDescendants) 256 { 257 if (!includeDescendants) 258 return IsBusy(); 259 260 struct IsBusyVisitor : KPartitionVisitor { 261 virtual bool VisitPre(KPartition* partition) 262 { 263 return partition->IsBusy(); 264 } 265 } checkVisitor; 266 267 return VisitEachDescendant(&checkVisitor) != NULL; 268 } 269 270 271 // CheckAndMarkBusy 272 bool 273 KPartition::CheckAndMarkBusy(bool includeDescendants) 274 { 275 if (IsBusy(includeDescendants)) 276 return false; 277 278 MarkBusy(includeDescendants); 279 280 return true; 281 } 282 283 284 // MarkBusy 285 void 286 KPartition::MarkBusy(bool includeDescendants) 287 { 288 if (includeDescendants) { 289 struct MarkBusyVisitor : KPartitionVisitor { 290 virtual bool VisitPre(KPartition* partition) 291 { 292 partition->AddFlags(B_PARTITION_BUSY); 293 return false; 294 } 295 } markVisitor; 296 297 VisitEachDescendant(&markVisitor); 298 } else 299 SetBusy(true); 300 } 301 302 303 // UnmarkBusy 304 void 305 KPartition::UnmarkBusy(bool includeDescendants) 306 { 307 if (includeDescendants) { 308 struct UnmarkBusyVisitor : KPartitionVisitor { 309 virtual bool VisitPre(KPartition* partition) 310 { 311 partition->ClearFlags(B_PARTITION_BUSY); 312 return false; 313 } 314 } visitor; 315 316 VisitEachDescendant(&visitor); 317 } else 318 SetBusy(false); 319 } 320 321 322 // SetOffset 323 void 324 KPartition::SetOffset(off_t offset) 325 { 326 if (fPartitionData.offset != offset) { 327 fPartitionData.offset = offset; 328 FireOffsetChanged(offset); 329 } 330 } 331 332 // Offset 333 off_t 334 KPartition::Offset() const 335 { 336 return fPartitionData.offset; 337 } 338 339 // SetSize 340 void 341 KPartition::SetSize(off_t size) 342 { 343 if (fPartitionData.size != size) { 344 fPartitionData.size = size; 345 FireSizeChanged(size); 346 } 347 } 348 349 // Size 350 off_t 351 KPartition::Size() const 352 { 353 return fPartitionData.size; 354 } 355 356 // SetContentSize 357 void 358 KPartition::SetContentSize(off_t size) 359 { 360 if (fPartitionData.content_size != size) { 361 fPartitionData.content_size = size; 362 FireContentSizeChanged(size); 363 } 364 } 365 366 // ContentSize 367 off_t 368 KPartition::ContentSize() const 369 { 370 return fPartitionData.content_size; 371 } 372 373 // SetBlockSize 374 void 375 KPartition::SetBlockSize(uint32 blockSize) 376 { 377 if (fPartitionData.block_size != blockSize) { 378 fPartitionData.block_size = blockSize; 379 FireBlockSizeChanged(blockSize); 380 } 381 } 382 383 // BlockSize 384 uint32 385 KPartition::BlockSize() const 386 { 387 return fPartitionData.block_size; 388 } 389 390 // SetIndex 391 void 392 KPartition::SetIndex(int32 index) 393 { 394 if (fPartitionData.index != index) { 395 fPartitionData.index = index; 396 FireIndexChanged(index); 397 } 398 } 399 400 // Index 401 int32 402 KPartition::Index() const 403 { 404 return fPartitionData.index; 405 } 406 407 // SetStatus 408 void 409 KPartition::SetStatus(uint32 status) 410 { 411 if (fPartitionData.status != status) { 412 fPartitionData.status = status; 413 FireStatusChanged(status); 414 } 415 } 416 417 // Status 418 uint32 419 KPartition::Status() const 420 { 421 return fPartitionData.status; 422 } 423 424 // IsUninitialized 425 bool 426 KPartition::IsUninitialized() const 427 { 428 return (Status() == B_PARTITION_UNINITIALIZED); 429 } 430 431 // SetFlags 432 void 433 KPartition::SetFlags(uint32 flags) 434 { 435 if (fPartitionData.flags != flags) { 436 fPartitionData.flags = flags; 437 FireFlagsChanged(flags); 438 } 439 } 440 441 // AddFlags 442 void 443 KPartition::AddFlags(uint32 flags) 444 { 445 if (~fPartitionData.flags & flags) { 446 fPartitionData.flags |= flags; 447 FireFlagsChanged(fPartitionData.flags); 448 } 449 } 450 451 // ClearFlags 452 void 453 KPartition::ClearFlags(uint32 flags) 454 { 455 if (fPartitionData.flags & flags) { 456 fPartitionData.flags &= ~flags; 457 FireFlagsChanged(fPartitionData.flags); 458 } 459 } 460 461 // Flags 462 uint32 463 KPartition::Flags() const 464 { 465 return fPartitionData.flags; 466 } 467 468 // ContainsFileSystem 469 bool 470 KPartition::ContainsFileSystem() const 471 { 472 return (fPartitionData.flags & B_PARTITION_FILE_SYSTEM); 473 } 474 475 // ContainsPartitioningSystem 476 bool 477 KPartition::ContainsPartitioningSystem() const 478 { 479 return (fPartitionData.flags & B_PARTITION_PARTITIONING_SYSTEM); 480 } 481 482 // IsReadOnly 483 bool 484 KPartition::IsReadOnly() const 485 { 486 return (fPartitionData.flags & B_PARTITION_READ_ONLY); 487 } 488 489 // IsMounted 490 bool 491 KPartition::IsMounted() const 492 { 493 return (fPartitionData.flags & B_PARTITION_MOUNTED); 494 } 495 496 // IsDevice 497 bool 498 KPartition::IsDevice() const 499 { 500 return (fPartitionData.flags & B_PARTITION_IS_DEVICE); 501 } 502 503 // SetName 504 status_t 505 KPartition::SetName(const char *name) 506 { 507 status_t error = set_string(fPartitionData.name, name); 508 FireNameChanged(fPartitionData.name); 509 return error; 510 } 511 512 // Name 513 const char * 514 KPartition::Name() const 515 { 516 return fPartitionData.name; 517 } 518 519 // SetContentName 520 status_t 521 KPartition::SetContentName(const char *name) 522 { 523 status_t error = set_string(fPartitionData.content_name, name); 524 FireContentNameChanged(fPartitionData.content_name); 525 return error; 526 } 527 528 // ContentName 529 const char * 530 KPartition::ContentName() const 531 { 532 return fPartitionData.content_name; 533 } 534 535 // SetType 536 status_t 537 KPartition::SetType(const char *type) 538 { 539 status_t error = set_string(fPartitionData.type, type); 540 FireTypeChanged(fPartitionData.type); 541 return error; 542 } 543 544 // Type 545 const char * 546 KPartition::Type() const 547 { 548 return fPartitionData.type; 549 } 550 551 // ContentType 552 const char * 553 KPartition::ContentType() const 554 { 555 return fPartitionData.content_type; 556 } 557 558 // PartitionData 559 partition_data * 560 KPartition::PartitionData() 561 { 562 return &fPartitionData; 563 } 564 565 // PartitionData 566 const partition_data * 567 KPartition::PartitionData() const 568 { 569 return &fPartitionData; 570 } 571 572 // SetID 573 void 574 KPartition::SetID(partition_id id) 575 { 576 if (fPartitionData.id != id) { 577 fPartitionData.id = id; 578 FireIDChanged(id); 579 } 580 } 581 582 // ID 583 partition_id 584 KPartition::ID() const 585 { 586 return fPartitionData.id; 587 } 588 589 // GetPath 590 status_t 591 KPartition::GetPath(KPath *path) const 592 { 593 // For a KDiskDevice this version is never invoked, so the check for 594 // Parent() is correct. 595 if (!path || path->InitCheck() != B_OK || !Parent() || Index() < 0) 596 return B_BAD_VALUE; 597 // get the parent's path 598 status_t error = Parent()->GetPath(path); 599 if (error != B_OK) 600 return error; 601 if (Parent()->IsDevice()) { 602 // Our parent is a device, so we replace `raw' by our index. 603 const char *leaf = path->Leaf(); 604 if (!leaf || strcmp(leaf, "raw") != B_OK) 605 return B_ERROR; 606 #ifdef _KERNEL_MODE 607 char indexBuffer[12]; 608 snprintf(indexBuffer, sizeof(indexBuffer), "%ld", Index()); 609 #else 610 const char *prefix = "haiku_"; 611 char indexBuffer[strlen(prefix) + 12]; 612 snprintf(indexBuffer, sizeof(indexBuffer), "%s%ld", prefix, 613 Index()); 614 #endif 615 error = path->ReplaceLeaf(indexBuffer); 616 } else { 617 // Our parent is a normal partition, no device: Append our index. 618 char indexBuffer[13]; 619 snprintf(indexBuffer, sizeof(indexBuffer), "_%ld", Index()); 620 error = path->Append(indexBuffer, false); 621 } 622 return error; 623 } 624 625 // SetVolumeID 626 void 627 KPartition::SetVolumeID(dev_t volumeID) 628 { 629 if (fPartitionData.volume != volumeID) { 630 fPartitionData.volume = volumeID; 631 FireVolumeIDChanged(volumeID); 632 if (VolumeID() >= 0) 633 AddFlags(B_PARTITION_MOUNTED); 634 else 635 ClearFlags(B_PARTITION_MOUNTED); 636 } 637 } 638 639 // VolumeID 640 dev_t 641 KPartition::VolumeID() const 642 { 643 return fPartitionData.volume; 644 } 645 646 // SetMountCookie 647 void 648 KPartition::SetMountCookie(void *cookie) 649 { 650 if (fPartitionData.mount_cookie != cookie) { 651 fPartitionData.mount_cookie = cookie; 652 FireMountCookieChanged(cookie); 653 } 654 } 655 656 // MountCookie 657 void * 658 KPartition::MountCookie() const 659 { 660 return fPartitionData.mount_cookie; 661 } 662 663 // Mount 664 status_t 665 KPartition::Mount(uint32 mountFlags, const char *parameters) 666 { 667 // not implemented 668 return B_ERROR; 669 } 670 671 // Unmount 672 status_t 673 KPartition::Unmount() 674 { 675 // not implemented 676 return B_ERROR; 677 } 678 679 // SetParameters 680 status_t 681 KPartition::SetParameters(const char *parameters) 682 { 683 status_t error = set_string(fPartitionData.parameters, parameters); 684 FireParametersChanged(fPartitionData.parameters); 685 return error; 686 } 687 688 // Parameters 689 const char * 690 KPartition::Parameters() const 691 { 692 return fPartitionData.parameters; 693 } 694 695 // SetContentParameters 696 status_t 697 KPartition::SetContentParameters(const char *parameters) 698 { 699 status_t error = set_string(fPartitionData.content_parameters, parameters); 700 FireContentParametersChanged(fPartitionData.content_parameters); 701 return error; 702 } 703 704 // ContentParameters 705 const char * 706 KPartition::ContentParameters() const 707 { 708 return fPartitionData.content_parameters; 709 } 710 711 // SetDevice 712 void 713 KPartition::SetDevice(KDiskDevice *device) 714 { 715 fDevice = device; 716 if (fDevice && fDevice->IsReadOnlyMedia()) 717 AddFlags(B_PARTITION_READ_ONLY); 718 } 719 720 // Device 721 KDiskDevice * 722 KPartition::Device() const 723 { 724 return fDevice; 725 } 726 727 // SetParent 728 void 729 KPartition::SetParent(KPartition *parent) 730 { 731 // Must be called in a {Add,Remove}Child() only! 732 fParent = parent; 733 } 734 735 // Parent 736 KPartition * 737 KPartition::Parent() const 738 { 739 return fParent; 740 } 741 742 // AddChild 743 status_t 744 KPartition::AddChild(KPartition *partition, int32 index) 745 { 746 // check parameters 747 int32 count = fPartitionData.child_count; 748 if (index == -1) 749 index = count; 750 if (index < 0 || index > count || !partition) 751 return B_BAD_VALUE; 752 // add partition 753 KDiskDeviceManager *manager = KDiskDeviceManager::Default(); 754 if (ManagerLocker locker = manager) { 755 status_t error = fChildren.Insert(partition, index); 756 if (error != B_OK) 757 return error; 758 if (!manager->PartitionAdded(partition)) { 759 fChildren.Erase(index); 760 return B_NO_MEMORY; 761 } 762 partition->SetIndex(index); 763 _UpdateChildIndices(index); 764 fPartitionData.child_count++; 765 partition->SetParent(this); 766 partition->SetDevice(Device()); 767 // notify listeners 768 FireChildAdded(partition, index); 769 return B_OK; 770 } 771 return B_ERROR; 772 } 773 774 775 // CreateChild 776 status_t 777 KPartition::CreateChild(partition_id id, int32 index, KPartition **_child) 778 { 779 // check parameters 780 int32 count = fPartitionData.child_count; 781 if (index == -1) 782 index = count; 783 if (index < 0 || index > count) 784 return B_BAD_VALUE; 785 786 // create and add partition 787 KPartition *child = new(nothrow) KPartition(id); 788 if (!child) 789 return B_NO_MEMORY; 790 791 status_t error = AddChild(child, index); 792 793 // cleanup / set result 794 if (error != B_OK) 795 delete child; 796 else if (_child) 797 *_child = child; 798 799 return error; 800 } 801 802 803 // RemoveChild 804 bool 805 KPartition::RemoveChild(int32 index) 806 { 807 if (index < 0 || index >= fPartitionData.child_count) 808 return false; 809 KDiskDeviceManager *manager = KDiskDeviceManager::Default(); 810 if (ManagerLocker locker = manager) { 811 KPartition *partition = fChildren.ElementAt(index); 812 PartitionRegistrar _(partition); 813 if (!partition || !manager->PartitionRemoved(partition) 814 || !fChildren.Erase(index)) { 815 return false; 816 } 817 _UpdateChildIndices(index + 1); 818 partition->SetIndex(-1); 819 fPartitionData.child_count--; 820 partition->SetParent(NULL); 821 partition->SetDevice(NULL); 822 // notify listeners 823 FireChildRemoved(partition, index); 824 return true; 825 } 826 return false; 827 } 828 829 // RemoveChild 830 bool 831 KPartition::RemoveChild(KPartition *child) 832 { 833 if (child) { 834 int32 index = fChildren.IndexOf(child); 835 if (index >= 0) 836 return RemoveChild(index); 837 } 838 return false; 839 } 840 841 // RemoveAllChildren 842 bool 843 KPartition::RemoveAllChildren() 844 { 845 int32 count = CountChildren(); 846 for (int32 i = count - 1; i >= 0; i--) { 847 if (!RemoveChild(i)) 848 return false; 849 } 850 return true; 851 } 852 853 // ChildAt 854 KPartition * 855 KPartition::ChildAt(int32 index) const 856 { 857 return (index >= 0 && index < fChildren.Count() 858 ? fChildren.ElementAt(index) : NULL); 859 } 860 861 // CountChildren 862 int32 863 KPartition::CountChildren() const 864 { 865 return fPartitionData.child_count; 866 } 867 868 // CountDescendants 869 int32 870 KPartition::CountDescendants() const 871 { 872 int32 count = 1; 873 for (int32 i = 0; KPartition *child = ChildAt(i); i++) 874 count += child->CountDescendants(); 875 return count; 876 } 877 878 // VisitEachDescendant 879 KPartition * 880 KPartition::VisitEachDescendant(KPartitionVisitor *visitor) 881 { 882 if (!visitor) 883 return NULL; 884 if (visitor->VisitPre(this)) 885 return this; 886 for (int32 i = 0; KPartition *child = ChildAt(i); i++) { 887 if (KPartition *result = child->VisitEachDescendant(visitor)) 888 return result; 889 } 890 if (visitor->VisitPost(this)) 891 return this; 892 return NULL; 893 } 894 895 896 // SetDiskSystem 897 void 898 KPartition::SetDiskSystem(KDiskSystem *diskSystem) 899 { 900 // unload former disk system 901 if (fDiskSystem) { 902 fPartitionData.content_type = NULL; 903 fDiskSystem->Unload(); 904 fDiskSystem = NULL; 905 } 906 // set and load new one 907 fDiskSystem = diskSystem; 908 if (fDiskSystem) 909 fDiskSystem->Load(); // can't fail, since it's already loaded 910 // update concerned partition flags 911 if (fDiskSystem) { 912 fPartitionData.content_type = fDiskSystem->PrettyName(); 913 if (fDiskSystem->IsFileSystem()) 914 AddFlags(B_PARTITION_FILE_SYSTEM); 915 else 916 AddFlags(B_PARTITION_PARTITIONING_SYSTEM); 917 } 918 // notify listeners 919 FireDiskSystemChanged(fDiskSystem); 920 } 921 922 // DiskSystem 923 KDiskSystem * 924 KPartition::DiskSystem() const 925 { 926 return fDiskSystem; 927 } 928 929 // ParentDiskSystem 930 KDiskSystem * 931 KPartition::ParentDiskSystem() const 932 { 933 return (Parent() ? Parent()->DiskSystem() : NULL); 934 } 935 936 // SetCookie 937 void 938 KPartition::SetCookie(void *cookie) 939 { 940 if (fPartitionData.cookie != cookie) { 941 fPartitionData.cookie = cookie; 942 FireCookieChanged(cookie); 943 } 944 } 945 946 // Cookie 947 void * 948 KPartition::Cookie() const 949 { 950 return fPartitionData.cookie; 951 } 952 953 // SetContentCookie 954 void 955 KPartition::SetContentCookie(void *cookie) 956 { 957 if (fPartitionData.content_cookie != cookie) { 958 fPartitionData.content_cookie = cookie; 959 FireContentCookieChanged(cookie); 960 } 961 } 962 963 // ContentCookie 964 void * 965 KPartition::ContentCookie() const 966 { 967 return fPartitionData.content_cookie; 968 } 969 970 // AddListener 971 bool 972 KPartition::AddListener(KPartitionListener *listener) 973 { 974 if (!listener) 975 return false; 976 // lazy create listeners 977 if (!fListeners) { 978 fListeners = new(nothrow) ListenerSet; 979 if (!fListeners) 980 return false; 981 } 982 // add listener 983 return (fListeners->Insert(listener) == B_OK); 984 } 985 986 // RemoveListener 987 bool 988 KPartition::RemoveListener(KPartitionListener *listener) 989 { 990 if (!listener || !fListeners) 991 return false; 992 // remove listener and delete the set, if empty now 993 bool result = (fListeners->Remove(listener) > 0); 994 if (fListeners->IsEmpty()) { 995 delete fListeners; 996 fListeners = NULL; 997 } 998 return result; 999 } 1000 1001 // Changed 1002 void 1003 KPartition::Changed(uint32 flags, uint32 clearFlags) 1004 { 1005 fChangeFlags &= ~clearFlags; 1006 fChangeFlags |= flags; 1007 fChangeCounter++; 1008 if (Parent()) 1009 Parent()->Changed(B_PARTITION_CHANGED_DESCENDANTS); 1010 } 1011 1012 // SetChangeFlags 1013 void 1014 KPartition::SetChangeFlags(uint32 flags) 1015 { 1016 fChangeFlags = flags; 1017 } 1018 1019 // ChangeFlags 1020 uint32 1021 KPartition::ChangeFlags() const 1022 { 1023 return fChangeFlags; 1024 } 1025 1026 // ChangeCounter 1027 int32 1028 KPartition::ChangeCounter() const 1029 { 1030 return fChangeCounter; 1031 } 1032 1033 1034 // UninitializeContents 1035 status_t 1036 KPartition::UninitializeContents(bool logChanges) 1037 { 1038 if (DiskSystem()) { 1039 uint32 flags = B_PARTITION_CHANGED_INITIALIZATION 1040 | B_PARTITION_CHANGED_CONTENT_TYPE 1041 | B_PARTITION_CHANGED_STATUS 1042 | B_PARTITION_CHANGED_FLAGS; 1043 1044 // children 1045 if (CountChildren() > 0) { 1046 if (!RemoveAllChildren()) 1047 return B_ERROR; 1048 flags |= B_PARTITION_CHANGED_CHILDREN; 1049 } 1050 1051 // volume 1052 if (VolumeID() >= 0) { 1053 status_t error = vfs_unmount(VolumeID(), 1054 B_FORCE_UNMOUNT | B_UNMOUNT_BUSY_PARTITION); 1055 if (error != B_OK) { 1056 dprintf("KPartition::UninitializeContents(): Failed to unmount " 1057 "device %ld: %s\n", VolumeID(), strerror(error)); 1058 } 1059 1060 SetVolumeID(-1); 1061 flags |= B_PARTITION_CHANGED_VOLUME; 1062 } 1063 1064 // content name 1065 if (ContentName()) { 1066 SetContentName(NULL); 1067 flags |= B_PARTITION_CHANGED_CONTENT_NAME; 1068 } 1069 1070 // content parameters 1071 if (ContentParameters()) { 1072 SetContentParameters(NULL); 1073 flags |= B_PARTITION_CHANGED_CONTENT_PARAMETERS; 1074 } 1075 1076 // content size 1077 if (ContentSize() > 0) { 1078 SetContentSize(0); 1079 flags |= B_PARTITION_CHANGED_CONTENT_SIZE; 1080 } 1081 1082 // block size 1083 if (Parent() && Parent()->BlockSize() != BlockSize()) { 1084 SetBlockSize(Parent()->BlockSize()); 1085 flags |= B_PARTITION_CHANGED_BLOCK_SIZE; 1086 } 1087 1088 // disk system 1089 DiskSystem()->FreeContentCookie(this); 1090 SetDiskSystem(NULL); 1091 1092 // status 1093 SetStatus(B_PARTITION_UNINITIALIZED); 1094 1095 // flags 1096 ClearFlags(B_PARTITION_FILE_SYSTEM | B_PARTITION_PARTITIONING_SYSTEM); 1097 if (!Device()->IsReadOnlyMedia()) 1098 ClearFlags(B_PARTITION_READ_ONLY); 1099 1100 // log changes 1101 if (logChanges) { 1102 Changed(flags, B_PARTITION_CHANGED_DEFRAGMENTATION 1103 | B_PARTITION_CHANGED_CHECK | B_PARTITION_CHANGED_REPAIR); 1104 } 1105 } 1106 1107 return B_OK; 1108 } 1109 1110 1111 // SetAlgorithmData 1112 void 1113 KPartition::SetAlgorithmData(uint32 data) 1114 { 1115 fAlgorithmData = data; 1116 } 1117 1118 // AlgorithmData 1119 uint32 1120 KPartition::AlgorithmData() const 1121 { 1122 return fAlgorithmData; 1123 } 1124 1125 // WriteUserData 1126 void 1127 KPartition::WriteUserData(UserDataWriter &writer, user_partition_data *data) 1128 { 1129 // allocate 1130 char *name = writer.PlaceString(Name()); 1131 char *contentName = writer.PlaceString(ContentName()); 1132 char *type = writer.PlaceString(Type()); 1133 char *contentType = writer.PlaceString(ContentType()); 1134 char *parameters = writer.PlaceString(Parameters()); 1135 char *contentParameters = writer.PlaceString(ContentParameters()); 1136 // fill in data 1137 if (data) { 1138 data->id = ID(); 1139 data->offset = Offset(); 1140 data->size = Size(); 1141 data->content_size = ContentSize(); 1142 data->block_size = BlockSize(); 1143 data->status = Status(); 1144 data->flags = Flags(); 1145 data->volume = VolumeID(); 1146 data->index = Index(); 1147 data->change_counter = ChangeCounter(); 1148 data->disk_system = (DiskSystem() ? DiskSystem()->ID() : -1); 1149 data->name = name; 1150 data->content_name = contentName; 1151 data->type = type; 1152 data->content_type = contentType; 1153 data->parameters = parameters; 1154 data->content_parameters = contentParameters; 1155 data->child_count = CountChildren(); 1156 // make buffer relocatable 1157 writer.AddRelocationEntry(&data->name); 1158 writer.AddRelocationEntry(&data->content_name); 1159 writer.AddRelocationEntry(&data->type); 1160 writer.AddRelocationEntry(&data->content_type); 1161 writer.AddRelocationEntry(&data->parameters); 1162 writer.AddRelocationEntry(&data->content_parameters); 1163 } 1164 // children 1165 for (int32 i = 0; KPartition *child = ChildAt(i); i++) { 1166 user_partition_data *childData 1167 = writer.AllocatePartitionData(child->CountChildren()); 1168 if (data) { 1169 data->children[i] = childData; 1170 writer.AddRelocationEntry(&data->children[i]); 1171 } 1172 child->WriteUserData(writer, childData); 1173 } 1174 } 1175 1176 // Dump 1177 void 1178 KPartition::Dump(bool deep, int32 level) 1179 { 1180 if (level < 0 || level > 255) 1181 return; 1182 char prefix[256]; 1183 sprintf(prefix, "%*s%*s", (int)level, "", (int)level, ""); 1184 KPath path; 1185 GetPath(&path); 1186 if (level > 0) 1187 OUT("%spartition %ld: %s\n", prefix, ID(), path.Path()); 1188 OUT("%s offset: %lld\n", prefix, Offset()); 1189 OUT("%s size: %lld (%.2f MB)\n", prefix, Size(), Size() / (1024.0*1024)); 1190 OUT("%s content size: %lld\n", prefix, ContentSize()); 1191 OUT("%s block size: %lu\n", prefix, BlockSize()); 1192 OUT("%s child count: %ld\n", prefix, CountChildren()); 1193 OUT("%s index: %ld\n", prefix, Index()); 1194 OUT("%s status: %lu\n", prefix, Status()); 1195 OUT("%s flags: %lx\n", prefix, Flags()); 1196 OUT("%s volume: %ld\n", prefix, VolumeID()); 1197 OUT("%s disk system: %s\n", prefix, 1198 (DiskSystem() ? DiskSystem()->Name() : NULL)); 1199 OUT("%s name: %s\n", prefix, Name()); 1200 OUT("%s content name: %s\n", prefix, ContentName()); 1201 OUT("%s type: %s\n", prefix, Type()); 1202 OUT("%s content type: %s\n", prefix, ContentType()); 1203 OUT("%s params: %s\n", prefix, Parameters()); 1204 OUT("%s content params: %s\n", prefix, ContentParameters()); 1205 if (deep) { 1206 for (int32 i = 0; KPartition *child = ChildAt(i); i++) 1207 child->Dump(true, level + 1); 1208 } 1209 } 1210 1211 // FireOffsetChanged 1212 void 1213 KPartition::FireOffsetChanged(off_t offset) 1214 { 1215 if (fListeners) { 1216 for (ListenerSet::Iterator it = fListeners->Begin(); 1217 it != fListeners->End(); ++it) { 1218 (*it)->OffsetChanged(this, offset); 1219 } 1220 } 1221 } 1222 1223 // FireSizeChanged 1224 void 1225 KPartition::FireSizeChanged(off_t size) 1226 { 1227 if (fListeners) { 1228 for (ListenerSet::Iterator it = fListeners->Begin(); 1229 it != fListeners->End(); ++it) { 1230 (*it)->SizeChanged(this, size); 1231 } 1232 } 1233 } 1234 1235 // FireContentSizeChanged 1236 void 1237 KPartition::FireContentSizeChanged(off_t size) 1238 { 1239 if (fListeners) { 1240 for (ListenerSet::Iterator it = fListeners->Begin(); 1241 it != fListeners->End(); ++it) { 1242 (*it)->ContentSizeChanged(this, size); 1243 } 1244 } 1245 } 1246 1247 // FireBlockSizeChanged 1248 void 1249 KPartition::FireBlockSizeChanged(uint32 blockSize) 1250 { 1251 if (fListeners) { 1252 for (ListenerSet::Iterator it = fListeners->Begin(); 1253 it != fListeners->End(); ++it) { 1254 (*it)->BlockSizeChanged(this, blockSize); 1255 } 1256 } 1257 } 1258 1259 // FireIndexChanged 1260 void 1261 KPartition::FireIndexChanged(int32 index) 1262 { 1263 if (fListeners) { 1264 for (ListenerSet::Iterator it = fListeners->Begin(); 1265 it != fListeners->End(); ++it) { 1266 (*it)->IndexChanged(this, index); 1267 } 1268 } 1269 } 1270 1271 // FireStatusChanged 1272 void 1273 KPartition::FireStatusChanged(uint32 status) 1274 { 1275 if (fListeners) { 1276 for (ListenerSet::Iterator it = fListeners->Begin(); 1277 it != fListeners->End(); ++it) { 1278 (*it)->StatusChanged(this, status); 1279 } 1280 } 1281 } 1282 1283 // FireFlagsChanged 1284 void 1285 KPartition::FireFlagsChanged(uint32 flags) 1286 { 1287 if (fListeners) { 1288 for (ListenerSet::Iterator it = fListeners->Begin(); 1289 it != fListeners->End(); ++it) { 1290 (*it)->FlagsChanged(this, flags); 1291 } 1292 } 1293 } 1294 1295 // FireNameChanged 1296 void 1297 KPartition::FireNameChanged(const char *name) 1298 { 1299 if (fListeners) { 1300 for (ListenerSet::Iterator it = fListeners->Begin(); 1301 it != fListeners->End(); ++it) { 1302 (*it)->NameChanged(this, name); 1303 } 1304 } 1305 } 1306 1307 // FireContentNameChanged 1308 void 1309 KPartition::FireContentNameChanged(const char *name) 1310 { 1311 if (fListeners) { 1312 for (ListenerSet::Iterator it = fListeners->Begin(); 1313 it != fListeners->End(); ++it) { 1314 (*it)->ContentNameChanged(this, name); 1315 } 1316 } 1317 } 1318 1319 // FireTypeChanged 1320 void 1321 KPartition::FireTypeChanged(const char *type) 1322 { 1323 if (fListeners) { 1324 for (ListenerSet::Iterator it = fListeners->Begin(); 1325 it != fListeners->End(); ++it) { 1326 (*it)->TypeChanged(this, type); 1327 } 1328 } 1329 } 1330 1331 // FireIDChanged 1332 void 1333 KPartition::FireIDChanged(partition_id id) 1334 { 1335 if (fListeners) { 1336 for (ListenerSet::Iterator it = fListeners->Begin(); 1337 it != fListeners->End(); ++it) { 1338 (*it)->IDChanged(this, id); 1339 } 1340 } 1341 } 1342 1343 // FireVolumeIDChanged 1344 void 1345 KPartition::FireVolumeIDChanged(dev_t volumeID) 1346 { 1347 if (fListeners) { 1348 for (ListenerSet::Iterator it = fListeners->Begin(); 1349 it != fListeners->End(); ++it) { 1350 (*it)->VolumeIDChanged(this, volumeID); 1351 } 1352 } 1353 } 1354 1355 // FireMountCookieChanged 1356 void 1357 KPartition::FireMountCookieChanged(void *cookie) 1358 { 1359 if (fListeners) { 1360 for (ListenerSet::Iterator it = fListeners->Begin(); 1361 it != fListeners->End(); ++it) { 1362 (*it)->MountCookieChanged(this, cookie); 1363 } 1364 } 1365 } 1366 1367 // FireParametersChanged 1368 void 1369 KPartition::FireParametersChanged(const char *parameters) 1370 { 1371 if (fListeners) { 1372 for (ListenerSet::Iterator it = fListeners->Begin(); 1373 it != fListeners->End(); ++it) { 1374 (*it)->ParametersChanged(this, parameters); 1375 } 1376 } 1377 } 1378 1379 // FireContentParametersChanged 1380 void 1381 KPartition::FireContentParametersChanged(const char *parameters) 1382 { 1383 if (fListeners) { 1384 for (ListenerSet::Iterator it = fListeners->Begin(); 1385 it != fListeners->End(); ++it) { 1386 (*it)->ContentParametersChanged(this, parameters); 1387 } 1388 } 1389 } 1390 1391 // FireChildAdded 1392 void 1393 KPartition::FireChildAdded(KPartition *child, int32 index) 1394 { 1395 if (fListeners) { 1396 for (ListenerSet::Iterator it = fListeners->Begin(); 1397 it != fListeners->End(); ++it) { 1398 (*it)->ChildAdded(this, child, index); 1399 } 1400 } 1401 } 1402 1403 // FireChildRemoved 1404 void 1405 KPartition::FireChildRemoved(KPartition *child, int32 index) 1406 { 1407 if (fListeners) { 1408 for (ListenerSet::Iterator it = fListeners->Begin(); 1409 it != fListeners->End(); ++it) { 1410 (*it)->ChildRemoved(this, child, index); 1411 } 1412 } 1413 } 1414 1415 // FireDiskSystemChanged 1416 void 1417 KPartition::FireDiskSystemChanged(KDiskSystem *diskSystem) 1418 { 1419 if (fListeners) { 1420 for (ListenerSet::Iterator it = fListeners->Begin(); 1421 it != fListeners->End(); ++it) { 1422 (*it)->DiskSystemChanged(this, diskSystem); 1423 } 1424 } 1425 } 1426 1427 // FireCookieChanged 1428 void 1429 KPartition::FireCookieChanged(void *cookie) 1430 { 1431 if (fListeners) { 1432 for (ListenerSet::Iterator it = fListeners->Begin(); 1433 it != fListeners->End(); ++it) { 1434 (*it)->CookieChanged(this, cookie); 1435 } 1436 } 1437 } 1438 1439 // FireContentCookieChanged 1440 void 1441 KPartition::FireContentCookieChanged(void *cookie) 1442 { 1443 if (fListeners) { 1444 for (ListenerSet::Iterator it = fListeners->Begin(); 1445 it != fListeners->End(); ++it) { 1446 (*it)->ContentCookieChanged(this, cookie); 1447 } 1448 } 1449 } 1450 1451 // _UpdateChildIndices 1452 void 1453 KPartition::_UpdateChildIndices(int32 index) 1454 { 1455 for (int32 i = index; i < fChildren.Count(); i++) 1456 fChildren.ElementAt(i)->SetIndex(i); 1457 } 1458 1459 // _NextID 1460 int32 1461 KPartition::_NextID() 1462 { 1463 return atomic_add(&fNextID, 1); 1464 } 1465 1466 1467 // fNextID 1468 int32 KPartition::fNextID = 0; 1469 1470