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