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