1/*
2 * Copyright 2007, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include <MutablePartition.h>
7
8#include <stdlib.h>
9#include <string.h>
10
11#include <new>
12
13#include <Partition.h>
14
15#include <ddm_userland_interface_defs.h>
16
17#include "DiskDeviceUtils.h"
18#include "PartitionDelegate.h"
19
20
21using std::nothrow;
22
23
24// UninitializeContents
25void
26BMutablePartition::UninitializeContents()
27{
28	DeleteAllChildren();
29	SetVolumeID(-1);
30	SetContentName(NULL);
31	SetContentParameters(NULL);
32	SetContentSize(0);
33	SetBlockSize(Parent()->BlockSize());
34	SetContentType(NULL);
35	SetStatus(B_PARTITION_UNINITIALIZED);
36	ClearFlags(B_PARTITION_FILE_SYSTEM | B_PARTITION_PARTITIONING_SYSTEM);
37//	if (!Device()->IsReadOnlyMedia())
38//		ClearFlags(B_PARTITION_READ_ONLY);
39}
40
41
42// Offset
43off_t
44BMutablePartition::Offset() const
45{
46	return fData->offset;
47}
48
49
50// SetOffset
51void
52BMutablePartition::SetOffset(off_t offset)
53{
54	if (fData->offset != offset) {
55		fData->offset = offset;
56		Changed(B_PARTITION_CHANGED_OFFSET);
57	}
58}
59
60
61// Size
62off_t
63BMutablePartition::Size() const
64{
65	return fData->size;
66}
67
68
69// SetSize
70void
71BMutablePartition::SetSize(off_t size)
72{
73	if (fData->size != size) {
74		fData->size = size;
75		Changed(B_PARTITION_CHANGED_SIZE);
76	}
77}
78
79
80// ContentSize
81off_t
82BMutablePartition::ContentSize() const
83{
84	return fData->content_size;
85}
86
87
88// SetContentSize
89void
90BMutablePartition::SetContentSize(off_t size)
91{
92	if (fData->content_size != size) {
93		fData->content_size = size;
94		Changed(B_PARTITION_CHANGED_CONTENT_SIZE);
95	}
96}
97
98
99// BlockSize
100off_t
101BMutablePartition::BlockSize() const
102{
103	return fData->block_size;
104}
105
106
107// SetBlockSize
108void
109BMutablePartition::SetBlockSize(off_t blockSize)
110{
111	if (fData->block_size != blockSize) {
112		fData->block_size = blockSize;
113		Changed(B_PARTITION_CHANGED_BLOCK_SIZE);
114	}
115}
116
117
118// Status
119uint32
120BMutablePartition::Status() const
121{
122	return fData->status;
123}
124
125
126// SetStatus
127void
128BMutablePartition::SetStatus(uint32 status)
129{
130	if (fData->status != status) {
131		fData->status = status;
132		Changed(B_PARTITION_CHANGED_STATUS);
133	}
134}
135
136
137// Flags
138uint32
139BMutablePartition::Flags() const
140{
141	return fData->flags;
142}
143
144
145// SetFlags
146void
147BMutablePartition::SetFlags(uint32 flags)
148{
149	if (fData->flags != flags) {
150		fData->flags = flags;
151		Changed(B_PARTITION_CHANGED_FLAGS);
152	}
153}
154
155
156// ClearFlags
157void
158BMutablePartition::ClearFlags(uint32 flags)
159{
160	if (flags & fData->flags) {
161		fData->flags &= ~flags;
162		Changed(B_PARTITION_CHANGED_FLAGS);
163	}
164}
165
166
167// VolumeID
168dev_t
169BMutablePartition::VolumeID() const
170{
171	return fData->volume;
172}
173
174
175// SetVolumeID
176void
177BMutablePartition::SetVolumeID(dev_t volumeID)
178{
179	if (fData->volume != volumeID) {
180		fData->volume = volumeID;
181		Changed(B_PARTITION_CHANGED_VOLUME);
182	}
183}
184
185
186// Index
187int32
188BMutablePartition::Index() const
189{
190	return fData->index;
191}
192
193
194// Name
195const char*
196BMutablePartition::Name() const
197{
198	return fData->name;
199}
200
201
202// SetName
203status_t
204BMutablePartition::SetName(const char* name)
205{
206	if (compare_string(name, fData->name) == 0)
207		return B_OK;
208
209	if (set_string(fData->name, name) != B_OK)
210		return B_NO_MEMORY;
211
212	Changed(B_PARTITION_CHANGED_NAME);
213	return B_OK;
214}
215
216
217// ContentName
218BString
219BMutablePartition::ContentName() const
220{
221	return fData->content_name;
222}
223
224
225// SetContentName
226status_t
227BMutablePartition::SetContentName(const char* name)
228{
229	if (compare_string(name, fData->content_name) == 0)
230		return B_OK;
231
232	if (set_string(fData->content_name, name) != B_OK)
233		return B_NO_MEMORY;
234
235	Changed(B_PARTITION_CHANGED_CONTENT_NAME);
236	return B_OK;
237}
238
239
240// Type
241const char*
242BMutablePartition::Type() const
243{
244	return fData->type;
245}
246
247
248// SetType
249status_t
250BMutablePartition::SetType(const char* type)
251{
252	if (compare_string(type, fData->type) == 0)
253		return B_OK;
254
255	if (set_string(fData->type, type) != B_OK)
256		return B_NO_MEMORY;
257
258	Changed(B_PARTITION_CHANGED_TYPE);
259	return B_OK;
260}
261
262
263// ContentType
264const char*
265BMutablePartition::ContentType() const
266{
267	return fData->content_type;
268}
269
270
271// SetContentType
272status_t
273BMutablePartition::SetContentType(const char* type)
274{
275	if (compare_string(type, fData->content_type) == 0)
276		return B_OK;
277
278	if (set_string(fData->content_type, type) != B_OK)
279		return B_NO_MEMORY;
280
281	Changed(B_PARTITION_CHANGED_CONTENT_TYPE
282		| B_PARTITION_CHANGED_INITIALIZATION);
283	return B_OK;
284}
285
286
287// Parameters
288const char*
289BMutablePartition::Parameters() const
290{
291	return fData->parameters;
292}
293
294
295// SetParameters
296status_t
297BMutablePartition::SetParameters(const char* parameters)
298{
299	if (compare_string(parameters, fData->parameters) == 0)
300		return B_OK;
301
302	if (set_string(fData->parameters, parameters) != B_OK)
303		return B_NO_MEMORY;
304
305	Changed(B_PARTITION_CHANGED_PARAMETERS);
306	return B_OK;
307}
308
309
310// ContentParameters
311const char*
312BMutablePartition::ContentParameters() const
313{
314	return fData->content_parameters;
315}
316
317
318// SetContentParameters
319status_t
320BMutablePartition::SetContentParameters(const char* parameters)
321{
322	if (compare_string(parameters, fData->content_parameters) == 0)
323		return B_OK;
324
325	if (set_string(fData->content_parameters, parameters) != B_OK)
326		return B_NO_MEMORY;
327
328	Changed(B_PARTITION_CHANGED_CONTENT_PARAMETERS);
329	return B_OK;
330}
331
332
333// CreateChild
334status_t
335BMutablePartition::CreateChild(int32 index, BMutablePartition** _child)
336{
337	if (index < 0)
338		index = fChildren.CountItems();
339	else if (index > fChildren.CountItems())
340		return B_BAD_VALUE;
341
342	// create the BPartition
343	BPartition* partition = new(nothrow) BPartition;
344	if (!partition)
345		return B_NO_MEMORY;
346
347	// create the delegate
348	BPartition::Delegate* delegate
349		= new(nothrow) BPartition::Delegate(partition);
350	if (!delegate) {
351		delete partition;
352		return B_NO_MEMORY;
353	}
354	partition->fDelegate = delegate;
355
356	// add the child
357	BMutablePartition* child = delegate->MutablePartition();
358	if (!fChildren.AddItem(child, index)) {
359		delete partition;
360		return B_NO_MEMORY;
361	}
362	child->fParent = this;
363	child->fData = new(nothrow) user_partition_data;
364	if (!child->fData) {
365		fChildren.RemoveItem(child);
366		delete partition;
367		return B_NO_MEMORY;
368	}
369
370	memset(child->fData, 0, sizeof(user_partition_data));
371
372	child->fData->id = -1;
373	child->fData->status = B_PARTITION_UNINITIALIZED;
374	child->fData->volume = -1;
375	child->fData->index = -1;
376	child->fData->disk_system = -1;
377
378	*_child = child;
379
380	Changed(B_PARTITION_CHANGED_CHILDREN);
381	return B_OK;
382}
383
384
385// CreateChild
386status_t
387BMutablePartition::CreateChild(int32 index, const char* type, const char* name,
388	const char* parameters, BMutablePartition** _child)
389{
390	// create the child
391	BMutablePartition* child;
392	status_t error = CreateChild(index, &child);
393	if (error != B_OK)
394		return error;
395
396	// set the name, type, and parameters
397	error = child->SetType(type);
398	if (error == B_OK)
399		error = child->SetName(name);
400	if (error == B_OK)
401		error = child->SetParameters(parameters);
402
403	// cleanup on error
404	if (error != B_OK) {
405		DeleteChild(child);
406		return error;
407	}
408
409	*_child = child;
410
411	Changed(B_PARTITION_CHANGED_CHILDREN);
412	return B_OK;
413}
414
415
416// DeleteChild
417status_t
418BMutablePartition::DeleteChild(int32 index)
419{
420	BMutablePartition* child = (BMutablePartition*)fChildren.RemoveItem(index);
421	if (!child)
422		return B_BAD_VALUE;
423
424	// This will delete not only all delegates in the child's hierarchy, but
425	// also the respective partitions themselves, if they are no longer
426	// referenced.
427	child->fDelegate->Partition()->_DeleteDelegates();
428
429	Changed(B_PARTITION_CHANGED_CHILDREN);
430	return B_OK;
431}
432
433
434// DeleteChild
435status_t
436BMutablePartition::DeleteChild(BMutablePartition* child)
437{
438	return DeleteChild(IndexOfChild(child));
439}
440
441
442// DeleteAllChildren
443void
444BMutablePartition::DeleteAllChildren()
445{
446	int32 count = CountChildren();
447	for (int32 i = count - 1; i >= 0; i--)
448		DeleteChild(i);
449}
450
451
452// Parent
453BMutablePartition*
454BMutablePartition::Parent() const
455{
456	return fParent;
457}
458
459
460// ChildAt
461BMutablePartition*
462BMutablePartition::ChildAt(int32 index) const
463{
464	return (BMutablePartition*)fChildren.ItemAt(index);
465}
466
467
468// CountChildren
469int32
470BMutablePartition::CountChildren() const
471{
472	return fChildren.CountItems();
473}
474
475
476// IndexOfChild
477int32
478BMutablePartition::IndexOfChild(BMutablePartition* child) const
479{
480	if (!child)
481		return -1;
482	return fChildren.IndexOf(child);
483}
484
485
486// SetChangeFlags
487void
488BMutablePartition::SetChangeFlags(uint32 flags)
489{
490	fChangeFlags = flags;
491}
492
493
494// ChangeFlags
495uint32
496BMutablePartition::ChangeFlags() const
497{
498	return fChangeFlags;
499}
500
501
502// Changed
503void
504BMutablePartition::Changed(uint32 flags, uint32 clearFlags)
505{
506	fChangeFlags &= ~clearFlags;
507	fChangeFlags |= flags;
508
509	if (Parent())
510		Parent()->Changed(B_PARTITION_CHANGED_DESCENDANTS);
511}
512
513
514// ChildCookie
515void*
516BMutablePartition::ChildCookie() const
517{
518	return fChildCookie;
519}
520
521
522// SetChildCookie
523void
524BMutablePartition::SetChildCookie(void* cookie)
525{
526	fChildCookie = cookie;
527}
528
529
530// constructor
531BMutablePartition::BMutablePartition(BPartition::Delegate* delegate)
532	: fDelegate(delegate),
533	  fData(NULL),
534	  fParent(NULL),
535	  fChangeFlags(0),
536	  fChildCookie(NULL)
537{
538}
539
540
541// Init
542status_t
543BMutablePartition::Init(const user_partition_data* partitionData,
544	BMutablePartition* parent)
545{
546	fParent = parent;
547
548	// add to the parent's child list
549	if (fParent) {
550		if (!fParent->fChildren.AddItem(this))
551			return B_NO_MEMORY;
552	}
553
554	// allocate data structure
555	fData = new(nothrow) user_partition_data;
556	if (!fData)
557		return B_NO_MEMORY;
558
559	memset(fData, 0, sizeof(user_partition_data));
560
561	// copy the flat data
562	fData->id = partitionData->id;
563	fData->offset = partitionData->offset;
564	fData->size = partitionData->size;
565	fData->content_size = partitionData->content_size;
566	fData->block_size = partitionData->block_size;
567	fData->physical_block_size = partitionData->physical_block_size;
568	fData->status = partitionData->status;
569	fData->flags = partitionData->flags;
570	fData->volume = partitionData->volume;
571	fData->index = partitionData->index;
572	fData->change_counter = partitionData->change_counter;
573	fData->disk_system = partitionData->disk_system;
574
575	// copy the strings
576	SET_STRING_RETURN_ON_ERROR(fData->name, partitionData->name);
577	SET_STRING_RETURN_ON_ERROR(fData->content_name,
578		partitionData->content_name);
579	SET_STRING_RETURN_ON_ERROR(fData->type, partitionData->type);
580	SET_STRING_RETURN_ON_ERROR(fData->content_type,
581		partitionData->content_type);
582	SET_STRING_RETURN_ON_ERROR(fData->parameters, partitionData->parameters);
583	SET_STRING_RETURN_ON_ERROR(fData->content_parameters,
584		partitionData->content_parameters);
585
586	return B_OK;
587}
588
589
590// destructor
591BMutablePartition::~BMutablePartition()
592{
593	if (fData) {
594		free(fData->name);
595		free(fData->content_name);
596		free(fData->type);
597		free(fData->content_type);
598		free(fData->parameters);
599		free(fData->content_parameters);
600		delete fData;
601	}
602}
603
604
605// PartitionData
606const user_partition_data*
607BMutablePartition::PartitionData() const
608{
609	return fData;
610}
611
612
613// GetDelegate
614BPartition::Delegate*
615BMutablePartition::GetDelegate() const
616{
617	return fDelegate;
618}
619
620