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