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 40using namespace std; 41 42 43// debugging 44//#define DBG(x) 45#define DBG(x) x 46#define OUT dprintf 47 48 49struct KPartition::ListenerSet : VectorSet<KPartitionListener*> {}; 50 51 52int32 KPartition::sNextID = 0; 53 54 55KPartition::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 94KPartition::~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 106void 107KPartition::Register() 108{ 109 fReferenceCount++; 110} 111 112 113void 114KPartition::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 126int32 127KPartition::CountReferences() const 128{ 129 return fReferenceCount; 130} 131 132 133void 134KPartition::MarkObsolete() 135{ 136 fObsolete = true; 137} 138 139 140bool 141KPartition::IsObsolete() const 142{ 143 return fObsolete; 144} 145 146 147bool 148KPartition::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 161bool 162KPartition::PrepareForDeletion() 163{ 164 return true; 165} 166 167 168status_t 169KPartition::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 189status_t 190KPartition::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 231status_t 232KPartition::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 259status_t 260KPartition::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 301bool 302KPartition::IsPublished() const 303{ 304 return fPublishedName != NULL; 305} 306 307 308void 309KPartition::SetBusy(bool busy) 310{ 311 if (busy) 312 AddFlags(B_PARTITION_BUSY); 313 else 314 ClearFlags(B_PARTITION_BUSY); 315} 316 317 318bool 319KPartition::IsBusy() const 320{ 321 return (fPartitionData.flags & B_PARTITION_BUSY) != 0; 322} 323 324 325bool 326KPartition::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 342bool 343KPartition::CheckAndMarkBusy(bool includeDescendants) 344{ 345 if (IsBusy(includeDescendants)) 346 return false; 347 348 MarkBusy(includeDescendants); 349 350 return true; 351} 352 353 354void 355KPartition::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 372void 373KPartition::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 390void 391KPartition::SetOffset(off_t offset) 392{ 393 if (fPartitionData.offset != offset) { 394 fPartitionData.offset = offset; 395 FireOffsetChanged(offset); 396 } 397} 398 399 400off_t 401KPartition::Offset() const 402{ 403 return fPartitionData.offset; 404} 405 406 407void 408KPartition::SetSize(off_t size) 409{ 410 if (fPartitionData.size != size) { 411 fPartitionData.size = size; 412 FireSizeChanged(size); 413 } 414} 415 416 417off_t 418KPartition::Size() const 419{ 420 return fPartitionData.size; 421} 422 423 424void 425KPartition::SetContentSize(off_t size) 426{ 427 if (fPartitionData.content_size != size) { 428 fPartitionData.content_size = size; 429 FireContentSizeChanged(size); 430 } 431} 432 433 434off_t 435KPartition::ContentSize() const 436{ 437 return fPartitionData.content_size; 438} 439 440 441void 442KPartition::SetBlockSize(uint32 blockSize) 443{ 444 if (fPartitionData.block_size != blockSize) { 445 fPartitionData.block_size = blockSize; 446 FireBlockSizeChanged(blockSize); 447 } 448} 449 450 451uint32 452KPartition::BlockSize() const 453{ 454 return fPartitionData.block_size; 455} 456 457 458uint32 459KPartition::PhysicalBlockSize() const 460{ 461 return fPartitionData.physical_block_size; 462} 463 464 465void 466KPartition::SetPhysicalBlockSize(uint32 blockSize) 467{ 468 if (fPartitionData.physical_block_size != blockSize) 469 fPartitionData.physical_block_size = blockSize; 470} 471 472 473void 474KPartition::SetIndex(int32 index) 475{ 476 if (fPartitionData.index != index) { 477 fPartitionData.index = index; 478 FireIndexChanged(index); 479 } 480} 481 482 483int32 484KPartition::Index() const 485{ 486 return fPartitionData.index; 487} 488 489 490void 491KPartition::SetStatus(uint32 status) 492{ 493 if (fPartitionData.status != status) { 494 fPartitionData.status = status; 495 FireStatusChanged(status); 496 } 497} 498 499 500uint32 501KPartition::Status() const 502{ 503 return fPartitionData.status; 504} 505 506 507bool 508KPartition::IsUninitialized() const 509{ 510 return Status() == B_PARTITION_UNINITIALIZED; 511} 512 513 514void 515KPartition::SetFlags(uint32 flags) 516{ 517 if (fPartitionData.flags != flags) { 518 fPartitionData.flags = flags; 519 FireFlagsChanged(flags); 520 } 521} 522 523 524void 525KPartition::AddFlags(uint32 flags) 526{ 527 if (~fPartitionData.flags & flags) { 528 fPartitionData.flags |= flags; 529 FireFlagsChanged(fPartitionData.flags); 530 } 531} 532 533 534void 535KPartition::ClearFlags(uint32 flags) 536{ 537 if (fPartitionData.flags & flags) { 538 fPartitionData.flags &= ~flags; 539 FireFlagsChanged(fPartitionData.flags); 540 } 541} 542 543 544uint32 545KPartition::Flags() const 546{ 547 return fPartitionData.flags; 548} 549 550 551bool 552KPartition::ContainsFileSystem() const 553{ 554 return (fPartitionData.flags & B_PARTITION_FILE_SYSTEM) != 0; 555} 556 557 558bool 559KPartition::ContainsPartitioningSystem() const 560{ 561 return (fPartitionData.flags & B_PARTITION_PARTITIONING_SYSTEM) != 0; 562} 563 564 565bool 566KPartition::IsReadOnly() const 567{ 568 return (fPartitionData.flags & B_PARTITION_READ_ONLY) != 0; 569} 570 571 572bool 573KPartition::IsMounted() const 574{ 575 return (fPartitionData.flags & B_PARTITION_MOUNTED) != 0; 576} 577 578 579bool 580KPartition::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 593bool 594KPartition::IsDevice() const 595{ 596 return (fPartitionData.flags & B_PARTITION_IS_DEVICE) != 0; 597} 598 599 600status_t 601KPartition::SetName(const char* name) 602{ 603 status_t error = set_string(fPartitionData.name, name); 604 FireNameChanged(fPartitionData.name); 605 return error; 606} 607 608 609const char* 610KPartition::Name() const 611{ 612 return fPartitionData.name; 613} 614 615 616status_t 617KPartition::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 625const char* 626KPartition::ContentName() const 627{ 628 return fPartitionData.content_name; 629} 630 631 632status_t 633KPartition::SetType(const char* type) 634{ 635 status_t error = set_string(fPartitionData.type, type); 636 FireTypeChanged(fPartitionData.type); 637 return error; 638} 639 640 641const char* 642KPartition::Type() const 643{ 644 return fPartitionData.type; 645} 646 647 648const char* 649KPartition::ContentType() const 650{ 651 return fPartitionData.content_type; 652} 653 654 655partition_data* 656KPartition::PartitionData() 657{ 658 return &fPartitionData; 659} 660 661 662const partition_data* 663KPartition::PartitionData() const 664{ 665 return &fPartitionData; 666} 667 668 669void 670KPartition::SetID(partition_id id) 671{ 672 if (fPartitionData.id != id) { 673 fPartitionData.id = id; 674 FireIDChanged(id); 675 } 676} 677 678 679partition_id 680KPartition::ID() const 681{ 682 return fPartitionData.id; 683} 684 685 686status_t 687KPartition::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 709status_t 710KPartition::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 732void 733KPartition::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 760dev_t 761KPartition::VolumeID() const 762{ 763 return fPartitionData.volume; 764} 765 766 767void 768KPartition::SetMountCookie(void* cookie) 769{ 770 if (fPartitionData.mount_cookie != cookie) { 771 fPartitionData.mount_cookie = cookie; 772 FireMountCookieChanged(cookie); 773 } 774} 775 776 777void* 778KPartition::MountCookie() const 779{ 780 return fPartitionData.mount_cookie; 781} 782 783 784status_t 785KPartition::Mount(uint32 mountFlags, const char* parameters) 786{ 787 // not implemented 788 return B_ERROR; 789} 790 791 792status_t 793KPartition::Unmount() 794{ 795 // not implemented 796 return B_ERROR; 797} 798 799 800status_t 801KPartition::SetParameters(const char* parameters) 802{ 803 status_t error = set_string(fPartitionData.parameters, parameters); 804 FireParametersChanged(fPartitionData.parameters); 805 return error; 806} 807 808 809const char* 810KPartition::Parameters() const 811{ 812 return fPartitionData.parameters; 813} 814 815 816status_t 817KPartition::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 825const char* 826KPartition::ContentParameters() const 827{ 828 return fPartitionData.content_parameters; 829} 830 831 832void 833KPartition::SetDevice(KDiskDevice* device) 834{ 835 fDevice = device; 836 if (fDevice != NULL && fDevice->IsReadOnlyMedia()) 837 AddFlags(B_PARTITION_READ_ONLY); 838} 839 840 841KDiskDevice* 842KPartition::Device() const 843{ 844 return fDevice; 845} 846 847 848void 849KPartition::SetParent(KPartition* parent) 850{ 851 // Must be called in a {Add,Remove}Child() only! 852 fParent = parent; 853} 854 855 856KPartition* 857KPartition::Parent() const 858{ 859 return fParent; 860} 861 862 863status_t 864KPartition::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 903status_t 904KPartition::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 934bool 935KPartition::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 961bool 962KPartition::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 973bool 974KPartition::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 985KPartition* 986KPartition::ChildAt(int32 index) const 987{ 988 return index >= 0 && index < fChildren.Count() 989 ? fChildren.ElementAt(index) : NULL; 990} 991 992 993int32 994KPartition::CountChildren() const 995{ 996 return fPartitionData.child_count; 997} 998 999 1000int32 1001KPartition::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 1010KPartition* 1011KPartition::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 1027void 1028KPartition::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 1067KDiskSystem* 1068KPartition::DiskSystem() const 1069{ 1070 return fDiskSystem; 1071} 1072 1073 1074float 1075KPartition::DiskSystemPriority() const 1076{ 1077 return fDiskSystemPriority; 1078} 1079 1080 1081KDiskSystem* 1082KPartition::ParentDiskSystem() const 1083{ 1084 return Parent() ? Parent()->DiskSystem() : NULL; 1085} 1086 1087 1088void 1089KPartition::SetCookie(void* cookie) 1090{ 1091 if (fPartitionData.cookie != cookie) { 1092 fPartitionData.cookie = cookie; 1093 FireCookieChanged(cookie); 1094 } 1095} 1096 1097 1098void* 1099KPartition::Cookie() const 1100{ 1101 return fPartitionData.cookie; 1102} 1103 1104 1105void 1106KPartition::SetContentCookie(void* cookie) 1107{ 1108 if (fPartitionData.content_cookie != cookie) { 1109 fPartitionData.content_cookie = cookie; 1110 FireContentCookieChanged(cookie); 1111 } 1112} 1113 1114 1115void* 1116KPartition::ContentCookie() const 1117{ 1118 return fPartitionData.content_cookie; 1119} 1120 1121 1122bool 1123KPartition::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 1138bool 1139KPartition::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 1153void 1154KPartition::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 1164void 1165KPartition::SetChangeFlags(uint32 flags) 1166{ 1167 fChangeFlags = flags; 1168} 1169 1170 1171uint32 1172KPartition::ChangeFlags() const 1173{ 1174 return fChangeFlags; 1175} 1176 1177 1178int32 1179KPartition::ChangeCounter() const 1180{ 1181 return fChangeCounter; 1182} 1183 1184 1185status_t 1186KPartition::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 1261void 1262KPartition::SetAlgorithmData(uint32 data) 1263{ 1264 fAlgorithmData = data; 1265} 1266 1267 1268uint32 1269KPartition::AlgorithmData() const 1270{ 1271 return fAlgorithmData; 1272} 1273 1274 1275void 1276KPartition::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 1327void 1328KPartition::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 1365void 1366KPartition::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 1377void 1378KPartition::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 1389void 1390KPartition::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 1401void 1402KPartition::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 1413void 1414KPartition::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 1425void 1426KPartition::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 1437void 1438KPartition::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 1449void 1450KPartition::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 1461void 1462KPartition::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 1473void 1474KPartition::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 1485void 1486KPartition::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 1497void 1498KPartition::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 1509void 1510KPartition::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 1521void 1522KPartition::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 1533void 1534KPartition::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 1545void 1546KPartition::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 1557void 1558KPartition::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 1569void 1570KPartition::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 1581void 1582KPartition::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 1593void 1594KPartition::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 1605void 1606KPartition::_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 1622int32 1623KPartition::_NextID() 1624{ 1625 return atomic_add(&sNextID, 1); 1626} 1627