headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / disk_device_manager / KPartition.cpp
blobcfe4263c3a19a7dc4e0212b4f3ee48fe8015bb05
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.
6 * Distributed under the terms of the MIT License.
7 */
10 #include <KPartition.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
18 #include <DiskDeviceRoster.h>
19 #include <Drivers.h>
20 #include <Errors.h>
21 #include <fs_volume.h>
22 #include <KernelExport.h>
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>
37 #include "UserDataWriter.h"
40 using namespace std;
43 // debugging
44 //#define DBG(x)
45 #define DBG(x) x
46 #define OUT dprintf
49 struct KPartition::ListenerSet : VectorSet<KPartitionListener*> {};
52 int32 KPartition::sNextID = 0;
55 KPartition::KPartition(partition_id id)
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)
71 fPartitionData.id = id >= 0 ? id : _NextID();
72 fPartitionData.offset = 0;
73 fPartitionData.size = 0;
74 fPartitionData.content_size = 0;
75 fPartitionData.block_size = 0;
76 fPartitionData.child_count = 0;
77 fPartitionData.index = -1;
78 fPartitionData.status = B_PARTITION_UNRECOGNIZED;
79 fPartitionData.flags = B_PARTITION_BUSY;
80 fPartitionData.volume = -1;
81 fPartitionData.mount_cookie = NULL;
82 fPartitionData.name = NULL;
83 fPartitionData.content_name = NULL;
84 fPartitionData.type = NULL;
85 fPartitionData.content_type = NULL;
86 fPartitionData.parameters = NULL;
87 fPartitionData.content_parameters = NULL;
88 fPartitionData.cookie = NULL;
89 fPartitionData.content_cookie = NULL;
93 KPartition::~KPartition()
95 delete fListeners;
96 SetDiskSystem(NULL);
97 free(fPartitionData.name);
98 free(fPartitionData.content_name);
99 free(fPartitionData.type);
100 free(fPartitionData.parameters);
101 free(fPartitionData.content_parameters);
105 void
106 KPartition::Register()
108 fReferenceCount++;
112 void
113 KPartition::Unregister()
115 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
116 ManagerLocker locker(manager);
117 fReferenceCount--;
118 if (IsObsolete() && fReferenceCount == 0) {
119 // let the manager delete object
120 manager->DeletePartition(this);
125 int32
126 KPartition::CountReferences() const
128 return fReferenceCount;
132 void
133 KPartition::MarkObsolete()
135 fObsolete = true;
139 bool
140 KPartition::IsObsolete() const
142 return fObsolete;
146 bool
147 KPartition::PrepareForRemoval()
149 bool result = RemoveAllChildren();
150 UninitializeContents();
151 UnpublishDevice();
152 if (ParentDiskSystem())
153 ParentDiskSystem()->FreeCookie(this);
154 if (DiskSystem())
155 DiskSystem()->FreeContentCookie(this);
156 return result;
160 bool
161 KPartition::PrepareForDeletion()
163 return true;
167 status_t
168 KPartition::Open(int flags, int* fd)
170 if (!fd)
171 return B_BAD_VALUE;
173 // get the path
174 KPath path;
175 status_t error = GetPath(&path);
176 if (error != B_OK)
177 return error;
179 // open the device
180 *fd = open(path.Path(), flags);
181 if (*fd < 0)
182 return errno;
184 return B_OK;
188 status_t
189 KPartition::PublishDevice()
191 if (fPublishedName)
192 return B_OK;
194 // get the name to publish
195 char buffer[B_FILE_NAME_LENGTH];
196 status_t error = GetFileName(buffer, B_FILE_NAME_LENGTH);
197 if (error != B_OK)
198 return error;
200 // prepare a partition_info
201 partition_info info;
202 info.offset = Offset();
203 info.size = Size();
204 info.logical_block_size = BlockSize();
205 info.session = 0;
206 info.partition = ID();
207 if (strlcpy(info.device, Device()->Path(), sizeof(info.device))
208 >= sizeof(info.device)) {
209 return B_NAME_TOO_LONG;
212 fPublishedName = strdup(buffer);
213 if (!fPublishedName)
214 return B_NO_MEMORY;
216 error = devfs_publish_partition(buffer, &info);
217 if (error != B_OK) {
218 dprintf("KPartition::PublishDevice(): Failed to publish partition "
219 "%" B_PRId32 ": %s\n", ID(), strerror(error));
220 free(fPublishedName);
221 fPublishedName = NULL;
222 return error;
225 return B_OK;
229 status_t
230 KPartition::UnpublishDevice()
232 if (!fPublishedName)
233 return B_OK;
235 // get the path
236 KPath path;
237 status_t error = GetPath(&path);
238 if (error != B_OK) {
239 dprintf("KPartition::UnpublishDevice(): Failed to get path for "
240 "partition %" B_PRId32 ": %s\n", ID(), strerror(error));
241 return error;
244 error = devfs_unpublish_partition(path.Path());
245 if (error != B_OK) {
246 dprintf("KPartition::UnpublishDevice(): Failed to unpublish partition "
247 "%" B_PRId32 ": %s\n", ID(), strerror(error));
250 free(fPublishedName);
251 fPublishedName = NULL;
253 return error;
257 status_t
258 KPartition::RepublishDevice()
260 if (!fPublishedName)
261 return B_OK;
263 char newNameBuffer[B_FILE_NAME_LENGTH];
264 status_t error = GetFileName(newNameBuffer, B_FILE_NAME_LENGTH);
265 if (error != B_OK) {
266 UnpublishDevice();
267 return error;
270 if (strcmp(fPublishedName, newNameBuffer) == 0)
271 return B_OK;
273 for (int i = 0; i < CountChildren(); i++)
274 ChildAt(i)->RepublishDevice();
276 char* newName = strdup(newNameBuffer);
277 if (!newName) {
278 UnpublishDevice();
279 return B_NO_MEMORY;
282 error = devfs_rename_partition(Device()->Path(), fPublishedName, newName);
284 if (error != B_OK) {
285 free(newName);
286 UnpublishDevice();
287 dprintf("KPartition::RepublishDevice(): Failed to republish partition "
288 "%" B_PRId32 ": %s\n", ID(), strerror(error));
289 return error;
292 free(fPublishedName);
293 fPublishedName = newName;
295 return B_OK;
299 bool
300 KPartition::IsPublished() const
302 return fPublishedName != NULL;
306 void
307 KPartition::SetBusy(bool busy)
309 if (busy)
310 AddFlags(B_PARTITION_BUSY);
311 else
312 ClearFlags(B_PARTITION_BUSY);
316 bool
317 KPartition::IsBusy() const
319 return (fPartitionData.flags & B_PARTITION_BUSY) != 0;
323 bool
324 KPartition::IsBusy(bool includeDescendants)
326 if (!includeDescendants)
327 return IsBusy();
329 struct IsBusyVisitor : KPartitionVisitor {
330 virtual bool VisitPre(KPartition* partition)
332 return partition->IsBusy();
334 } checkVisitor;
336 return VisitEachDescendant(&checkVisitor) != NULL;
340 bool
341 KPartition::CheckAndMarkBusy(bool includeDescendants)
343 if (IsBusy(includeDescendants))
344 return false;
346 MarkBusy(includeDescendants);
348 return true;
352 void
353 KPartition::MarkBusy(bool includeDescendants)
355 if (includeDescendants) {
356 struct MarkBusyVisitor : KPartitionVisitor {
357 virtual bool VisitPre(KPartition* partition)
359 partition->AddFlags(B_PARTITION_BUSY);
360 return false;
362 } markVisitor;
364 VisitEachDescendant(&markVisitor);
365 } else
366 SetBusy(true);
370 void
371 KPartition::UnmarkBusy(bool includeDescendants)
373 if (includeDescendants) {
374 struct UnmarkBusyVisitor : KPartitionVisitor {
375 virtual bool VisitPre(KPartition* partition)
377 partition->ClearFlags(B_PARTITION_BUSY);
378 return false;
380 } visitor;
382 VisitEachDescendant(&visitor);
383 } else
384 SetBusy(false);
388 void
389 KPartition::SetOffset(off_t offset)
391 if (fPartitionData.offset != offset) {
392 fPartitionData.offset = offset;
393 FireOffsetChanged(offset);
398 off_t
399 KPartition::Offset() const
401 return fPartitionData.offset;
405 void
406 KPartition::SetSize(off_t size)
408 if (fPartitionData.size != size) {
409 fPartitionData.size = size;
410 FireSizeChanged(size);
415 off_t
416 KPartition::Size() const
418 return fPartitionData.size;
422 void
423 KPartition::SetContentSize(off_t size)
425 if (fPartitionData.content_size != size) {
426 fPartitionData.content_size = size;
427 FireContentSizeChanged(size);
432 off_t
433 KPartition::ContentSize() const
435 return fPartitionData.content_size;
439 void
440 KPartition::SetBlockSize(uint32 blockSize)
442 if (fPartitionData.block_size != blockSize) {
443 fPartitionData.block_size = blockSize;
444 FireBlockSizeChanged(blockSize);
449 uint32
450 KPartition::BlockSize() const
452 return fPartitionData.block_size;
456 void
457 KPartition::SetIndex(int32 index)
459 if (fPartitionData.index != index) {
460 fPartitionData.index = index;
461 FireIndexChanged(index);
466 int32
467 KPartition::Index() const
469 return fPartitionData.index;
473 void
474 KPartition::SetStatus(uint32 status)
476 if (fPartitionData.status != status) {
477 fPartitionData.status = status;
478 FireStatusChanged(status);
483 uint32
484 KPartition::Status() const
486 return fPartitionData.status;
490 bool
491 KPartition::IsUninitialized() const
493 return Status() == B_PARTITION_UNINITIALIZED;
497 void
498 KPartition::SetFlags(uint32 flags)
500 if (fPartitionData.flags != flags) {
501 fPartitionData.flags = flags;
502 FireFlagsChanged(flags);
507 void
508 KPartition::AddFlags(uint32 flags)
510 if (~fPartitionData.flags & flags) {
511 fPartitionData.flags |= flags;
512 FireFlagsChanged(fPartitionData.flags);
517 void
518 KPartition::ClearFlags(uint32 flags)
520 if (fPartitionData.flags & flags) {
521 fPartitionData.flags &= ~flags;
522 FireFlagsChanged(fPartitionData.flags);
527 uint32
528 KPartition::Flags() const
530 return fPartitionData.flags;
534 bool
535 KPartition::ContainsFileSystem() const
537 return (fPartitionData.flags & B_PARTITION_FILE_SYSTEM) != 0;
541 bool
542 KPartition::ContainsPartitioningSystem() const
544 return (fPartitionData.flags & B_PARTITION_PARTITIONING_SYSTEM) != 0;
548 bool
549 KPartition::IsReadOnly() const
551 return (fPartitionData.flags & B_PARTITION_READ_ONLY) != 0;
555 bool
556 KPartition::IsMounted() const
558 return (fPartitionData.flags & B_PARTITION_MOUNTED) != 0;
562 bool
563 KPartition::IsChildMounted()
565 struct IsMountedVisitor : KPartitionVisitor {
566 virtual bool VisitPre(KPartition* partition)
568 return partition->IsMounted();
570 } checkVisitor;
572 return VisitEachDescendant(&checkVisitor) != NULL;
576 bool
577 KPartition::IsDevice() const
579 return (fPartitionData.flags & B_PARTITION_IS_DEVICE) != 0;
583 status_t
584 KPartition::SetName(const char* name)
586 status_t error = set_string(fPartitionData.name, name);
587 FireNameChanged(fPartitionData.name);
588 return error;
592 const char*
593 KPartition::Name() const
595 return fPartitionData.name;
599 status_t
600 KPartition::SetContentName(const char* name)
602 status_t error = set_string(fPartitionData.content_name, name);
603 FireContentNameChanged(fPartitionData.content_name);
604 return error;
608 const char*
609 KPartition::ContentName() const
611 return fPartitionData.content_name;
615 status_t
616 KPartition::SetType(const char* type)
618 status_t error = set_string(fPartitionData.type, type);
619 FireTypeChanged(fPartitionData.type);
620 return error;
624 const char*
625 KPartition::Type() const
627 return fPartitionData.type;
631 const char*
632 KPartition::ContentType() const
634 return fPartitionData.content_type;
638 partition_data*
639 KPartition::PartitionData()
641 return &fPartitionData;
645 const partition_data*
646 KPartition::PartitionData() const
648 return &fPartitionData;
652 void
653 KPartition::SetID(partition_id id)
655 if (fPartitionData.id != id) {
656 fPartitionData.id = id;
657 FireIDChanged(id);
662 partition_id
663 KPartition::ID() const
665 return fPartitionData.id;
669 status_t
670 KPartition::GetFileName(char* buffer, size_t size) const
672 // If the parent is the device, the name is the index of the partition.
673 if (Parent() == NULL || Parent()->IsDevice()) {
674 if (snprintf(buffer, size, "%" B_PRId32, Index()) >= (int)size)
675 return B_NAME_TOO_LONG;
676 return B_OK;
679 // The partition has a non-device parent, so we append the index to the
680 // parent partition's name.
681 status_t error = Parent()->GetFileName(buffer, size);
682 if (error != B_OK)
683 return error;
685 size_t len = strlen(buffer);
686 if (snprintf(buffer + len, size - len, "_%" B_PRId32, Index()) >= int(size - len))
687 return B_NAME_TOO_LONG;
688 return B_OK;
692 status_t
693 KPartition::GetPath(KPath* path) const
695 // For a KDiskDevice this version is never invoked, so the check for
696 // Parent() is correct.
697 if (!path || path->InitCheck() != B_OK || !Parent() || Index() < 0)
698 return B_BAD_VALUE;
700 // init the path with the device path
701 status_t error = path->SetPath(Device()->Path());
702 if (error != B_OK)
703 return error;
705 // replace the leaf name with the partition's file name
706 char name[B_FILE_NAME_LENGTH];
707 error = GetFileName(name, sizeof(name));
708 if (error == B_OK)
709 error = path->ReplaceLeaf(name);
711 return error;
715 void
716 KPartition::SetVolumeID(dev_t volumeID)
718 if (fPartitionData.volume == volumeID)
719 return;
721 fPartitionData.volume = volumeID;
722 FireVolumeIDChanged(volumeID);
723 if (VolumeID() >= 0)
724 AddFlags(B_PARTITION_MOUNTED);
725 else
726 ClearFlags(B_PARTITION_MOUNTED);
728 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
730 char messageBuffer[512];
731 KMessage message;
732 message.SetTo(messageBuffer, sizeof(messageBuffer), B_DEVICE_UPDATE);
733 message.AddInt32("event", volumeID >= 0
734 ? B_DEVICE_PARTITION_MOUNTED : B_DEVICE_PARTITION_UNMOUNTED);
735 message.AddInt32("id", ID());
736 if (volumeID >= 0)
737 message.AddInt32("volume", volumeID);
739 manager->Notify(message, B_DEVICE_REQUEST_MOUNTING);
743 dev_t
744 KPartition::VolumeID() const
746 return fPartitionData.volume;
750 void
751 KPartition::SetMountCookie(void* cookie)
753 if (fPartitionData.mount_cookie != cookie) {
754 fPartitionData.mount_cookie = cookie;
755 FireMountCookieChanged(cookie);
760 void*
761 KPartition::MountCookie() const
763 return fPartitionData.mount_cookie;
767 status_t
768 KPartition::Mount(uint32 mountFlags, const char* parameters)
770 // not implemented
771 return B_ERROR;
775 status_t
776 KPartition::Unmount()
778 // not implemented
779 return B_ERROR;
783 status_t
784 KPartition::SetParameters(const char* parameters)
786 status_t error = set_string(fPartitionData.parameters, parameters);
787 FireParametersChanged(fPartitionData.parameters);
788 return error;
792 const char*
793 KPartition::Parameters() const
795 return fPartitionData.parameters;
799 status_t
800 KPartition::SetContentParameters(const char* parameters)
802 status_t error = set_string(fPartitionData.content_parameters, parameters);
803 FireContentParametersChanged(fPartitionData.content_parameters);
804 return error;
808 const char*
809 KPartition::ContentParameters() const
811 return fPartitionData.content_parameters;
815 void
816 KPartition::SetDevice(KDiskDevice* device)
818 fDevice = device;
819 if (fDevice != NULL && fDevice->IsReadOnlyMedia())
820 AddFlags(B_PARTITION_READ_ONLY);
824 KDiskDevice*
825 KPartition::Device() const
827 return fDevice;
831 void
832 KPartition::SetParent(KPartition* parent)
834 // Must be called in a {Add,Remove}Child() only!
835 fParent = parent;
839 KPartition*
840 KPartition::Parent() const
842 return fParent;
846 status_t
847 KPartition::AddChild(KPartition* partition, int32 index)
849 // check parameters
850 int32 count = fPartitionData.child_count;
851 if (index == -1)
852 index = count;
853 if (index < 0 || index > count || !partition)
854 return B_BAD_VALUE;
856 // add partition
857 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
858 if (ManagerLocker locker = manager) {
859 status_t error = fChildren.Insert(partition, index);
860 if (error != B_OK)
861 return error;
862 if (!manager->PartitionAdded(partition)) {
863 fChildren.Erase(index);
864 return B_NO_MEMORY;
866 // update siblings index's
867 partition->SetIndex(index);
868 _UpdateChildIndices(count, index);
869 fPartitionData.child_count++;
871 partition->SetParent(this);
872 partition->SetDevice(Device());
874 // publish to devfs
875 partition->PublishDevice();
877 // notify listeners
878 FireChildAdded(partition, index);
879 return B_OK;
881 return B_ERROR;
885 status_t
886 KPartition::CreateChild(partition_id id, int32 index, off_t offset, off_t size,
887 KPartition** _child)
889 // check parameters
890 int32 count = fPartitionData.child_count;
891 if (index == -1)
892 index = count;
893 if (index < 0 || index > count)
894 return B_BAD_VALUE;
896 // create and add partition
897 KPartition* child = new(std::nothrow) KPartition(id);
898 if (child == NULL)
899 return B_NO_MEMORY;
901 child->SetOffset(offset);
902 child->SetSize(size);
904 status_t error = AddChild(child, index);
906 // cleanup / set result
907 if (error != B_OK)
908 delete child;
909 else if (_child)
910 *_child = child;
912 return error;
916 bool
917 KPartition::RemoveChild(int32 index)
919 if (index < 0 || index >= fPartitionData.child_count)
920 return false;
922 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
923 if (ManagerLocker locker = manager) {
924 KPartition* partition = fChildren.ElementAt(index);
925 PartitionRegistrar _(partition);
926 if (!partition || !manager->PartitionRemoved(partition)
927 || !fChildren.Erase(index)) {
928 return false;
930 _UpdateChildIndices(index, fChildren.Count());
931 partition->SetIndex(-1);
932 fPartitionData.child_count--;
933 partition->SetParent(NULL);
934 partition->SetDevice(NULL);
935 // notify listeners
936 FireChildRemoved(partition, index);
937 return true;
939 return false;
943 bool
944 KPartition::RemoveChild(KPartition* child)
946 if (child) {
947 int32 index = fChildren.IndexOf(child);
948 if (index >= 0)
949 return RemoveChild(index);
951 return false;
955 bool
956 KPartition::RemoveAllChildren()
958 int32 count = CountChildren();
959 for (int32 i = count - 1; i >= 0; i--) {
960 if (!RemoveChild(i))
961 return false;
963 return true;
967 KPartition*
968 KPartition::ChildAt(int32 index) const
970 return index >= 0 && index < fChildren.Count()
971 ? fChildren.ElementAt(index) : NULL;
975 int32
976 KPartition::CountChildren() const
978 return fPartitionData.child_count;
982 int32
983 KPartition::CountDescendants() const
985 int32 count = 1;
986 for (int32 i = 0; KPartition* child = ChildAt(i); i++)
987 count += child->CountDescendants();
988 return count;
992 KPartition*
993 KPartition::VisitEachDescendant(KPartitionVisitor* visitor)
995 if (!visitor)
996 return NULL;
997 if (visitor->VisitPre(this))
998 return this;
999 for (int32 i = 0; KPartition* child = ChildAt(i); i++) {
1000 if (KPartition* result = child->VisitEachDescendant(visitor))
1001 return result;
1003 if (visitor->VisitPost(this))
1004 return this;
1005 return NULL;
1009 void
1010 KPartition::SetDiskSystem(KDiskSystem* diskSystem, float priority)
1012 // unload former disk system
1013 if (fDiskSystem) {
1014 fPartitionData.content_type = NULL;
1015 fDiskSystem->Unload();
1016 fDiskSystem = NULL;
1017 fDiskSystemPriority = -1;
1019 // set and load new one
1020 fDiskSystem = diskSystem;
1021 if (fDiskSystem) {
1022 fDiskSystem->Load();
1023 // can't fail, since it's already loaded
1025 // update concerned partition flags
1026 if (fDiskSystem) {
1027 fPartitionData.content_type = fDiskSystem->PrettyName();
1028 fDiskSystemPriority = priority;
1029 if (fDiskSystem->IsFileSystem())
1030 AddFlags(B_PARTITION_FILE_SYSTEM);
1031 else
1032 AddFlags(B_PARTITION_PARTITIONING_SYSTEM);
1034 // notify listeners
1035 FireDiskSystemChanged(fDiskSystem);
1037 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1039 char messageBuffer[512];
1040 KMessage message;
1041 message.SetTo(messageBuffer, sizeof(messageBuffer), B_DEVICE_UPDATE);
1042 message.AddInt32("event", B_DEVICE_PARTITION_INITIALIZED);
1043 message.AddInt32("id", ID());
1045 manager->Notify(message, B_DEVICE_REQUEST_PARTITION);
1049 KDiskSystem*
1050 KPartition::DiskSystem() const
1052 return fDiskSystem;
1056 float
1057 KPartition::DiskSystemPriority() const
1059 return fDiskSystemPriority;
1063 KDiskSystem*
1064 KPartition::ParentDiskSystem() const
1066 return Parent() ? Parent()->DiskSystem() : NULL;
1070 void
1071 KPartition::SetCookie(void* cookie)
1073 if (fPartitionData.cookie != cookie) {
1074 fPartitionData.cookie = cookie;
1075 FireCookieChanged(cookie);
1080 void*
1081 KPartition::Cookie() const
1083 return fPartitionData.cookie;
1087 void
1088 KPartition::SetContentCookie(void* cookie)
1090 if (fPartitionData.content_cookie != cookie) {
1091 fPartitionData.content_cookie = cookie;
1092 FireContentCookieChanged(cookie);
1097 void*
1098 KPartition::ContentCookie() const
1100 return fPartitionData.content_cookie;
1104 bool
1105 KPartition::AddListener(KPartitionListener* listener)
1107 if (!listener)
1108 return false;
1109 // lazy create listeners
1110 if (!fListeners) {
1111 fListeners = new(nothrow) ListenerSet;
1112 if (!fListeners)
1113 return false;
1115 // add listener
1116 return fListeners->Insert(listener) == B_OK;
1120 bool
1121 KPartition::RemoveListener(KPartitionListener* listener)
1123 if (!listener || !fListeners)
1124 return false;
1125 // remove listener and delete the set, if empty now
1126 bool result = (fListeners->Remove(listener) > 0);
1127 if (fListeners->IsEmpty()) {
1128 delete fListeners;
1129 fListeners = NULL;
1131 return result;
1135 void
1136 KPartition::Changed(uint32 flags, uint32 clearFlags)
1138 fChangeFlags &= ~clearFlags;
1139 fChangeFlags |= flags;
1140 fChangeCounter++;
1141 if (Parent())
1142 Parent()->Changed(B_PARTITION_CHANGED_DESCENDANTS);
1146 void
1147 KPartition::SetChangeFlags(uint32 flags)
1149 fChangeFlags = flags;
1153 uint32
1154 KPartition::ChangeFlags() const
1156 return fChangeFlags;
1160 int32
1161 KPartition::ChangeCounter() const
1163 return fChangeCounter;
1167 status_t
1168 KPartition::UninitializeContents(bool logChanges)
1170 if (DiskSystem()) {
1171 uint32 flags = B_PARTITION_CHANGED_INITIALIZATION
1172 | B_PARTITION_CHANGED_CONTENT_TYPE
1173 | B_PARTITION_CHANGED_STATUS
1174 | B_PARTITION_CHANGED_FLAGS;
1176 // children
1177 if (CountChildren() > 0) {
1178 if (!RemoveAllChildren())
1179 return B_ERROR;
1180 flags |= B_PARTITION_CHANGED_CHILDREN;
1183 // volume
1184 if (VolumeID() >= 0) {
1185 status_t error = vfs_unmount(VolumeID(),
1186 B_FORCE_UNMOUNT | B_UNMOUNT_BUSY_PARTITION);
1187 if (error != B_OK) {
1188 dprintf("KPartition::UninitializeContents(): Failed to unmount "
1189 "device %" B_PRIdDEV ": %s\n", VolumeID(), strerror(error));
1192 SetVolumeID(-1);
1193 flags |= B_PARTITION_CHANGED_VOLUME;
1196 // content name
1197 if (ContentName()) {
1198 SetContentName(NULL);
1199 flags |= B_PARTITION_CHANGED_CONTENT_NAME;
1202 // content parameters
1203 if (ContentParameters()) {
1204 SetContentParameters(NULL);
1205 flags |= B_PARTITION_CHANGED_CONTENT_PARAMETERS;
1208 // content size
1209 if (ContentSize() > 0) {
1210 SetContentSize(0);
1211 flags |= B_PARTITION_CHANGED_CONTENT_SIZE;
1214 // block size
1215 if (Parent() && Parent()->BlockSize() != BlockSize()) {
1216 SetBlockSize(Parent()->BlockSize());
1217 flags |= B_PARTITION_CHANGED_BLOCK_SIZE;
1220 // disk system
1221 DiskSystem()->FreeContentCookie(this);
1222 SetDiskSystem(NULL);
1224 // status
1225 SetStatus(B_PARTITION_UNINITIALIZED);
1227 // flags
1228 ClearFlags(B_PARTITION_FILE_SYSTEM | B_PARTITION_PARTITIONING_SYSTEM);
1229 if (!Device()->IsReadOnlyMedia())
1230 ClearFlags(B_PARTITION_READ_ONLY);
1232 // log changes
1233 if (logChanges) {
1234 Changed(flags, B_PARTITION_CHANGED_DEFRAGMENTATION
1235 | B_PARTITION_CHANGED_CHECK | B_PARTITION_CHANGED_REPAIR);
1239 return B_OK;
1243 void
1244 KPartition::SetAlgorithmData(uint32 data)
1246 fAlgorithmData = data;
1250 uint32
1251 KPartition::AlgorithmData() const
1253 return fAlgorithmData;
1257 void
1258 KPartition::WriteUserData(UserDataWriter& writer, user_partition_data* data)
1260 // allocate
1261 char* name = writer.PlaceString(Name());
1262 char* contentName = writer.PlaceString(ContentName());
1263 char* type = writer.PlaceString(Type());
1264 char* contentType = writer.PlaceString(ContentType());
1265 char* parameters = writer.PlaceString(Parameters());
1266 char* contentParameters = writer.PlaceString(ContentParameters());
1267 // fill in data
1268 if (data) {
1269 data->id = ID();
1270 data->offset = Offset();
1271 data->size = Size();
1272 data->content_size = ContentSize();
1273 data->block_size = BlockSize();
1274 data->status = Status();
1275 data->flags = Flags();
1276 data->volume = VolumeID();
1277 data->index = Index();
1278 data->change_counter = ChangeCounter();
1279 data->disk_system = (DiskSystem() ? DiskSystem()->ID() : -1);
1280 data->name = name;
1281 data->content_name = contentName;
1282 data->type = type;
1283 data->content_type = contentType;
1284 data->parameters = parameters;
1285 data->content_parameters = contentParameters;
1286 data->child_count = CountChildren();
1287 // make buffer relocatable
1288 writer.AddRelocationEntry(&data->name);
1289 writer.AddRelocationEntry(&data->content_name);
1290 writer.AddRelocationEntry(&data->type);
1291 writer.AddRelocationEntry(&data->content_type);
1292 writer.AddRelocationEntry(&data->parameters);
1293 writer.AddRelocationEntry(&data->content_parameters);
1295 // children
1296 for (int32 i = 0; KPartition* child = ChildAt(i); i++) {
1297 user_partition_data* childData
1298 = writer.AllocatePartitionData(child->CountChildren());
1299 if (data) {
1300 data->children[i] = childData;
1301 writer.AddRelocationEntry(&data->children[i]);
1303 child->WriteUserData(writer, childData);
1308 void
1309 KPartition::Dump(bool deep, int32 level)
1311 if (level < 0 || level > 255)
1312 return;
1314 char prefix[256];
1315 sprintf(prefix, "%*s%*s", (int)level, "", (int)level, "");
1316 KPath path;
1317 GetPath(&path);
1318 if (level > 0)
1319 OUT("%spartition %" B_PRId32 ": %s\n", prefix, ID(), path.Path());
1320 OUT("%s offset: %" B_PRIdOFF "\n", prefix, Offset());
1321 OUT("%s size: %" B_PRIdOFF " (%.2f MB)\n", prefix, Size(),
1322 Size() / (1024.0*1024));
1323 OUT("%s content size: %" B_PRIdOFF "\n", prefix, ContentSize());
1324 OUT("%s block size: %" B_PRIu32 "\n", prefix, BlockSize());
1325 OUT("%s child count: %" B_PRId32 "\n", prefix, CountChildren());
1326 OUT("%s index: %" B_PRId32 "\n", prefix, Index());
1327 OUT("%s status: %" B_PRIu32 "\n", prefix, Status());
1328 OUT("%s flags: %" B_PRIx32 "\n", prefix, Flags());
1329 OUT("%s volume: %" B_PRIdDEV "\n", prefix, VolumeID());
1330 OUT("%s disk system: %s\n", prefix,
1331 (DiskSystem() ? DiskSystem()->Name() : NULL));
1332 OUT("%s name: %s\n", prefix, Name());
1333 OUT("%s content name: %s\n", prefix, ContentName());
1334 OUT("%s type: %s\n", prefix, Type());
1335 OUT("%s content type: %s\n", prefix, ContentType());
1336 OUT("%s params: %s\n", prefix, Parameters());
1337 OUT("%s content params: %s\n", prefix, ContentParameters());
1338 if (deep) {
1339 for (int32 i = 0; KPartition* child = ChildAt(i); i++)
1340 child->Dump(true, level + 1);
1345 void
1346 KPartition::FireOffsetChanged(off_t offset)
1348 if (fListeners) {
1349 for (ListenerSet::Iterator it = fListeners->Begin();
1350 it != fListeners->End(); ++it) {
1351 (*it)->OffsetChanged(this, offset);
1357 void
1358 KPartition::FireSizeChanged(off_t size)
1360 if (fListeners) {
1361 for (ListenerSet::Iterator it = fListeners->Begin();
1362 it != fListeners->End(); ++it) {
1363 (*it)->SizeChanged(this, size);
1369 void
1370 KPartition::FireContentSizeChanged(off_t size)
1372 if (fListeners) {
1373 for (ListenerSet::Iterator it = fListeners->Begin();
1374 it != fListeners->End(); ++it) {
1375 (*it)->ContentSizeChanged(this, size);
1381 void
1382 KPartition::FireBlockSizeChanged(uint32 blockSize)
1384 if (fListeners) {
1385 for (ListenerSet::Iterator it = fListeners->Begin();
1386 it != fListeners->End(); ++it) {
1387 (*it)->BlockSizeChanged(this, blockSize);
1393 void
1394 KPartition::FireIndexChanged(int32 index)
1396 if (fListeners) {
1397 for (ListenerSet::Iterator it = fListeners->Begin();
1398 it != fListeners->End(); ++it) {
1399 (*it)->IndexChanged(this, index);
1405 void
1406 KPartition::FireStatusChanged(uint32 status)
1408 if (fListeners) {
1409 for (ListenerSet::Iterator it = fListeners->Begin();
1410 it != fListeners->End(); ++it) {
1411 (*it)->StatusChanged(this, status);
1417 void
1418 KPartition::FireFlagsChanged(uint32 flags)
1420 if (fListeners) {
1421 for (ListenerSet::Iterator it = fListeners->Begin();
1422 it != fListeners->End(); ++it) {
1423 (*it)->FlagsChanged(this, flags);
1429 void
1430 KPartition::FireNameChanged(const char* name)
1432 if (fListeners) {
1433 for (ListenerSet::Iterator it = fListeners->Begin();
1434 it != fListeners->End(); ++it) {
1435 (*it)->NameChanged(this, name);
1441 void
1442 KPartition::FireContentNameChanged(const char* name)
1444 if (fListeners) {
1445 for (ListenerSet::Iterator it = fListeners->Begin();
1446 it != fListeners->End(); ++it) {
1447 (*it)->ContentNameChanged(this, name);
1453 void
1454 KPartition::FireTypeChanged(const char* type)
1456 if (fListeners) {
1457 for (ListenerSet::Iterator it = fListeners->Begin();
1458 it != fListeners->End(); ++it) {
1459 (*it)->TypeChanged(this, type);
1465 void
1466 KPartition::FireIDChanged(partition_id id)
1468 if (fListeners) {
1469 for (ListenerSet::Iterator it = fListeners->Begin();
1470 it != fListeners->End(); ++it) {
1471 (*it)->IDChanged(this, id);
1477 void
1478 KPartition::FireVolumeIDChanged(dev_t volumeID)
1480 if (fListeners) {
1481 for (ListenerSet::Iterator it = fListeners->Begin();
1482 it != fListeners->End(); ++it) {
1483 (*it)->VolumeIDChanged(this, volumeID);
1489 void
1490 KPartition::FireMountCookieChanged(void* cookie)
1492 if (fListeners) {
1493 for (ListenerSet::Iterator it = fListeners->Begin();
1494 it != fListeners->End(); ++it) {
1495 (*it)->MountCookieChanged(this, cookie);
1501 void
1502 KPartition::FireParametersChanged(const char* parameters)
1504 if (fListeners) {
1505 for (ListenerSet::Iterator it = fListeners->Begin();
1506 it != fListeners->End(); ++it) {
1507 (*it)->ParametersChanged(this, parameters);
1513 void
1514 KPartition::FireContentParametersChanged(const char* parameters)
1516 if (fListeners) {
1517 for (ListenerSet::Iterator it = fListeners->Begin();
1518 it != fListeners->End(); ++it) {
1519 (*it)->ContentParametersChanged(this, parameters);
1525 void
1526 KPartition::FireChildAdded(KPartition* child, int32 index)
1528 if (fListeners) {
1529 for (ListenerSet::Iterator it = fListeners->Begin();
1530 it != fListeners->End(); ++it) {
1531 (*it)->ChildAdded(this, child, index);
1537 void
1538 KPartition::FireChildRemoved(KPartition* child, int32 index)
1540 if (fListeners) {
1541 for (ListenerSet::Iterator it = fListeners->Begin();
1542 it != fListeners->End(); ++it) {
1543 (*it)->ChildRemoved(this, child, index);
1549 void
1550 KPartition::FireDiskSystemChanged(KDiskSystem* diskSystem)
1552 if (fListeners) {
1553 for (ListenerSet::Iterator it = fListeners->Begin();
1554 it != fListeners->End(); ++it) {
1555 (*it)->DiskSystemChanged(this, diskSystem);
1561 void
1562 KPartition::FireCookieChanged(void* cookie)
1564 if (fListeners) {
1565 for (ListenerSet::Iterator it = fListeners->Begin();
1566 it != fListeners->End(); ++it) {
1567 (*it)->CookieChanged(this, cookie);
1573 void
1574 KPartition::FireContentCookieChanged(void* cookie)
1576 if (fListeners) {
1577 for (ListenerSet::Iterator it = fListeners->Begin();
1578 it != fListeners->End(); ++it) {
1579 (*it)->ContentCookieChanged(this, cookie);
1585 void
1586 KPartition::_UpdateChildIndices(int32 start, int32 end)
1588 if (start < end) {
1589 for (int32 i = start; i < end; i++) {
1590 fChildren.ElementAt(i)->SetIndex(i);
1591 fChildren.ElementAt(i)->RepublishDevice();
1593 } else {
1594 for (int32 i = start; i > end; i--) {
1595 fChildren.ElementAt(i)->SetIndex(i);
1596 fChildren.ElementAt(i)->RepublishDevice();
1602 int32
1603 KPartition::_NextID()
1605 return atomic_add(&sNextID, 1);