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