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
39 using 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 */
53 static inline int
compare_string(const char * str1,const char * str2)54 compare_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
68 struct DiskDeviceJobGenerator::MoveInfo {
69 BPartition* partition;
70 off_t position;
71 off_t target_position;
72 off_t size;
73 };
74
75
76 // PartitionRefInfo
77 struct DiskDeviceJobGenerator::PartitionRefInfo {
PartitionRefInfoDiskDeviceJobGenerator::PartitionRefInfo78 PartitionRefInfo()
79 : partition(NULL),
80 reference(NULL)
81 {
82 }
83
~PartitionRefInfoDiskDeviceJobGenerator::PartitionRefInfo84 ~PartitionRefInfo()
85 {
86 if (reference)
87 reference->ReleaseReference();
88 }
89
90 BPartition* partition;
91 PartitionReference* reference;
92 };
93
94
95 // constructor
DiskDeviceJobGenerator(BDiskDevice * device,DiskDeviceJobQueue * jobQueue)96 DiskDeviceJobGenerator::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
~DiskDeviceJobGenerator()117 DiskDeviceJobGenerator::~DiskDeviceJobGenerator()
118 {
119 delete[] fMoveInfos;
120 delete[] fPartitionRefs;
121 delete[] fContentsToMove;
122 }
123
124
125 // GenerateJobs
126 status_t
GenerateJobs()127 DiskDeviceJobGenerator::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
174 status_t
_AddJob(DiskDeviceJob * job)175 DiskDeviceJobGenerator::_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
189 status_t
_GenerateCleanupJobs(BPartition * partition)190 DiskDeviceJobGenerator::_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
220 status_t
_GeneratePlacementJobs(BPartition * partition)221 DiskDeviceJobGenerator::_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
257 status_t
_GenerateChildPlacementJobs(BPartition * partition)258 DiskDeviceJobGenerator::_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
370 status_t
_GenerateRemainingJobs(BPartition * parent,BPartition * partition)371 DiskDeviceJobGenerator::_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
484 BMutablePartition*
_GetMutablePartition(BPartition * partition)485 DiskDeviceJobGenerator::_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
496 status_t
_GenerateInitializeJob(BPartition * partition)497 DiskDeviceJobGenerator::_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
520 status_t
_GenerateUninitializeJob(BPartition * partition)521 DiskDeviceJobGenerator::_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
541 status_t
_GenerateSetContentNameJob(BPartition * partition)542 DiskDeviceJobGenerator::_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
565 status_t
_GenerateSetContentParametersJob(BPartition * partition)566 DiskDeviceJobGenerator::_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
589 status_t
_GenerateDefragmentJob(BPartition * partition)590 DiskDeviceJobGenerator::_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
602 status_t
_GenerateRepairJob(BPartition * partition,bool repair)603 DiskDeviceJobGenerator::_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
615 status_t
_GenerateCreateChildJob(BPartition * parent,BPartition * partition)616 DiskDeviceJobGenerator::_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
646 status_t
_GenerateDeleteChildJob(BPartition * parent,BPartition * partition)647 DiskDeviceJobGenerator::_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
665 status_t
_GenerateResizeJob(BPartition * partition)666 DiskDeviceJobGenerator::_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
688 status_t
_GenerateMoveJob(BPartition * partition)689 DiskDeviceJobGenerator::_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
728 status_t
_GenerateSetNameJob(BPartition * parent,BPartition * partition)729 DiskDeviceJobGenerator::_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
757 status_t
_GenerateSetTypeJob(BPartition * parent,BPartition * partition)758 DiskDeviceJobGenerator::_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
786 status_t
_GenerateSetParametersJob(BPartition * parent,BPartition * partition)787 DiskDeviceJobGenerator::_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
816 status_t
_CollectContentsToMove(BPartition * partition)817 DiskDeviceJobGenerator::_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
842 status_t
_PushContentsToMove(BPartition * partition)843 DiskDeviceJobGenerator::_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
860 status_t
_GetPartitionReference(BPartition * partition,PartitionReference * & reference)861 DiskDeviceJobGenerator::_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
900 int
_CompareMoveInfoPosition(const void * _a,const void * _b)901 DiskDeviceJobGenerator::_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