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