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