1/*
2 * Copyright 2003-2007, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6#include "DiskDeviceJobGenerator.h"
7
8#include <new>
9
10#include <stdlib.h>
11#include <string.h>
12
13#include <DiskDevice.h>
14#include <MutablePartition.h>
15
16#include <ddm_userland_interface_defs.h>
17
18#include "DiskDeviceJob.h"
19#include "DiskDeviceJobQueue.h"
20#include "PartitionDelegate.h"
21#include "PartitionReference.h"
22
23#include "CreateChildJob.h"
24#include "DeleteChildJob.h"
25#include "DefragmentJob.h"
26#include "InitializeJob.h"
27#include "MoveJob.h"
28#include "RepairJob.h"
29#include "ResizeJob.h"
30#include "SetStringJob.h"
31#include "UninitializeJob.h"
32
33
34#undef TRACE
35#define TRACE(x...)
36//#define TRACE(x...)	printf(x)
37
38
39using std::nothrow;
40
41
42// compare_string
43/*!	\brief \c NULL aware strcmp().
44
45	\c NULL is considered the least of all strings. \c NULL equals \c NULL.
46
47	\param str1 First string.
48	\param str2 Second string.
49	\return A value less than 0, if \a str1 is less than \a str2,
50			0, if they are equal, or a value greater than 0, if
51			\a str1 is greater \a str2.
52*/
53static inline int
54compare_string(const char* str1, const char* str2)
55{
56	if (str1 == NULL) {
57		if (str2 == NULL)
58			return 0;
59		return 1;
60	} else if (str2 == NULL)
61		return -1;
62
63	return strcmp(str1, str2);
64}
65
66
67// MoveInfo
68struct DiskDeviceJobGenerator::MoveInfo {
69	BPartition*	partition;
70	off_t		position;
71	off_t		target_position;
72	off_t		size;
73};
74
75
76// PartitionRefInfo
77struct DiskDeviceJobGenerator::PartitionRefInfo {
78	PartitionRefInfo()
79		: partition(NULL),
80		  reference(NULL)
81	{
82	}
83
84	~PartitionRefInfo()
85	{
86		if (reference)
87			reference->ReleaseReference();
88	}
89
90	BPartition*			partition;
91	PartitionReference*	reference;
92};
93
94
95// constructor
96DiskDeviceJobGenerator::DiskDeviceJobGenerator(BDiskDevice* device,
97		DiskDeviceJobQueue* jobQueue)
98	: fDevice(device),
99	  fJobQueue(jobQueue),
100	  fMoveInfos(NULL),
101	  fPartitionRefs(NULL),
102	  fContentsToMove(NULL),
103	  fContentsToMoveCount(0)
104{
105	// Make sure the arrays are big enough (worst case: all old partitions have
106	// been deleted and new ones been created).
107	fPartitionCount = fDevice->CountDescendants()
108		+ fDevice->_CountDescendants();
109
110	fMoveInfos = new(nothrow) MoveInfo[fPartitionCount];
111	fPartitionRefs = new(nothrow) PartitionRefInfo[fPartitionCount];
112	fContentsToMove = new(nothrow) PartitionReference*[fPartitionCount];
113}
114
115
116// destructor
117DiskDeviceJobGenerator::~DiskDeviceJobGenerator()
118{
119	delete[] fMoveInfos;
120	delete[] fPartitionRefs;
121	delete[] fContentsToMove;
122}
123
124
125// GenerateJobs
126status_t
127DiskDeviceJobGenerator::GenerateJobs()
128{
129	// check parameters
130	if (!fDevice || !fJobQueue)
131		return B_BAD_VALUE;
132
133	if (!fMoveInfos || !fPartitionRefs || !fContentsToMove)
134		return B_NO_MEMORY;
135
136	// 1) Generate jobs for all physical partitions that don't have an
137	// associated shadow partition, i.e. those that shall be deleted.
138	// 2) Generate uninitialize jobs for all partition whose initialization
139	// changes, also those that shall be initialized with a disk system.
140	// This simplifies moving and resizing.
141	status_t error = _GenerateCleanupJobs(fDevice);
142	if (error != B_OK) {
143		TRACE("DiskDeviceJobGenerator::GenerateJobs(): _GenerateCleanupJobs() "
144			"failed\n");
145		return error;
146	}
147
148	// Generate jobs that move and resize the remaining physical partitions
149	// to their final position/size.
150	error = _GeneratePlacementJobs(fDevice);
151	if (error != B_OK) {
152		TRACE("DiskDeviceJobGenerator::GenerateJobs(): "
153			"_GeneratePlacementJobs() failed\n");
154		return error;
155	}
156
157	// Generate the remaining jobs in one run: initialization, creation of
158	// partitions, and changing of name, content name, type, parameters, and
159	// content parameters.
160	error = _GenerateRemainingJobs(NULL, fDevice);
161	if (error != B_OK) {
162		TRACE("DiskDeviceJobGenerator::GenerateJobs(): "
163			"_GenerateRemainingJobs() failed\n");
164		return error;
165	}
166
167	TRACE("DiskDeviceJobGenerator::GenerateJobs(): succeeded\n");
168
169	return B_OK;
170}
171
172
173// _AddJob
174status_t
175DiskDeviceJobGenerator::_AddJob(DiskDeviceJob* job)
176{
177	if (!job)
178		return B_NO_MEMORY;
179
180	status_t error = fJobQueue->AddJob(job);
181	if (error != B_OK)
182		delete job;
183
184	return error;
185}
186
187
188// _GenerateCleanupJobs
189status_t
190DiskDeviceJobGenerator::_GenerateCleanupJobs(BPartition* partition)
191{
192// TODO: Depending on how this shall be handled, we might want to unmount
193// all descendants of a partition to be uninitialized or removed.
194	if (BMutablePartition* shadow = _GetMutablePartition(partition)) {
195		if ((shadow->ChangeFlags() & B_PARTITION_CHANGED_INITIALIZATION)
196			&& partition->fPartitionData->content_type) {
197			// partition changes initialization
198			status_t error = _GenerateUninitializeJob(partition);
199			if (error != B_OK)
200				return error;
201		} else {
202			// recurse
203			for (int32 i = 0; BPartition* child = partition->_ChildAt(i); i++) {
204				status_t error = _GenerateCleanupJobs(child);
205				if (error != B_OK)
206					return error;
207			}
208		}
209	} else if (BPartition* parent = partition->Parent()) {
210		// create job and add it to the queue
211		status_t error = _GenerateDeleteChildJob(parent, partition);
212		if (error != B_OK)
213			return error;
214	}
215	return B_OK;
216}
217
218
219// _GeneratePlacementJobs
220status_t
221DiskDeviceJobGenerator::_GeneratePlacementJobs(BPartition* partition)
222{
223	if (BMutablePartition* shadow = _GetMutablePartition(partition)) {
224		// Don't resize/move partitions that have an unrecognized contents.
225		// They must have been uninitialized before.
226		if (shadow->Status() == B_PARTITION_UNRECOGNIZED
227			&& (shadow->Size() != partition->Size()
228				|| shadow->Offset() != partition->Offset())) {
229			return B_ERROR;
230		}
231
232		if (shadow->Size() > partition->Size()) {
233			// size grows: resize first
234			status_t error = _GenerateResizeJob(partition);
235			if (error != B_OK)
236				return error;
237		}
238
239		// place the children
240		status_t error = _GenerateChildPlacementJobs(partition);
241		if (error != B_OK)
242			return error;
243
244		if (shadow->Size() < partition->Size()) {
245			// size shrinks: resize now
246			status_t error = _GenerateResizeJob(partition);
247			if (error != B_OK)
248				return error;
249		}
250	}
251
252	return B_OK;
253}
254
255
256// _GenerateChildPlacementJobs
257status_t
258DiskDeviceJobGenerator::_GenerateChildPlacementJobs(BPartition* partition)
259{
260	BMutablePartition* shadow = _GetMutablePartition(partition);
261
262	// nothing to do, if the partition contains no partitioning system or
263	// shall be re-initialized
264	if (!shadow->ContentType()
265		|| (shadow->ChangeFlags() & B_PARTITION_CHANGED_INITIALIZATION)) {
266		return B_OK;
267	}
268
269	// first resize all children that shall shrink and place their descendants
270	int32 childCount = 0;
271	int32 moveForth = 0;
272	int32 moveBack = 0;
273
274	for (int32 i = 0; BPartition* child = partition->_ChildAt(i); i++) {
275		if (BMutablePartition* childShadow = _GetMutablePartition(child)) {
276			// add a MoveInfo for the child
277			MoveInfo& info = fMoveInfos[childCount];
278			childCount++;
279			info.partition = child;
280			info.position = child->Offset();
281			info.target_position = childShadow->Offset();
282			info.size = child->Size();
283
284			if (info.position < info.target_position)
285				moveForth++;
286			else if (info.position > info.target_position)
287				moveBack++;
288
289			// resize the child, if it shall shrink
290			if (childShadow->Size() < child->Size()) {
291				status_t error = _GeneratePlacementJobs(child);
292				if (error != B_OK)
293					return error;
294				info.size = childShadow->Size();
295			}
296		}
297	}
298
299	// sort the move infos
300	if (childCount > 0 && moveForth + moveBack > 0) {
301		qsort(fMoveInfos, childCount, sizeof(MoveInfo),
302			_CompareMoveInfoPosition);
303	}
304
305	// move the children to their final positions
306	while (moveForth + moveBack > 0) {
307		int32 moved = 0;
308		if (moveForth < moveBack) {
309			// move children back
310			for (int32 i = 0; i < childCount; i++) {
311				MoveInfo& info = fMoveInfos[i];
312				if (info.position > info.target_position) {
313					if (i == 0
314						|| info.target_position >= fMoveInfos[i - 1].position
315							+ fMoveInfos[i - 1].size) {
316						// check OK -- the partition wouldn't be moved before
317						// the end of the preceding one
318						status_t error = _GenerateMoveJob(info.partition);
319						if (error != B_OK)
320							return error;
321						info.position = info.target_position;
322						moved++;
323						moveBack--;
324					}
325				}
326			}
327		} else {
328			// move children forth
329			for (int32 i = childCount - 1; i >= 0; i--) {
330				MoveInfo &info = fMoveInfos[i];
331				if (info.position > info.target_position) {
332					if (i == childCount - 1
333						|| info.target_position + info.size
334							<= fMoveInfos[i - 1].position) {
335						// check OK -- the partition wouldn't be moved before
336						// the end of the preceding one
337						status_t error = _GenerateMoveJob(info.partition);
338						if (error != B_OK)
339							return error;
340						info.position = info.target_position;
341						moved++;
342						moveForth--;
343					}
344				}
345			}
346		}
347
348		// terminate, if no partition could be moved
349		if (moved == 0)
350			return B_ERROR;
351	}
352
353	// now resize all children that shall grow/keep their size and place
354	// their descendants
355	for (int32 i = 0; BPartition* child = partition->_ChildAt(i); i++) {
356		if (BMutablePartition* childShadow = _GetMutablePartition(child)) {
357			if (childShadow->Size() >= child->Size()) {
358				status_t error = _GeneratePlacementJobs(child);
359				if (error != B_OK)
360					return error;
361			}
362		}
363	}
364
365	return B_OK;
366}
367
368
369// _GenerateRemainingJobs
370status_t
371DiskDeviceJobGenerator::_GenerateRemainingJobs(BPartition* parent,
372	BPartition* partition)
373{
374	user_partition_data* partitionData = partition->fPartitionData;
375
376	uint32 changeFlags
377		= partition->fDelegate->MutablePartition()->ChangeFlags();
378
379	// create the partition, if not existing yet
380	if (!partitionData) {
381		if (!parent)
382			return B_BAD_VALUE;
383
384		status_t error = _GenerateCreateChildJob(parent, partition);
385		if (error != B_OK)
386			return error;
387	} else {
388		// partition already exists: set non-content properties
389
390		// name
391		if ((changeFlags & B_PARTITION_CHANGED_NAME)
392			|| compare_string(partition->Name(), partitionData->name)) {
393			if (!parent)
394				return B_BAD_VALUE;
395
396			status_t error = _GenerateSetNameJob(parent, partition);
397			if (error != B_OK)
398				return error;
399		}
400
401		// type
402		if ((changeFlags & B_PARTITION_CHANGED_TYPE)
403			|| compare_string(partition->Type(), partitionData->type)) {
404			if (!parent)
405				return B_BAD_VALUE;
406
407			status_t error = _GenerateSetTypeJob(parent, partition);
408			if (error != B_OK)
409				return error;
410		}
411
412		// parameters
413		if ((partition->Parameters() != NULL)
414			&& ((changeFlags & B_PARTITION_CHANGED_PARAMETERS) != 0
415				|| compare_string(partition->Parameters(),
416					partitionData->parameters))) {
417			if (!parent)
418				return B_BAD_VALUE;
419
420			status_t error = _GenerateSetParametersJob(parent, partition);
421			if (error != B_OK)
422				return error;
423		}
424	}
425
426	if (partition->ContentType()) {
427		// initialize the partition, if required
428		if (changeFlags & B_PARTITION_CHANGED_INITIALIZATION) {
429			status_t error = _GenerateInitializeJob(partition);
430			if (error != B_OK)
431				return error;
432		} else {
433			// partition not (re-)initialized, set content properties
434
435			// content name
436			if ((changeFlags & B_PARTITION_CHANGED_NAME)
437				|| compare_string(partition->RawContentName(),
438					partitionData->content_name)) {
439				status_t error = _GenerateSetContentNameJob(partition);
440				if (error != B_OK)
441					return error;
442			}
443
444			// content parameters
445			if ((partition->ContentParameters() != NULL)
446				&& ((changeFlags & B_PARTITION_CHANGED_PARAMETERS) != 0
447					|| compare_string(partition->ContentParameters(),
448						partitionData->content_parameters))) {
449				status_t error = _GenerateSetContentParametersJob(partition);
450				if (error != B_OK)
451					return error;
452			}
453
454			// defragment
455			if (changeFlags & B_PARTITION_CHANGED_DEFRAGMENTATION) {
456				status_t error = _GenerateDefragmentJob(partition);
457				if (error != B_OK)
458					return error;
459			}
460
461			// check / repair
462			bool repair = (changeFlags & B_PARTITION_CHANGED_REPAIR);
463			if ((changeFlags & B_PARTITION_CHANGED_CHECK)
464				|| repair) {
465				status_t error = _GenerateRepairJob(partition, repair);
466				if (error != B_OK)
467					return error;
468			}
469		}
470	}
471
472	// recurse
473	for (int32 i = 0; BPartition* child = partition->ChildAt(i); i++) {
474		status_t error = _GenerateRemainingJobs(partition, child);
475		if (error != B_OK)
476			return error;
477	}
478
479	return B_OK;
480}
481
482
483// _GetMutablePartition
484BMutablePartition*
485DiskDeviceJobGenerator::_GetMutablePartition(BPartition* partition)
486{
487	if (!partition)
488		return NULL;
489
490	return partition->fDelegate
491		? partition->fDelegate->MutablePartition() : NULL;
492}
493
494
495// _GenerateInitializeJob
496status_t
497DiskDeviceJobGenerator::_GenerateInitializeJob(BPartition* partition)
498{
499	PartitionReference* reference;
500	status_t error = _GetPartitionReference(partition, reference);
501	if (error != B_OK)
502		return error;
503
504	InitializeJob* job = new(nothrow) InitializeJob(reference);
505	if (!job)
506		return B_NO_MEMORY;
507
508	error = job->Init(partition->ContentType(),
509		partition->RawContentName(), partition->ContentParameters());
510	if (error != B_OK) {
511		delete job;
512		return error;
513	}
514
515	return _AddJob(job);
516}
517
518
519// _GenerateUninitializeJob
520status_t
521DiskDeviceJobGenerator::_GenerateUninitializeJob(BPartition* partition)
522{
523	PartitionReference* reference;
524	status_t error = _GetPartitionReference(partition, reference);
525	if (error != B_OK)
526		return error;
527
528	BPartition* parent = partition->Parent();
529	PartitionReference* parentReference = NULL;
530	if (parent != NULL) {
531		error = _GetPartitionReference(parent, parentReference);
532		if (error != B_OK)
533			return error;
534	}
535
536	return _AddJob(new(nothrow) UninitializeJob(reference, parentReference));
537}
538
539
540// _GenerateSetContentNameJob
541status_t
542DiskDeviceJobGenerator::_GenerateSetContentNameJob(BPartition* partition)
543{
544	PartitionReference* reference;
545	status_t error = _GetPartitionReference(partition, reference);
546	if (error != B_OK)
547		return error;
548
549	SetStringJob* job = new(nothrow) SetStringJob(reference);
550	if (!job)
551		return B_NO_MEMORY;
552
553	error = job->Init(partition->RawContentName(),
554		B_DISK_DEVICE_JOB_SET_CONTENT_NAME);
555	if (error != B_OK) {
556		delete job;
557		return error;
558	}
559
560	return _AddJob(job);
561}
562
563
564// _GenerateSetContentParametersJob
565status_t
566DiskDeviceJobGenerator::_GenerateSetContentParametersJob(BPartition* partition)
567{
568	PartitionReference* reference;
569	status_t error = _GetPartitionReference(partition, reference);
570	if (error != B_OK)
571		return error;
572
573	SetStringJob* job = new(nothrow) SetStringJob(reference);
574	if (!job)
575		return B_NO_MEMORY;
576
577	error = job->Init(partition->ContentParameters(),
578		B_DISK_DEVICE_JOB_SET_CONTENT_PARAMETERS);
579	if (error != B_OK) {
580		delete job;
581		return error;
582	}
583
584	return _AddJob(job);
585}
586
587
588// _GenerateDefragmentJob
589status_t
590DiskDeviceJobGenerator::_GenerateDefragmentJob(BPartition* partition)
591{
592	PartitionReference* reference;
593	status_t error = _GetPartitionReference(partition, reference);
594	if (error != B_OK)
595		return error;
596
597	return _AddJob(new(nothrow) DefragmentJob(reference));
598}
599
600
601// _GenerateRepairJob
602status_t
603DiskDeviceJobGenerator::_GenerateRepairJob(BPartition* partition, bool repair)
604{
605	PartitionReference* reference;
606	status_t error = _GetPartitionReference(partition, reference);
607	if (error != B_OK)
608		return error;
609
610	return _AddJob(new(nothrow) RepairJob(reference, repair));
611}
612
613
614// _GenerateCreateChildJob
615status_t
616DiskDeviceJobGenerator::_GenerateCreateChildJob(BPartition* parent,
617	BPartition* partition)
618{
619	PartitionReference* parentReference;
620	status_t error = _GetPartitionReference(parent, parentReference);
621	if (error != B_OK)
622		return error;
623
624	PartitionReference* reference;
625	error = _GetPartitionReference(partition, reference);
626	if (error != B_OK)
627		return error;
628
629	CreateChildJob* job = new(nothrow) CreateChildJob(parentReference,
630		reference);
631	if (!job)
632		return B_NO_MEMORY;
633
634	error = job->Init(partition->Offset(), partition->Size(), partition->Type(),
635		partition->Name(), partition->Parameters());
636	if (error != B_OK) {
637		delete job;
638		return error;
639	}
640
641	return _AddJob(job);
642}
643
644
645// _GenerateDeleteChildJob
646status_t
647DiskDeviceJobGenerator::_GenerateDeleteChildJob(BPartition* parent,
648	BPartition* partition)
649{
650	PartitionReference* parentReference;
651	status_t error = _GetPartitionReference(parent, parentReference);
652	if (error != B_OK)
653		return error;
654
655	PartitionReference* reference;
656	error = _GetPartitionReference(partition, reference);
657	if (error != B_OK)
658		return error;
659
660	return _AddJob(new(nothrow) DeleteChildJob(parentReference, reference));
661}
662
663
664// _GenerateResizeJob
665status_t
666DiskDeviceJobGenerator::_GenerateResizeJob(BPartition* partition)
667{
668	BPartition* parent = partition->Parent();
669	if (!parent)
670		return B_BAD_VALUE;
671
672	PartitionReference* parentReference;
673	status_t error = _GetPartitionReference(parent, parentReference);
674	if (error != B_OK)
675		return error;
676
677	PartitionReference* reference;
678	error = _GetPartitionReference(partition, reference);
679	if (error != B_OK)
680		return error;
681
682	return _AddJob(new(nothrow) ResizeJob(parentReference, reference,
683		partition->Size(), partition->ContentSize()));
684}
685
686
687// _GenerateMoveJob
688status_t
689DiskDeviceJobGenerator::_GenerateMoveJob(BPartition* partition)
690{
691	BPartition* parent = partition->Parent();
692	if (!parent)
693		return B_BAD_VALUE;
694
695	PartitionReference* parentReference;
696	status_t error = _GetPartitionReference(parent, parentReference);
697	if (error != B_OK)
698		return error;
699
700	PartitionReference* reference;
701	error = _GetPartitionReference(partition, reference);
702	if (error != B_OK)
703		return error;
704
705	// collect all descendants whose contents need to be moved
706	fContentsToMoveCount = 0;
707	error = _CollectContentsToMove(partition);
708	if (error != B_OK)
709		return B_OK;
710
711	// create and init the job
712	MoveJob* job = new(nothrow) MoveJob(parentReference, reference);
713	if (!job)
714		return B_NO_MEMORY;
715
716	error = job->Init(partition->Offset(), fContentsToMove,
717		fContentsToMoveCount);
718	if (error != B_OK) {
719		delete job;
720		return error;
721	}
722
723	return _AddJob(job);
724}
725
726
727// _GenerateSetNameJob
728status_t
729DiskDeviceJobGenerator::_GenerateSetNameJob(BPartition* parent,
730	BPartition* partition)
731{
732	PartitionReference* parentReference;
733	status_t error = _GetPartitionReference(parent, parentReference);
734	if (error != B_OK)
735		return error;
736
737	PartitionReference* reference;
738	error = _GetPartitionReference(partition, reference);
739	if (error != B_OK)
740		return error;
741
742	SetStringJob* job = new(nothrow) SetStringJob(parentReference, reference);
743	if (!job)
744		return B_NO_MEMORY;
745
746	error = job->Init(partition->Name(), B_DISK_DEVICE_JOB_SET_NAME);
747	if (error != B_OK) {
748		delete job;
749		return error;
750	}
751
752	return _AddJob(job);
753}
754
755
756// _GenerateSetTypeJob
757status_t
758DiskDeviceJobGenerator::_GenerateSetTypeJob(BPartition* parent,
759	BPartition* partition)
760{
761	PartitionReference* parentReference;
762	status_t error = _GetPartitionReference(parent, parentReference);
763	if (error != B_OK)
764		return error;
765
766	PartitionReference* reference;
767	error = _GetPartitionReference(partition, reference);
768	if (error != B_OK)
769		return error;
770
771	SetStringJob* job = new(nothrow) SetStringJob(parentReference, reference);
772	if (!job)
773		return B_NO_MEMORY;
774
775	error = job->Init(partition->Type(), B_DISK_DEVICE_JOB_SET_TYPE);
776	if (error != B_OK) {
777		delete job;
778		return error;
779	}
780
781	return _AddJob(job);
782}
783
784
785// _GenerateSetParametersJob
786status_t
787DiskDeviceJobGenerator::_GenerateSetParametersJob(BPartition* parent,
788	BPartition* partition)
789{
790	PartitionReference* parentReference;
791	status_t error = _GetPartitionReference(parent, parentReference);
792	if (error != B_OK)
793		return error;
794
795	PartitionReference* reference;
796	error = _GetPartitionReference(partition, reference);
797	if (error != B_OK)
798		return error;
799
800	SetStringJob* job = new(nothrow) SetStringJob(parentReference, reference);
801	if (!job)
802		return B_NO_MEMORY;
803
804	error = job->Init(partition->Parameters(),
805		B_DISK_DEVICE_JOB_SET_PARAMETERS);
806	if (error != B_OK) {
807		delete job;
808		return error;
809	}
810
811	return _AddJob(job);
812}
813
814
815// _CollectContentsToMove
816status_t
817DiskDeviceJobGenerator::_CollectContentsToMove(BPartition* partition)
818{
819	BMutablePartition* shadow = _GetMutablePartition(partition);
820	if (shadow->Status() == B_PARTITION_UNRECOGNIZED)
821		return B_ERROR;
822
823	// if the partition has contents, push its ID
824	if (shadow->ContentType()
825		&& !(shadow->ChangeFlags() & B_PARTITION_CHANGED_INITIALIZATION)) {
826		status_t error = _PushContentsToMove(partition);
827		if (error != B_OK)
828			return error;
829	}
830
831	// recurse
832	for (int32 i = 0; BPartition* child = partition->ChildAt(i); i++) {
833		status_t error = _CollectContentsToMove(child);
834		if (error != B_OK)
835			return error;
836	}
837	return B_OK;
838}
839
840
841// _PushContentsToMove
842status_t
843DiskDeviceJobGenerator::_PushContentsToMove(BPartition* partition)
844{
845	if (fContentsToMoveCount >= fPartitionCount)
846		return B_ERROR;
847
848	PartitionReference* reference;
849	status_t error = _GetPartitionReference(partition, reference);
850	if (error != B_OK)
851		return error;
852
853	fContentsToMove[fContentsToMoveCount++] = reference;
854
855	return B_OK;
856}
857
858
859// _GetPartitionReference
860status_t
861DiskDeviceJobGenerator::_GetPartitionReference(BPartition* partition,
862	PartitionReference*& reference)
863{
864	if (!partition)
865		return B_BAD_VALUE;
866
867	for (int32 i = 0; i < fPartitionCount; i++) {
868		PartitionRefInfo& info = fPartitionRefs[i];
869
870		if (info.partition == partition) {
871			reference = info.reference;
872			return B_OK;
873		}
874
875		if (info.partition == NULL) {
876			// create partition reference
877			info.reference = new(nothrow) PartitionReference();
878			if (!info.reference)
879				return B_NO_MEMORY;
880
881			// set partition ID and change counter
882			user_partition_data* partitionData = partition->fPartitionData;
883			if (partitionData) {
884				info.reference->SetPartitionID(partitionData->id);
885				info.reference->SetChangeCounter(partitionData->change_counter);
886			}
887
888			info.partition = partition;
889			reference = info.reference;
890			return B_OK;
891		}
892	}
893
894	// Out of slots -- that can't happen.
895	return B_ERROR;
896}
897
898
899// _CompareMoveInfoOffset
900int
901DiskDeviceJobGenerator::_CompareMoveInfoPosition(const void* _a, const void* _b)
902{
903	const MoveInfo* a = static_cast<const MoveInfo*>(_a);
904	const MoveInfo* b = static_cast<const MoveInfo*>(_b);
905	if (a->position < b->position)
906		return -1;
907	if (a->position > b->position)
908		return 1;
909	return 0;
910}
911