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