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::IsDevice() const 564 { 565 return (fPartitionData.flags & B_PARTITION_IS_DEVICE) != 0; 566 } 567 568 569 status_t 570 KPartition::SetName(const char* name) 571 { 572 status_t error = set_string(fPartitionData.name, name); 573 FireNameChanged(fPartitionData.name); 574 return error; 575 } 576 577 578 const char* 579 KPartition::Name() const 580 { 581 return fPartitionData.name; 582 } 583 584 585 status_t 586 KPartition::SetContentName(const char* name) 587 { 588 status_t error = set_string(fPartitionData.content_name, name); 589 FireContentNameChanged(fPartitionData.content_name); 590 return error; 591 } 592 593 594 const char* 595 KPartition::ContentName() const 596 { 597 return fPartitionData.content_name; 598 } 599 600 601 status_t 602 KPartition::SetType(const char* type) 603 { 604 status_t error = set_string(fPartitionData.type, type); 605 FireTypeChanged(fPartitionData.type); 606 return error; 607 } 608 609 610 const char* 611 KPartition::Type() const 612 { 613 return fPartitionData.type; 614 } 615 616 617 const char* 618 KPartition::ContentType() const 619 { 620 return fPartitionData.content_type; 621 } 622 623 624 partition_data* 625 KPartition::PartitionData() 626 { 627 return &fPartitionData; 628 } 629 630 631 const partition_data* 632 KPartition::PartitionData() const 633 { 634 return &fPartitionData; 635 } 636 637 638 void 639 KPartition::SetID(partition_id id) 640 { 641 if (fPartitionData.id != id) { 642 fPartitionData.id = id; 643 FireIDChanged(id); 644 } 645 } 646 647 648 partition_id 649 KPartition::ID() const 650 { 651 return fPartitionData.id; 652 } 653 654 655 status_t 656 KPartition::GetFileName(char* buffer, size_t size) const 657 { 658 // If the parent is the device, the name is the index of the partition. 659 if (Parent() == NULL || Parent()->IsDevice()) { 660 if (snprintf(buffer, size, "%" B_PRId32, Index()) >= (int)size) 661 return B_NAME_TOO_LONG; 662 return B_OK; 663 } 664 665 // The partition has a non-device parent, so we append the index to the 666 // parent partition's name. 667 status_t error = Parent()->GetFileName(buffer, size); 668 if (error != B_OK) 669 return error; 670 671 size_t len = strlen(buffer); 672 if (snprintf(buffer + len, size - len, "_%" B_PRId32, Index()) >= int(size - len)) 673 return B_NAME_TOO_LONG; 674 return B_OK; 675 } 676 677 678 status_t 679 KPartition::GetPath(KPath* path) const 680 { 681 // For a KDiskDevice this version is never invoked, so the check for 682 // Parent() is correct. 683 if (!path || path->InitCheck() != B_OK || !Parent() || Index() < 0) 684 return B_BAD_VALUE; 685 686 // init the path with the device path 687 status_t error = path->SetPath(Device()->Path()); 688 if (error != B_OK) 689 return error; 690 691 // replace the leaf name with the partition's file name 692 char name[B_FILE_NAME_LENGTH]; 693 error = GetFileName(name, sizeof(name)); 694 if (error == B_OK) 695 error = path->ReplaceLeaf(name); 696 697 return error; 698 } 699 700 701 void 702 KPartition::SetVolumeID(dev_t volumeID) 703 { 704 if (fPartitionData.volume == volumeID) 705 return; 706 707 fPartitionData.volume = volumeID; 708 FireVolumeIDChanged(volumeID); 709 if (VolumeID() >= 0) 710 AddFlags(B_PARTITION_MOUNTED); 711 else 712 ClearFlags(B_PARTITION_MOUNTED); 713 714 KDiskDeviceManager* manager = KDiskDeviceManager::Default(); 715 716 char messageBuffer[512]; 717 KMessage message; 718 message.SetTo(messageBuffer, sizeof(messageBuffer), B_DEVICE_UPDATE); 719 message.AddInt32("event", volumeID >= 0 720 ? B_DEVICE_PARTITION_MOUNTED : B_DEVICE_PARTITION_UNMOUNTED); 721 message.AddInt32("id", ID()); 722 if (volumeID >= 0) 723 message.AddInt32("volume", volumeID); 724 725 manager->Notify(message, B_DEVICE_REQUEST_MOUNTING); 726 } 727 728 729 dev_t 730 KPartition::VolumeID() const 731 { 732 return fPartitionData.volume; 733 } 734 735 736 void 737 KPartition::SetMountCookie(void* cookie) 738 { 739 if (fPartitionData.mount_cookie != cookie) { 740 fPartitionData.mount_cookie = cookie; 741 FireMountCookieChanged(cookie); 742 } 743 } 744 745 746 void* 747 KPartition::MountCookie() const 748 { 749 return fPartitionData.mount_cookie; 750 } 751 752 753 status_t 754 KPartition::Mount(uint32 mountFlags, const char* parameters) 755 { 756 // not implemented 757 return B_ERROR; 758 } 759 760 761 status_t 762 KPartition::Unmount() 763 { 764 // not implemented 765 return B_ERROR; 766 } 767 768 769 status_t 770 KPartition::SetParameters(const char* parameters) 771 { 772 status_t error = set_string(fPartitionData.parameters, parameters); 773 FireParametersChanged(fPartitionData.parameters); 774 return error; 775 } 776 777 778 const char* 779 KPartition::Parameters() const 780 { 781 return fPartitionData.parameters; 782 } 783 784 785 status_t 786 KPartition::SetContentParameters(const char* parameters) 787 { 788 status_t error = set_string(fPartitionData.content_parameters, parameters); 789 FireContentParametersChanged(fPartitionData.content_parameters); 790 return error; 791 } 792 793 794 const char* 795 KPartition::ContentParameters() const 796 { 797 return fPartitionData.content_parameters; 798 } 799 800 801 void 802 KPartition::SetDevice(KDiskDevice* device) 803 { 804 fDevice = device; 805 if (fDevice != NULL && fDevice->IsReadOnlyMedia()) 806 AddFlags(B_PARTITION_READ_ONLY); 807 } 808 809 810 KDiskDevice* 811 KPartition::Device() const 812 { 813 return fDevice; 814 } 815 816 817 void 818 KPartition::SetParent(KPartition* parent) 819 { 820 // Must be called in a {Add,Remove}Child() only! 821 fParent = parent; 822 } 823 824 825 KPartition* 826 KPartition::Parent() const 827 { 828 return fParent; 829 } 830 831 832 status_t 833 KPartition::AddChild(KPartition* partition, int32 index) 834 { 835 // check parameters 836 int32 count = fPartitionData.child_count; 837 if (index == -1) 838 index = count; 839 if (index < 0 || index > count || !partition) 840 return B_BAD_VALUE; 841 842 // add partition 843 KDiskDeviceManager* manager = KDiskDeviceManager::Default(); 844 if (ManagerLocker locker = manager) { 845 status_t error = fChildren.Insert(partition, index); 846 if (error != B_OK) 847 return error; 848 if (!manager->PartitionAdded(partition)) { 849 fChildren.Erase(index); 850 return B_NO_MEMORY; 851 } 852 // update siblings index's 853 partition->SetIndex(index); 854 _UpdateChildIndices(count, index); 855 fPartitionData.child_count++; 856 857 partition->SetParent(this); 858 partition->SetDevice(Device()); 859 860 // publish to devfs 861 partition->PublishDevice(); 862 863 // notify listeners 864 FireChildAdded(partition, index); 865 return B_OK; 866 } 867 return B_ERROR; 868 } 869 870 871 status_t 872 KPartition::CreateChild(partition_id id, int32 index, off_t offset, off_t size, 873 KPartition** _child) 874 { 875 // check parameters 876 int32 count = fPartitionData.child_count; 877 if (index == -1) 878 index = count; 879 if (index < 0 || index > count) 880 return B_BAD_VALUE; 881 882 // create and add partition 883 KPartition* child = new(std::nothrow) KPartition(id); 884 if (child == NULL) 885 return B_NO_MEMORY; 886 887 child->SetOffset(offset); 888 child->SetSize(size); 889 890 status_t error = AddChild(child, index); 891 892 // cleanup / set result 893 if (error != B_OK) 894 delete child; 895 else if (_child) 896 *_child = child; 897 898 return error; 899 } 900 901 902 bool 903 KPartition::RemoveChild(int32 index) 904 { 905 if (index < 0 || index >= fPartitionData.child_count) 906 return false; 907 908 KDiskDeviceManager* manager = KDiskDeviceManager::Default(); 909 if (ManagerLocker locker = manager) { 910 KPartition* partition = fChildren.ElementAt(index); 911 PartitionRegistrar _(partition); 912 if (!partition || !manager->PartitionRemoved(partition) 913 || !fChildren.Erase(index)) { 914 return false; 915 } 916 _UpdateChildIndices(index, fChildren.Count()); 917 partition->SetIndex(-1); 918 fPartitionData.child_count--; 919 partition->SetParent(NULL); 920 partition->SetDevice(NULL); 921 // notify listeners 922 FireChildRemoved(partition, index); 923 return true; 924 } 925 return false; 926 } 927 928 929 bool 930 KPartition::RemoveChild(KPartition* child) 931 { 932 if (child) { 933 int32 index = fChildren.IndexOf(child); 934 if (index >= 0) 935 return RemoveChild(index); 936 } 937 return false; 938 } 939 940 941 bool 942 KPartition::RemoveAllChildren() 943 { 944 int32 count = CountChildren(); 945 for (int32 i = count - 1; i >= 0; i--) { 946 if (!RemoveChild(i)) 947 return false; 948 } 949 return true; 950 } 951 952 953 KPartition* 954 KPartition::ChildAt(int32 index) const 955 { 956 return index >= 0 && index < fChildren.Count() 957 ? fChildren.ElementAt(index) : NULL; 958 } 959 960 961 int32 962 KPartition::CountChildren() const 963 { 964 return fPartitionData.child_count; 965 } 966 967 968 int32 969 KPartition::CountDescendants() const 970 { 971 int32 count = 1; 972 for (int32 i = 0; KPartition* child = ChildAt(i); i++) 973 count += child->CountDescendants(); 974 return count; 975 } 976 977 978 KPartition* 979 KPartition::VisitEachDescendant(KPartitionVisitor* visitor) 980 { 981 if (!visitor) 982 return NULL; 983 if (visitor->VisitPre(this)) 984 return this; 985 for (int32 i = 0; KPartition* child = ChildAt(i); i++) { 986 if (KPartition* result = child->VisitEachDescendant(visitor)) 987 return result; 988 } 989 if (visitor->VisitPost(this)) 990 return this; 991 return NULL; 992 } 993 994 995 void 996 KPartition::SetDiskSystem(KDiskSystem* diskSystem, float priority) 997 { 998 // unload former disk system 999 if (fDiskSystem) { 1000 fPartitionData.content_type = NULL; 1001 fDiskSystem->Unload(); 1002 fDiskSystem = NULL; 1003 fDiskSystemPriority = -1; 1004 } 1005 // set and load new one 1006 fDiskSystem = diskSystem; 1007 if (fDiskSystem) { 1008 fDiskSystem->Load(); 1009 // can't fail, since it's already loaded 1010 } 1011 // update concerned partition flags 1012 if (fDiskSystem) { 1013 fPartitionData.content_type = fDiskSystem->PrettyName(); 1014 fDiskSystemPriority = priority; 1015 if (fDiskSystem->IsFileSystem()) 1016 AddFlags(B_PARTITION_FILE_SYSTEM); 1017 else 1018 AddFlags(B_PARTITION_PARTITIONING_SYSTEM); 1019 } 1020 // notify listeners 1021 FireDiskSystemChanged(fDiskSystem); 1022 1023 KDiskDeviceManager* manager = KDiskDeviceManager::Default(); 1024 1025 char messageBuffer[512]; 1026 KMessage message; 1027 message.SetTo(messageBuffer, sizeof(messageBuffer), B_DEVICE_UPDATE); 1028 message.AddInt32("event", B_DEVICE_PARTITION_INITIALIZED); 1029 message.AddInt32("id", ID()); 1030 1031 manager->Notify(message, B_DEVICE_REQUEST_PARTITION); 1032 } 1033 1034 1035 KDiskSystem* 1036 KPartition::DiskSystem() const 1037 { 1038 return fDiskSystem; 1039 } 1040 1041 1042 float 1043 KPartition::DiskSystemPriority() const 1044 { 1045 return fDiskSystemPriority; 1046 } 1047 1048 1049 KDiskSystem* 1050 KPartition::ParentDiskSystem() const 1051 { 1052 return Parent() ? Parent()->DiskSystem() : NULL; 1053 } 1054 1055 1056 void 1057 KPartition::SetCookie(void* cookie) 1058 { 1059 if (fPartitionData.cookie != cookie) { 1060 fPartitionData.cookie = cookie; 1061 FireCookieChanged(cookie); 1062 } 1063 } 1064 1065 1066 void* 1067 KPartition::Cookie() const 1068 { 1069 return fPartitionData.cookie; 1070 } 1071 1072 1073 void 1074 KPartition::SetContentCookie(void* cookie) 1075 { 1076 if (fPartitionData.content_cookie != cookie) { 1077 fPartitionData.content_cookie = cookie; 1078 FireContentCookieChanged(cookie); 1079 } 1080 } 1081 1082 1083 void* 1084 KPartition::ContentCookie() const 1085 { 1086 return fPartitionData.content_cookie; 1087 } 1088 1089 1090 bool 1091 KPartition::AddListener(KPartitionListener* listener) 1092 { 1093 if (!listener) 1094 return false; 1095 // lazy create listeners 1096 if (!fListeners) { 1097 fListeners = new(nothrow) ListenerSet; 1098 if (!fListeners) 1099 return false; 1100 } 1101 // add listener 1102 return fListeners->Insert(listener) == B_OK; 1103 } 1104 1105 1106 bool 1107 KPartition::RemoveListener(KPartitionListener* listener) 1108 { 1109 if (!listener || !fListeners) 1110 return false; 1111 // remove listener and delete the set, if empty now 1112 bool result = (fListeners->Remove(listener) > 0); 1113 if (fListeners->IsEmpty()) { 1114 delete fListeners; 1115 fListeners = NULL; 1116 } 1117 return result; 1118 } 1119 1120 1121 void 1122 KPartition::Changed(uint32 flags, uint32 clearFlags) 1123 { 1124 fChangeFlags &= ~clearFlags; 1125 fChangeFlags |= flags; 1126 fChangeCounter++; 1127 if (Parent()) 1128 Parent()->Changed(B_PARTITION_CHANGED_DESCENDANTS); 1129 } 1130 1131 1132 void 1133 KPartition::SetChangeFlags(uint32 flags) 1134 { 1135 fChangeFlags = flags; 1136 } 1137 1138 1139 uint32 1140 KPartition::ChangeFlags() const 1141 { 1142 return fChangeFlags; 1143 } 1144 1145 1146 int32 1147 KPartition::ChangeCounter() const 1148 { 1149 return fChangeCounter; 1150 } 1151 1152 1153 status_t 1154 KPartition::UninitializeContents(bool logChanges) 1155 { 1156 if (DiskSystem()) { 1157 uint32 flags = B_PARTITION_CHANGED_INITIALIZATION 1158 | B_PARTITION_CHANGED_CONTENT_TYPE 1159 | B_PARTITION_CHANGED_STATUS 1160 | B_PARTITION_CHANGED_FLAGS; 1161 1162 // children 1163 if (CountChildren() > 0) { 1164 if (!RemoveAllChildren()) 1165 return B_ERROR; 1166 flags |= B_PARTITION_CHANGED_CHILDREN; 1167 } 1168 1169 // volume 1170 if (VolumeID() >= 0) { 1171 status_t error = vfs_unmount(VolumeID(), 1172 B_FORCE_UNMOUNT | B_UNMOUNT_BUSY_PARTITION); 1173 if (error != B_OK) { 1174 dprintf("KPartition::UninitializeContents(): Failed to unmount " 1175 "device %" B_PRIdDEV ": %s\n", VolumeID(), strerror(error)); 1176 } 1177 1178 SetVolumeID(-1); 1179 flags |= B_PARTITION_CHANGED_VOLUME; 1180 } 1181 1182 // content name 1183 if (ContentName()) { 1184 SetContentName(NULL); 1185 flags |= B_PARTITION_CHANGED_CONTENT_NAME; 1186 } 1187 1188 // content parameters 1189 if (ContentParameters()) { 1190 SetContentParameters(NULL); 1191 flags |= B_PARTITION_CHANGED_CONTENT_PARAMETERS; 1192 } 1193 1194 // content size 1195 if (ContentSize() > 0) { 1196 SetContentSize(0); 1197 flags |= B_PARTITION_CHANGED_CONTENT_SIZE; 1198 } 1199 1200 // block size 1201 if (Parent() && Parent()->BlockSize() != BlockSize()) { 1202 SetBlockSize(Parent()->BlockSize()); 1203 flags |= B_PARTITION_CHANGED_BLOCK_SIZE; 1204 } 1205 1206 // disk system 1207 DiskSystem()->FreeContentCookie(this); 1208 SetDiskSystem(NULL); 1209 1210 // status 1211 SetStatus(B_PARTITION_UNINITIALIZED); 1212 1213 // flags 1214 ClearFlags(B_PARTITION_FILE_SYSTEM | B_PARTITION_PARTITIONING_SYSTEM); 1215 if (!Device()->IsReadOnlyMedia()) 1216 ClearFlags(B_PARTITION_READ_ONLY); 1217 1218 // log changes 1219 if (logChanges) { 1220 Changed(flags, B_PARTITION_CHANGED_DEFRAGMENTATION 1221 | B_PARTITION_CHANGED_CHECK | B_PARTITION_CHANGED_REPAIR); 1222 } 1223 } 1224 1225 return B_OK; 1226 } 1227 1228 1229 void 1230 KPartition::SetAlgorithmData(uint32 data) 1231 { 1232 fAlgorithmData = data; 1233 } 1234 1235 1236 uint32 1237 KPartition::AlgorithmData() const 1238 { 1239 return fAlgorithmData; 1240 } 1241 1242 1243 void 1244 KPartition::WriteUserData(UserDataWriter& writer, user_partition_data* data) 1245 { 1246 // allocate 1247 char* name = writer.PlaceString(Name()); 1248 char* contentName = writer.PlaceString(ContentName()); 1249 char* type = writer.PlaceString(Type()); 1250 char* contentType = writer.PlaceString(ContentType()); 1251 char* parameters = writer.PlaceString(Parameters()); 1252 char* contentParameters = writer.PlaceString(ContentParameters()); 1253 // fill in data 1254 if (data) { 1255 data->id = ID(); 1256 data->offset = Offset(); 1257 data->size = Size(); 1258 data->content_size = ContentSize(); 1259 data->block_size = BlockSize(); 1260 data->status = Status(); 1261 data->flags = Flags(); 1262 data->volume = VolumeID(); 1263 data->index = Index(); 1264 data->change_counter = ChangeCounter(); 1265 data->disk_system = (DiskSystem() ? DiskSystem()->ID() : -1); 1266 data->name = name; 1267 data->content_name = contentName; 1268 data->type = type; 1269 data->content_type = contentType; 1270 data->parameters = parameters; 1271 data->content_parameters = contentParameters; 1272 data->child_count = CountChildren(); 1273 // make buffer relocatable 1274 writer.AddRelocationEntry(&data->name); 1275 writer.AddRelocationEntry(&data->content_name); 1276 writer.AddRelocationEntry(&data->type); 1277 writer.AddRelocationEntry(&data->content_type); 1278 writer.AddRelocationEntry(&data->parameters); 1279 writer.AddRelocationEntry(&data->content_parameters); 1280 } 1281 // children 1282 for (int32 i = 0; KPartition* child = ChildAt(i); i++) { 1283 user_partition_data* childData 1284 = writer.AllocatePartitionData(child->CountChildren()); 1285 if (data) { 1286 data->children[i] = childData; 1287 writer.AddRelocationEntry(&data->children[i]); 1288 } 1289 child->WriteUserData(writer, childData); 1290 } 1291 } 1292 1293 1294 void 1295 KPartition::Dump(bool deep, int32 level) 1296 { 1297 if (level < 0 || level > 255) 1298 return; 1299 1300 char prefix[256]; 1301 sprintf(prefix, "%*s%*s", (int)level, "", (int)level, ""); 1302 KPath path; 1303 GetPath(&path); 1304 if (level > 0) 1305 OUT("%spartition %" B_PRId32 ": %s\n", prefix, ID(), path.Path()); 1306 OUT("%s offset: %" B_PRIdOFF "\n", prefix, Offset()); 1307 OUT("%s size: %" B_PRIdOFF " (%.2f MB)\n", prefix, Size(), 1308 Size() / (1024.0*1024)); 1309 OUT("%s content size: %" B_PRIdOFF "\n", prefix, ContentSize()); 1310 OUT("%s block size: %" B_PRIu32 "\n", prefix, BlockSize()); 1311 OUT("%s child count: %" B_PRId32 "\n", prefix, CountChildren()); 1312 OUT("%s index: %" B_PRId32 "\n", prefix, Index()); 1313 OUT("%s status: %" B_PRIu32 "\n", prefix, Status()); 1314 OUT("%s flags: %" B_PRIx32 "\n", prefix, Flags()); 1315 OUT("%s volume: %" B_PRIdDEV "\n", prefix, VolumeID()); 1316 OUT("%s disk system: %s\n", prefix, 1317 (DiskSystem() ? DiskSystem()->Name() : NULL)); 1318 OUT("%s name: %s\n", prefix, Name()); 1319 OUT("%s content name: %s\n", prefix, ContentName()); 1320 OUT("%s type: %s\n", prefix, Type()); 1321 OUT("%s content type: %s\n", prefix, ContentType()); 1322 OUT("%s params: %s\n", prefix, Parameters()); 1323 OUT("%s content params: %s\n", prefix, ContentParameters()); 1324 if (deep) { 1325 for (int32 i = 0; KPartition* child = ChildAt(i); i++) 1326 child->Dump(true, level + 1); 1327 } 1328 } 1329 1330 1331 void 1332 KPartition::FireOffsetChanged(off_t offset) 1333 { 1334 if (fListeners) { 1335 for (ListenerSet::Iterator it = fListeners->Begin(); 1336 it != fListeners->End(); ++it) { 1337 (*it)->OffsetChanged(this, offset); 1338 } 1339 } 1340 } 1341 1342 1343 void 1344 KPartition::FireSizeChanged(off_t size) 1345 { 1346 if (fListeners) { 1347 for (ListenerSet::Iterator it = fListeners->Begin(); 1348 it != fListeners->End(); ++it) { 1349 (*it)->SizeChanged(this, size); 1350 } 1351 } 1352 } 1353 1354 1355 void 1356 KPartition::FireContentSizeChanged(off_t size) 1357 { 1358 if (fListeners) { 1359 for (ListenerSet::Iterator it = fListeners->Begin(); 1360 it != fListeners->End(); ++it) { 1361 (*it)->ContentSizeChanged(this, size); 1362 } 1363 } 1364 } 1365 1366 1367 void 1368 KPartition::FireBlockSizeChanged(uint32 blockSize) 1369 { 1370 if (fListeners) { 1371 for (ListenerSet::Iterator it = fListeners->Begin(); 1372 it != fListeners->End(); ++it) { 1373 (*it)->BlockSizeChanged(this, blockSize); 1374 } 1375 } 1376 } 1377 1378 1379 void 1380 KPartition::FireIndexChanged(int32 index) 1381 { 1382 if (fListeners) { 1383 for (ListenerSet::Iterator it = fListeners->Begin(); 1384 it != fListeners->End(); ++it) { 1385 (*it)->IndexChanged(this, index); 1386 } 1387 } 1388 } 1389 1390 1391 void 1392 KPartition::FireStatusChanged(uint32 status) 1393 { 1394 if (fListeners) { 1395 for (ListenerSet::Iterator it = fListeners->Begin(); 1396 it != fListeners->End(); ++it) { 1397 (*it)->StatusChanged(this, status); 1398 } 1399 } 1400 } 1401 1402 1403 void 1404 KPartition::FireFlagsChanged(uint32 flags) 1405 { 1406 if (fListeners) { 1407 for (ListenerSet::Iterator it = fListeners->Begin(); 1408 it != fListeners->End(); ++it) { 1409 (*it)->FlagsChanged(this, flags); 1410 } 1411 } 1412 } 1413 1414 1415 void 1416 KPartition::FireNameChanged(const char* name) 1417 { 1418 if (fListeners) { 1419 for (ListenerSet::Iterator it = fListeners->Begin(); 1420 it != fListeners->End(); ++it) { 1421 (*it)->NameChanged(this, name); 1422 } 1423 } 1424 } 1425 1426 1427 void 1428 KPartition::FireContentNameChanged(const char* name) 1429 { 1430 if (fListeners) { 1431 for (ListenerSet::Iterator it = fListeners->Begin(); 1432 it != fListeners->End(); ++it) { 1433 (*it)->ContentNameChanged(this, name); 1434 } 1435 } 1436 } 1437 1438 1439 void 1440 KPartition::FireTypeChanged(const char* type) 1441 { 1442 if (fListeners) { 1443 for (ListenerSet::Iterator it = fListeners->Begin(); 1444 it != fListeners->End(); ++it) { 1445 (*it)->TypeChanged(this, type); 1446 } 1447 } 1448 } 1449 1450 1451 void 1452 KPartition::FireIDChanged(partition_id id) 1453 { 1454 if (fListeners) { 1455 for (ListenerSet::Iterator it = fListeners->Begin(); 1456 it != fListeners->End(); ++it) { 1457 (*it)->IDChanged(this, id); 1458 } 1459 } 1460 } 1461 1462 1463 void 1464 KPartition::FireVolumeIDChanged(dev_t volumeID) 1465 { 1466 if (fListeners) { 1467 for (ListenerSet::Iterator it = fListeners->Begin(); 1468 it != fListeners->End(); ++it) { 1469 (*it)->VolumeIDChanged(this, volumeID); 1470 } 1471 } 1472 } 1473 1474 1475 void 1476 KPartition::FireMountCookieChanged(void* cookie) 1477 { 1478 if (fListeners) { 1479 for (ListenerSet::Iterator it = fListeners->Begin(); 1480 it != fListeners->End(); ++it) { 1481 (*it)->MountCookieChanged(this, cookie); 1482 } 1483 } 1484 } 1485 1486 1487 void 1488 KPartition::FireParametersChanged(const char* parameters) 1489 { 1490 if (fListeners) { 1491 for (ListenerSet::Iterator it = fListeners->Begin(); 1492 it != fListeners->End(); ++it) { 1493 (*it)->ParametersChanged(this, parameters); 1494 } 1495 } 1496 } 1497 1498 1499 void 1500 KPartition::FireContentParametersChanged(const char* parameters) 1501 { 1502 if (fListeners) { 1503 for (ListenerSet::Iterator it = fListeners->Begin(); 1504 it != fListeners->End(); ++it) { 1505 (*it)->ContentParametersChanged(this, parameters); 1506 } 1507 } 1508 } 1509 1510 1511 void 1512 KPartition::FireChildAdded(KPartition* child, int32 index) 1513 { 1514 if (fListeners) { 1515 for (ListenerSet::Iterator it = fListeners->Begin(); 1516 it != fListeners->End(); ++it) { 1517 (*it)->ChildAdded(this, child, index); 1518 } 1519 } 1520 } 1521 1522 1523 void 1524 KPartition::FireChildRemoved(KPartition* child, int32 index) 1525 { 1526 if (fListeners) { 1527 for (ListenerSet::Iterator it = fListeners->Begin(); 1528 it != fListeners->End(); ++it) { 1529 (*it)->ChildRemoved(this, child, index); 1530 } 1531 } 1532 } 1533 1534 1535 void 1536 KPartition::FireDiskSystemChanged(KDiskSystem* diskSystem) 1537 { 1538 if (fListeners) { 1539 for (ListenerSet::Iterator it = fListeners->Begin(); 1540 it != fListeners->End(); ++it) { 1541 (*it)->DiskSystemChanged(this, diskSystem); 1542 } 1543 } 1544 } 1545 1546 1547 void 1548 KPartition::FireCookieChanged(void* cookie) 1549 { 1550 if (fListeners) { 1551 for (ListenerSet::Iterator it = fListeners->Begin(); 1552 it != fListeners->End(); ++it) { 1553 (*it)->CookieChanged(this, cookie); 1554 } 1555 } 1556 } 1557 1558 1559 void 1560 KPartition::FireContentCookieChanged(void* cookie) 1561 { 1562 if (fListeners) { 1563 for (ListenerSet::Iterator it = fListeners->Begin(); 1564 it != fListeners->End(); ++it) { 1565 (*it)->ContentCookieChanged(this, cookie); 1566 } 1567 } 1568 } 1569 1570 1571 void 1572 KPartition::_UpdateChildIndices(int32 start, int32 end) 1573 { 1574 if (start < end) { 1575 for (int32 i = start; i < end; i++) { 1576 fChildren.ElementAt(i)->SetIndex(i); 1577 fChildren.ElementAt(i)->RepublishDevice(); 1578 } 1579 } else { 1580 for (int32 i = start; i > end; i--) { 1581 fChildren.ElementAt(i)->SetIndex(i); 1582 fChildren.ElementAt(i)->RepublishDevice(); 1583 } 1584 } 1585 } 1586 1587 1588 int32 1589 KPartition::_NextID() 1590 { 1591 return atomic_add(&sNextID, 1); 1592 } 1593