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