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