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::IsDevice() const
564{
565	return (fPartitionData.flags & B_PARTITION_IS_DEVICE) != 0;
566}
567
568
569status_t
570KPartition::SetName(const char* name)
571{
572	status_t error = set_string(fPartitionData.name, name);
573	FireNameChanged(fPartitionData.name);
574	return error;
575}
576
577
578const char*
579KPartition::Name() const
580{
581	return fPartitionData.name;
582}
583
584
585status_t
586KPartition::SetContentName(const char* name)
587{
588	status_t error = set_string(fPartitionData.content_name, name);
589	FireContentNameChanged(fPartitionData.content_name);
590	return error;
591}
592
593
594const char*
595KPartition::ContentName() const
596{
597	return fPartitionData.content_name;
598}
599
600
601status_t
602KPartition::SetType(const char* type)
603{
604	status_t error = set_string(fPartitionData.type, type);
605	FireTypeChanged(fPartitionData.type);
606	return error;
607}
608
609
610const char*
611KPartition::Type() const
612{
613	return fPartitionData.type;
614}
615
616
617const char*
618KPartition::ContentType() const
619{
620	return fPartitionData.content_type;
621}
622
623
624partition_data*
625KPartition::PartitionData()
626{
627	return &fPartitionData;
628}
629
630
631const partition_data*
632KPartition::PartitionData() const
633{
634	return &fPartitionData;
635}
636
637
638void
639KPartition::SetID(partition_id id)
640{
641	if (fPartitionData.id != id) {
642		fPartitionData.id = id;
643		FireIDChanged(id);
644	}
645}
646
647
648partition_id
649KPartition::ID() const
650{
651	return fPartitionData.id;
652}
653
654
655status_t
656KPartition::GetFileName(char* buffer, size_t size) const
657{
658	// If the parent is the device, the name is the index of the partition.
659	if (Parent() == NULL || Parent()->IsDevice()) {
660		if (snprintf(buffer, size, "%" B_PRId32, Index()) >= (int)size)
661			return B_NAME_TOO_LONG;
662		return B_OK;
663	}
664
665	// The partition has a non-device parent, so we append the index to the
666	// parent partition's name.
667	status_t error = Parent()->GetFileName(buffer, size);
668	if (error != B_OK)
669		return error;
670
671	size_t len = strlen(buffer);
672	if (snprintf(buffer + len, size - len, "_%" B_PRId32, Index()) >= int(size - len))
673		return B_NAME_TOO_LONG;
674	return B_OK;
675}
676
677
678status_t
679KPartition::GetPath(KPath* path) const
680{
681	// For a KDiskDevice this version is never invoked, so the check for
682	// Parent() is correct.
683	if (!path || path->InitCheck() != B_OK || !Parent() || Index() < 0)
684		return B_BAD_VALUE;
685
686	// init the path with the device path
687	status_t error = path->SetPath(Device()->Path());
688	if (error != B_OK)
689		return error;
690
691	// replace the leaf name with the partition's file name
692	char name[B_FILE_NAME_LENGTH];
693	error = GetFileName(name, sizeof(name));
694	if (error == B_OK)
695		error = path->ReplaceLeaf(name);
696
697	return error;
698}
699
700
701void
702KPartition::SetVolumeID(dev_t volumeID)
703{
704	if (fPartitionData.volume == volumeID)
705		return;
706
707	fPartitionData.volume = volumeID;
708	FireVolumeIDChanged(volumeID);
709	if (VolumeID() >= 0)
710		AddFlags(B_PARTITION_MOUNTED);
711	else
712		ClearFlags(B_PARTITION_MOUNTED);
713
714	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
715
716	char messageBuffer[512];
717	KMessage message;
718	message.SetTo(messageBuffer, sizeof(messageBuffer), B_DEVICE_UPDATE);
719	message.AddInt32("event", volumeID >= 0
720		? B_DEVICE_PARTITION_MOUNTED : B_DEVICE_PARTITION_UNMOUNTED);
721	message.AddInt32("id", ID());
722	if (volumeID >= 0)
723		message.AddInt32("volume", volumeID);
724
725	manager->Notify(message, B_DEVICE_REQUEST_MOUNTING);
726}
727
728
729dev_t
730KPartition::VolumeID() const
731{
732	return fPartitionData.volume;
733}
734
735
736void
737KPartition::SetMountCookie(void* cookie)
738{
739	if (fPartitionData.mount_cookie != cookie) {
740		fPartitionData.mount_cookie = cookie;
741		FireMountCookieChanged(cookie);
742	}
743}
744
745
746void*
747KPartition::MountCookie() const
748{
749	return fPartitionData.mount_cookie;
750}
751
752
753status_t
754KPartition::Mount(uint32 mountFlags, const char* parameters)
755{
756	// not implemented
757	return B_ERROR;
758}
759
760
761status_t
762KPartition::Unmount()
763{
764	// not implemented
765	return B_ERROR;
766}
767
768
769status_t
770KPartition::SetParameters(const char* parameters)
771{
772	status_t error = set_string(fPartitionData.parameters, parameters);
773	FireParametersChanged(fPartitionData.parameters);
774	return error;
775}
776
777
778const char*
779KPartition::Parameters() const
780{
781	return fPartitionData.parameters;
782}
783
784
785status_t
786KPartition::SetContentParameters(const char* parameters)
787{
788	status_t error = set_string(fPartitionData.content_parameters, parameters);
789	FireContentParametersChanged(fPartitionData.content_parameters);
790	return error;
791}
792
793
794const char*
795KPartition::ContentParameters() const
796{
797	return fPartitionData.content_parameters;
798}
799
800
801void
802KPartition::SetDevice(KDiskDevice* device)
803{
804	fDevice = device;
805	if (fDevice != NULL && fDevice->IsReadOnlyMedia())
806		AddFlags(B_PARTITION_READ_ONLY);
807}
808
809
810KDiskDevice*
811KPartition::Device() const
812{
813	return fDevice;
814}
815
816
817void
818KPartition::SetParent(KPartition* parent)
819{
820	// Must be called in a {Add,Remove}Child() only!
821	fParent = parent;
822}
823
824
825KPartition*
826KPartition::Parent() const
827{
828	return fParent;
829}
830
831
832status_t
833KPartition::AddChild(KPartition* partition, int32 index)
834{
835	// check parameters
836	int32 count = fPartitionData.child_count;
837	if (index == -1)
838		index = count;
839	if (index < 0 || index > count || !partition)
840		return B_BAD_VALUE;
841
842	// add partition
843	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
844	if (ManagerLocker locker = manager) {
845		status_t error = fChildren.Insert(partition, index);
846		if (error != B_OK)
847			return error;
848		if (!manager->PartitionAdded(partition)) {
849			fChildren.Erase(index);
850			return B_NO_MEMORY;
851		}
852		// update siblings index's
853		partition->SetIndex(index);
854		_UpdateChildIndices(count, index);
855		fPartitionData.child_count++;
856
857		partition->SetParent(this);
858		partition->SetDevice(Device());
859
860		// publish to devfs
861		partition->PublishDevice();
862
863		// notify listeners
864		FireChildAdded(partition, index);
865		return B_OK;
866	}
867	return B_ERROR;
868}
869
870
871status_t
872KPartition::CreateChild(partition_id id, int32 index, off_t offset, off_t size,
873	KPartition** _child)
874{
875	// check parameters
876	int32 count = fPartitionData.child_count;
877	if (index == -1)
878		index = count;
879	if (index < 0 || index > count)
880		return B_BAD_VALUE;
881
882	// create and add partition
883	KPartition* child = new(std::nothrow) KPartition(id);
884	if (child == NULL)
885		return B_NO_MEMORY;
886
887	child->SetOffset(offset);
888	child->SetSize(size);
889
890	status_t error = AddChild(child, index);
891
892	// cleanup / set result
893	if (error != B_OK)
894		delete child;
895	else if (_child)
896		*_child = child;
897
898	return error;
899}
900
901
902bool
903KPartition::RemoveChild(int32 index)
904{
905	if (index < 0 || index >= fPartitionData.child_count)
906		return false;
907
908	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
909	if (ManagerLocker locker = manager) {
910		KPartition* partition = fChildren.ElementAt(index);
911		PartitionRegistrar _(partition);
912		if (!partition || !manager->PartitionRemoved(partition)
913			|| !fChildren.Erase(index)) {
914			return false;
915		}
916		_UpdateChildIndices(index, fChildren.Count());
917		partition->SetIndex(-1);
918		fPartitionData.child_count--;
919		partition->SetParent(NULL);
920		partition->SetDevice(NULL);
921		// notify listeners
922		FireChildRemoved(partition, index);
923		return true;
924	}
925	return false;
926}
927
928
929bool
930KPartition::RemoveChild(KPartition* child)
931{
932	if (child) {
933		int32 index = fChildren.IndexOf(child);
934		if (index >= 0)
935			return RemoveChild(index);
936	}
937	return false;
938}
939
940
941bool
942KPartition::RemoveAllChildren()
943{
944	int32 count = CountChildren();
945	for (int32 i = count - 1; i >= 0; i--) {
946		if (!RemoveChild(i))
947			return false;
948	}
949	return true;
950}
951
952
953KPartition*
954KPartition::ChildAt(int32 index) const
955{
956	return index >= 0 && index < fChildren.Count()
957		? fChildren.ElementAt(index) : NULL;
958}
959
960
961int32
962KPartition::CountChildren() const
963{
964	return fPartitionData.child_count;
965}
966
967
968int32
969KPartition::CountDescendants() const
970{
971	int32 count = 1;
972	for (int32 i = 0; KPartition* child = ChildAt(i); i++)
973		count += child->CountDescendants();
974	return count;
975}
976
977
978KPartition*
979KPartition::VisitEachDescendant(KPartitionVisitor* visitor)
980{
981	if (!visitor)
982		return NULL;
983	if (visitor->VisitPre(this))
984		return this;
985	for (int32 i = 0; KPartition* child = ChildAt(i); i++) {
986		if (KPartition* result = child->VisitEachDescendant(visitor))
987			return result;
988	}
989	if (visitor->VisitPost(this))
990		return this;
991	return NULL;
992}
993
994
995void
996KPartition::SetDiskSystem(KDiskSystem* diskSystem, float priority)
997{
998	// unload former disk system
999	if (fDiskSystem) {
1000		fPartitionData.content_type = NULL;
1001		fDiskSystem->Unload();
1002		fDiskSystem = NULL;
1003		fDiskSystemPriority = -1;
1004	}
1005	// set and load new one
1006	fDiskSystem = diskSystem;
1007	if (fDiskSystem) {
1008		fDiskSystem->Load();
1009			// can't fail, since it's already loaded
1010	}
1011	// update concerned partition flags
1012	if (fDiskSystem) {
1013		fPartitionData.content_type = fDiskSystem->PrettyName();
1014		fDiskSystemPriority = priority;
1015		if (fDiskSystem->IsFileSystem())
1016			AddFlags(B_PARTITION_FILE_SYSTEM);
1017		else
1018			AddFlags(B_PARTITION_PARTITIONING_SYSTEM);
1019	}
1020	// notify listeners
1021	FireDiskSystemChanged(fDiskSystem);
1022
1023	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1024
1025	char messageBuffer[512];
1026	KMessage message;
1027	message.SetTo(messageBuffer, sizeof(messageBuffer), B_DEVICE_UPDATE);
1028	message.AddInt32("event", B_DEVICE_PARTITION_INITIALIZED);
1029	message.AddInt32("id", ID());
1030
1031	manager->Notify(message, B_DEVICE_REQUEST_PARTITION);
1032}
1033
1034
1035KDiskSystem*
1036KPartition::DiskSystem() const
1037{
1038	return fDiskSystem;
1039}
1040
1041
1042float
1043KPartition::DiskSystemPriority() const
1044{
1045	return fDiskSystemPriority;
1046}
1047
1048
1049KDiskSystem*
1050KPartition::ParentDiskSystem() const
1051{
1052	return Parent() ? Parent()->DiskSystem() : NULL;
1053}
1054
1055
1056void
1057KPartition::SetCookie(void* cookie)
1058{
1059	if (fPartitionData.cookie != cookie) {
1060		fPartitionData.cookie = cookie;
1061		FireCookieChanged(cookie);
1062	}
1063}
1064
1065
1066void*
1067KPartition::Cookie() const
1068{
1069	return fPartitionData.cookie;
1070}
1071
1072
1073void
1074KPartition::SetContentCookie(void* cookie)
1075{
1076	if (fPartitionData.content_cookie != cookie) {
1077		fPartitionData.content_cookie = cookie;
1078		FireContentCookieChanged(cookie);
1079	}
1080}
1081
1082
1083void*
1084KPartition::ContentCookie() const
1085{
1086	return fPartitionData.content_cookie;
1087}
1088
1089
1090bool
1091KPartition::AddListener(KPartitionListener* listener)
1092{
1093	if (!listener)
1094		return false;
1095	// lazy create listeners
1096	if (!fListeners) {
1097		fListeners = new(nothrow) ListenerSet;
1098		if (!fListeners)
1099			return false;
1100	}
1101	// add listener
1102	return fListeners->Insert(listener) == B_OK;
1103}
1104
1105
1106bool
1107KPartition::RemoveListener(KPartitionListener* listener)
1108{
1109	if (!listener || !fListeners)
1110		return false;
1111	// remove listener and delete the set, if empty now
1112	bool result = (fListeners->Remove(listener) > 0);
1113	if (fListeners->IsEmpty()) {
1114		delete fListeners;
1115		fListeners = NULL;
1116	}
1117	return result;
1118}
1119
1120
1121void
1122KPartition::Changed(uint32 flags, uint32 clearFlags)
1123{
1124	fChangeFlags &= ~clearFlags;
1125	fChangeFlags |= flags;
1126	fChangeCounter++;
1127	if (Parent())
1128		Parent()->Changed(B_PARTITION_CHANGED_DESCENDANTS);
1129}
1130
1131
1132void
1133KPartition::SetChangeFlags(uint32 flags)
1134{
1135	fChangeFlags = flags;
1136}
1137
1138
1139uint32
1140KPartition::ChangeFlags() const
1141{
1142	return fChangeFlags;
1143}
1144
1145
1146int32
1147KPartition::ChangeCounter() const
1148{
1149	return fChangeCounter;
1150}
1151
1152
1153status_t
1154KPartition::UninitializeContents(bool logChanges)
1155{
1156	if (DiskSystem()) {
1157		uint32 flags = B_PARTITION_CHANGED_INITIALIZATION
1158			| B_PARTITION_CHANGED_CONTENT_TYPE
1159			| B_PARTITION_CHANGED_STATUS
1160			| B_PARTITION_CHANGED_FLAGS;
1161
1162		// children
1163		if (CountChildren() > 0) {
1164			if (!RemoveAllChildren())
1165				return B_ERROR;
1166			flags |= B_PARTITION_CHANGED_CHILDREN;
1167		}
1168
1169		// volume
1170		if (VolumeID() >= 0) {
1171			status_t error = vfs_unmount(VolumeID(),
1172				B_FORCE_UNMOUNT | B_UNMOUNT_BUSY_PARTITION);
1173			if (error != B_OK) {
1174				dprintf("KPartition::UninitializeContents(): Failed to unmount "
1175					"device %" B_PRIdDEV ": %s\n", VolumeID(), strerror(error));
1176			}
1177
1178			SetVolumeID(-1);
1179			flags |= B_PARTITION_CHANGED_VOLUME;
1180		}
1181
1182		// content name
1183		if (ContentName()) {
1184			SetContentName(NULL);
1185			flags |= B_PARTITION_CHANGED_CONTENT_NAME;
1186		}
1187
1188		// content parameters
1189		if (ContentParameters()) {
1190			SetContentParameters(NULL);
1191			flags |= B_PARTITION_CHANGED_CONTENT_PARAMETERS;
1192		}
1193
1194		// content size
1195		if (ContentSize() > 0) {
1196			SetContentSize(0);
1197			flags |= B_PARTITION_CHANGED_CONTENT_SIZE;
1198		}
1199
1200		// block size
1201		if (Parent() && Parent()->BlockSize() != BlockSize()) {
1202			SetBlockSize(Parent()->BlockSize());
1203			flags |= B_PARTITION_CHANGED_BLOCK_SIZE;
1204		}
1205
1206		// disk system
1207		DiskSystem()->FreeContentCookie(this);
1208		SetDiskSystem(NULL);
1209
1210		// status
1211		SetStatus(B_PARTITION_UNINITIALIZED);
1212
1213		// flags
1214		ClearFlags(B_PARTITION_FILE_SYSTEM | B_PARTITION_PARTITIONING_SYSTEM);
1215		if (!Device()->IsReadOnlyMedia())
1216			ClearFlags(B_PARTITION_READ_ONLY);
1217
1218		// log changes
1219		if (logChanges) {
1220			Changed(flags, B_PARTITION_CHANGED_DEFRAGMENTATION
1221				| B_PARTITION_CHANGED_CHECK | B_PARTITION_CHANGED_REPAIR);
1222		}
1223	}
1224
1225	return B_OK;
1226}
1227
1228
1229void
1230KPartition::SetAlgorithmData(uint32 data)
1231{
1232	fAlgorithmData = data;
1233}
1234
1235
1236uint32
1237KPartition::AlgorithmData() const
1238{
1239	return fAlgorithmData;
1240}
1241
1242
1243void
1244KPartition::WriteUserData(UserDataWriter& writer, user_partition_data* data)
1245{
1246	// allocate
1247	char* name = writer.PlaceString(Name());
1248	char* contentName = writer.PlaceString(ContentName());
1249	char* type = writer.PlaceString(Type());
1250	char* contentType = writer.PlaceString(ContentType());
1251	char* parameters = writer.PlaceString(Parameters());
1252	char* contentParameters = writer.PlaceString(ContentParameters());
1253	// fill in data
1254	if (data) {
1255		data->id = ID();
1256		data->offset = Offset();
1257		data->size = Size();
1258		data->content_size = ContentSize();
1259		data->block_size = BlockSize();
1260		data->status = Status();
1261		data->flags = Flags();
1262		data->volume = VolumeID();
1263		data->index = Index();
1264		data->change_counter = ChangeCounter();
1265		data->disk_system = (DiskSystem() ? DiskSystem()->ID() : -1);
1266		data->name = name;
1267		data->content_name = contentName;
1268		data->type = type;
1269		data->content_type = contentType;
1270		data->parameters = parameters;
1271		data->content_parameters = contentParameters;
1272		data->child_count = CountChildren();
1273		// make buffer relocatable
1274		writer.AddRelocationEntry(&data->name);
1275		writer.AddRelocationEntry(&data->content_name);
1276		writer.AddRelocationEntry(&data->type);
1277		writer.AddRelocationEntry(&data->content_type);
1278		writer.AddRelocationEntry(&data->parameters);
1279		writer.AddRelocationEntry(&data->content_parameters);
1280	}
1281	// children
1282	for (int32 i = 0; KPartition* child = ChildAt(i); i++) {
1283		user_partition_data* childData
1284			= writer.AllocatePartitionData(child->CountChildren());
1285		if (data) {
1286			data->children[i] = childData;
1287			writer.AddRelocationEntry(&data->children[i]);
1288		}
1289		child->WriteUserData(writer, childData);
1290	}
1291}
1292
1293
1294void
1295KPartition::Dump(bool deep, int32 level)
1296{
1297	if (level < 0 || level > 255)
1298		return;
1299
1300	char prefix[256];
1301	sprintf(prefix, "%*s%*s", (int)level, "", (int)level, "");
1302	KPath path;
1303	GetPath(&path);
1304	if (level > 0)
1305		OUT("%spartition %" B_PRId32 ": %s\n", prefix, ID(), path.Path());
1306	OUT("%s  offset:            %" B_PRIdOFF "\n", prefix, Offset());
1307	OUT("%s  size:              %" B_PRIdOFF " (%.2f MB)\n", prefix, Size(),
1308		Size() / (1024.0*1024));
1309	OUT("%s  content size:      %" B_PRIdOFF "\n", prefix, ContentSize());
1310	OUT("%s  block size:        %" B_PRIu32 "\n", prefix, BlockSize());
1311	OUT("%s  child count:       %" B_PRId32 "\n", prefix, CountChildren());
1312	OUT("%s  index:             %" B_PRId32 "\n", prefix, Index());
1313	OUT("%s  status:            %" B_PRIu32 "\n", prefix, Status());
1314	OUT("%s  flags:             %" B_PRIx32 "\n", prefix, Flags());
1315	OUT("%s  volume:            %" B_PRIdDEV "\n", prefix, VolumeID());
1316	OUT("%s  disk system:       %s\n", prefix,
1317		(DiskSystem() ? DiskSystem()->Name() : NULL));
1318	OUT("%s  name:              %s\n", prefix, Name());
1319	OUT("%s  content name:      %s\n", prefix, ContentName());
1320	OUT("%s  type:              %s\n", prefix, Type());
1321	OUT("%s  content type:      %s\n", prefix, ContentType());
1322	OUT("%s  params:            %s\n", prefix, Parameters());
1323	OUT("%s  content params:    %s\n", prefix, ContentParameters());
1324	if (deep) {
1325		for (int32 i = 0; KPartition* child = ChildAt(i); i++)
1326			child->Dump(true, level + 1);
1327	}
1328}
1329
1330
1331void
1332KPartition::FireOffsetChanged(off_t offset)
1333{
1334	if (fListeners) {
1335		for (ListenerSet::Iterator it = fListeners->Begin();
1336			 it != fListeners->End(); ++it) {
1337			(*it)->OffsetChanged(this, offset);
1338		}
1339	}
1340}
1341
1342
1343void
1344KPartition::FireSizeChanged(off_t size)
1345{
1346	if (fListeners) {
1347		for (ListenerSet::Iterator it = fListeners->Begin();
1348			 it != fListeners->End(); ++it) {
1349			(*it)->SizeChanged(this, size);
1350		}
1351	}
1352}
1353
1354
1355void
1356KPartition::FireContentSizeChanged(off_t size)
1357{
1358	if (fListeners) {
1359		for (ListenerSet::Iterator it = fListeners->Begin();
1360			 it != fListeners->End(); ++it) {
1361			(*it)->ContentSizeChanged(this, size);
1362		}
1363	}
1364}
1365
1366
1367void
1368KPartition::FireBlockSizeChanged(uint32 blockSize)
1369{
1370	if (fListeners) {
1371		for (ListenerSet::Iterator it = fListeners->Begin();
1372			 it != fListeners->End(); ++it) {
1373			(*it)->BlockSizeChanged(this, blockSize);
1374		}
1375	}
1376}
1377
1378
1379void
1380KPartition::FireIndexChanged(int32 index)
1381{
1382	if (fListeners) {
1383		for (ListenerSet::Iterator it = fListeners->Begin();
1384			 it != fListeners->End(); ++it) {
1385			(*it)->IndexChanged(this, index);
1386		}
1387	}
1388}
1389
1390
1391void
1392KPartition::FireStatusChanged(uint32 status)
1393{
1394	if (fListeners) {
1395		for (ListenerSet::Iterator it = fListeners->Begin();
1396			 it != fListeners->End(); ++it) {
1397			(*it)->StatusChanged(this, status);
1398		}
1399	}
1400}
1401
1402
1403void
1404KPartition::FireFlagsChanged(uint32 flags)
1405{
1406	if (fListeners) {
1407		for (ListenerSet::Iterator it = fListeners->Begin();
1408			 it != fListeners->End(); ++it) {
1409			(*it)->FlagsChanged(this, flags);
1410		}
1411	}
1412}
1413
1414
1415void
1416KPartition::FireNameChanged(const char* name)
1417{
1418	if (fListeners) {
1419		for (ListenerSet::Iterator it = fListeners->Begin();
1420			 it != fListeners->End(); ++it) {
1421			(*it)->NameChanged(this, name);
1422		}
1423	}
1424}
1425
1426
1427void
1428KPartition::FireContentNameChanged(const char* name)
1429{
1430	if (fListeners) {
1431		for (ListenerSet::Iterator it = fListeners->Begin();
1432			 it != fListeners->End(); ++it) {
1433			(*it)->ContentNameChanged(this, name);
1434		}
1435	}
1436}
1437
1438
1439void
1440KPartition::FireTypeChanged(const char* type)
1441{
1442	if (fListeners) {
1443		for (ListenerSet::Iterator it = fListeners->Begin();
1444			 it != fListeners->End(); ++it) {
1445			(*it)->TypeChanged(this, type);
1446		}
1447	}
1448}
1449
1450
1451void
1452KPartition::FireIDChanged(partition_id id)
1453{
1454	if (fListeners) {
1455		for (ListenerSet::Iterator it = fListeners->Begin();
1456			 it != fListeners->End(); ++it) {
1457			(*it)->IDChanged(this, id);
1458		}
1459	}
1460}
1461
1462
1463void
1464KPartition::FireVolumeIDChanged(dev_t volumeID)
1465{
1466	if (fListeners) {
1467		for (ListenerSet::Iterator it = fListeners->Begin();
1468			 it != fListeners->End(); ++it) {
1469			(*it)->VolumeIDChanged(this, volumeID);
1470		}
1471	}
1472}
1473
1474
1475void
1476KPartition::FireMountCookieChanged(void* cookie)
1477{
1478	if (fListeners) {
1479		for (ListenerSet::Iterator it = fListeners->Begin();
1480			 it != fListeners->End(); ++it) {
1481			(*it)->MountCookieChanged(this, cookie);
1482		}
1483	}
1484}
1485
1486
1487void
1488KPartition::FireParametersChanged(const char* parameters)
1489{
1490	if (fListeners) {
1491		for (ListenerSet::Iterator it = fListeners->Begin();
1492			 it != fListeners->End(); ++it) {
1493			(*it)->ParametersChanged(this, parameters);
1494		}
1495	}
1496}
1497
1498
1499void
1500KPartition::FireContentParametersChanged(const char* parameters)
1501{
1502	if (fListeners) {
1503		for (ListenerSet::Iterator it = fListeners->Begin();
1504			 it != fListeners->End(); ++it) {
1505			(*it)->ContentParametersChanged(this, parameters);
1506		}
1507	}
1508}
1509
1510
1511void
1512KPartition::FireChildAdded(KPartition* child, int32 index)
1513{
1514	if (fListeners) {
1515		for (ListenerSet::Iterator it = fListeners->Begin();
1516			 it != fListeners->End(); ++it) {
1517			(*it)->ChildAdded(this, child, index);
1518		}
1519	}
1520}
1521
1522
1523void
1524KPartition::FireChildRemoved(KPartition* child, int32 index)
1525{
1526	if (fListeners) {
1527		for (ListenerSet::Iterator it = fListeners->Begin();
1528			 it != fListeners->End(); ++it) {
1529			(*it)->ChildRemoved(this, child, index);
1530		}
1531	}
1532}
1533
1534
1535void
1536KPartition::FireDiskSystemChanged(KDiskSystem* diskSystem)
1537{
1538	if (fListeners) {
1539		for (ListenerSet::Iterator it = fListeners->Begin();
1540			 it != fListeners->End(); ++it) {
1541			(*it)->DiskSystemChanged(this, diskSystem);
1542		}
1543	}
1544}
1545
1546
1547void
1548KPartition::FireCookieChanged(void* cookie)
1549{
1550	if (fListeners) {
1551		for (ListenerSet::Iterator it = fListeners->Begin();
1552			 it != fListeners->End(); ++it) {
1553			(*it)->CookieChanged(this, cookie);
1554		}
1555	}
1556}
1557
1558
1559void
1560KPartition::FireContentCookieChanged(void* cookie)
1561{
1562	if (fListeners) {
1563		for (ListenerSet::Iterator it = fListeners->Begin();
1564			 it != fListeners->End(); ++it) {
1565			(*it)->ContentCookieChanged(this, cookie);
1566		}
1567	}
1568}
1569
1570
1571void
1572KPartition::_UpdateChildIndices(int32 start, int32 end)
1573{
1574	if (start < end) {
1575		for (int32 i = start; i < end; i++) {
1576			fChildren.ElementAt(i)->SetIndex(i);
1577			fChildren.ElementAt(i)->RepublishDevice();
1578		}
1579	} else {
1580		for (int32 i = start; i > end; i--) {
1581			fChildren.ElementAt(i)->SetIndex(i);
1582			fChildren.ElementAt(i)->RepublishDevice();
1583		}
1584	}
1585}
1586
1587
1588int32
1589KPartition::_NextID()
1590{
1591	return atomic_add(&sNextID, 1);
1592}
1593