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 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 { 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 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 117 DiskDeviceJobGenerator::~DiskDeviceJobGenerator() 118 { 119 delete[] fMoveInfos; 120 delete[] fPartitionRefs; 121 delete[] fContentsToMove; 122 } 123 124 125 // GenerateJobs 126 status_t 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 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 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 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 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 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 ((changeFlags & B_PARTITION_CHANGED_PARAMETERS) 414 || compare_string(partition->Parameters(), 415 partitionData->parameters)) { 416 if (!parent) 417 return B_BAD_VALUE; 418 419 status_t error = _GenerateSetParametersJob(parent, partition); 420 if (error != B_OK) 421 return error; 422 } 423 } 424 425 if (partition->ContentType()) { 426 // initialize the partition, if required 427 if (changeFlags & B_PARTITION_CHANGED_INITIALIZATION) { 428 status_t error = _GenerateInitializeJob(partition); 429 if (error != B_OK) 430 return error; 431 } else { 432 // partition not (re-)initialized, set content properties 433 434 // content name 435 if ((changeFlags & B_PARTITION_CHANGED_NAME) 436 || compare_string(partition->ContentName(), 437 partitionData->content_name)) { 438 status_t error = _GenerateSetContentNameJob(partition); 439 if (error != B_OK) 440 return error; 441 } 442 443 // content parameters 444 if ((changeFlags & B_PARTITION_CHANGED_PARAMETERS) 445 || compare_string(partition->ContentParameters(), 446 partitionData->content_parameters)) { 447 status_t error = _GenerateSetContentParametersJob(partition); 448 if (error != B_OK) 449 return error; 450 } 451 452 // defragment 453 if (changeFlags & B_PARTITION_CHANGED_DEFRAGMENTATION) { 454 status_t error = _GenerateDefragmentJob(partition); 455 if (error != B_OK) 456 return error; 457 } 458 459 // check / repair 460 bool repair = (changeFlags & B_PARTITION_CHANGED_REPAIR); 461 if ((changeFlags & B_PARTITION_CHANGED_CHECK) 462 || repair) { 463 status_t error = _GenerateRepairJob(partition, repair); 464 if (error != B_OK) 465 return error; 466 } 467 } 468 } 469 470 // recurse 471 for (int32 i = 0; BPartition* child = partition->ChildAt(i); i++) { 472 status_t error = _GenerateRemainingJobs(partition, child); 473 if (error != B_OK) 474 return error; 475 } 476 477 return B_OK; 478 } 479 480 481 // _GetMutablePartition 482 BMutablePartition* 483 DiskDeviceJobGenerator::_GetMutablePartition(BPartition* partition) 484 { 485 if (!partition) 486 return NULL; 487 488 return partition->fDelegate 489 ? partition->fDelegate->MutablePartition() : NULL; 490 } 491 492 493 // _GenerateInitializeJob 494 status_t 495 DiskDeviceJobGenerator::_GenerateInitializeJob(BPartition* partition) 496 { 497 PartitionReference* reference; 498 status_t error = _GetPartitionReference(partition, reference); 499 if (error != B_OK) 500 return error; 501 502 InitializeJob* job = new(nothrow) InitializeJob(reference); 503 if (!job) 504 return B_NO_MEMORY; 505 506 error = job->Init(partition->ContentType(), 507 partition->ContentName(), partition->ContentParameters()); 508 if (error != B_OK) { 509 delete job; 510 return error; 511 } 512 513 return _AddJob(job); 514 } 515 516 517 // _GenerateUninitializeJob 518 status_t 519 DiskDeviceJobGenerator::_GenerateUninitializeJob(BPartition* partition) 520 { 521 PartitionReference* reference; 522 status_t error = _GetPartitionReference(partition, reference); 523 if (error != B_OK) 524 return error; 525 526 BPartition* parent = partition->Parent(); 527 PartitionReference* parentReference = NULL; 528 if (parent != NULL) { 529 error = _GetPartitionReference(parent, parentReference); 530 if (error != B_OK) 531 return error; 532 } 533 534 return _AddJob(new(nothrow) UninitializeJob(reference, parentReference)); 535 } 536 537 538 // _GenerateSetContentNameJob 539 status_t 540 DiskDeviceJobGenerator::_GenerateSetContentNameJob(BPartition* partition) 541 { 542 PartitionReference* reference; 543 status_t error = _GetPartitionReference(partition, reference); 544 if (error != B_OK) 545 return error; 546 547 SetStringJob* job = new(nothrow) SetStringJob(reference); 548 if (!job) 549 return B_NO_MEMORY; 550 551 error = job->Init(partition->ContentName(), 552 B_DISK_DEVICE_JOB_SET_CONTENT_NAME); 553 if (error != B_OK) { 554 delete job; 555 return error; 556 } 557 558 return _AddJob(job); 559 } 560 561 562 // _GenerateSetContentParametersJob 563 status_t 564 DiskDeviceJobGenerator::_GenerateSetContentParametersJob(BPartition* partition) 565 { 566 PartitionReference* reference; 567 status_t error = _GetPartitionReference(partition, reference); 568 if (error != B_OK) 569 return error; 570 571 SetStringJob* job = new(nothrow) SetStringJob(reference); 572 if (!job) 573 return B_NO_MEMORY; 574 575 error = job->Init(partition->ContentParameters(), 576 B_DISK_DEVICE_JOB_SET_CONTENT_PARAMETERS); 577 if (error != B_OK) { 578 delete job; 579 return error; 580 } 581 582 return _AddJob(job); 583 } 584 585 586 // _GenerateDefragmentJob 587 status_t 588 DiskDeviceJobGenerator::_GenerateDefragmentJob(BPartition* partition) 589 { 590 PartitionReference* reference; 591 status_t error = _GetPartitionReference(partition, reference); 592 if (error != B_OK) 593 return error; 594 595 return _AddJob(new(nothrow) DefragmentJob(reference)); 596 } 597 598 599 // _GenerateRepairJob 600 status_t 601 DiskDeviceJobGenerator::_GenerateRepairJob(BPartition* partition, bool repair) 602 { 603 PartitionReference* reference; 604 status_t error = _GetPartitionReference(partition, reference); 605 if (error != B_OK) 606 return error; 607 608 return _AddJob(new(nothrow) RepairJob(reference, repair)); 609 } 610 611 612 // _GenerateCreateChildJob 613 status_t 614 DiskDeviceJobGenerator::_GenerateCreateChildJob(BPartition* parent, 615 BPartition* partition) 616 { 617 PartitionReference* parentReference; 618 status_t error = _GetPartitionReference(parent, parentReference); 619 if (error != B_OK) 620 return error; 621 622 PartitionReference* reference; 623 error = _GetPartitionReference(partition, reference); 624 if (error != B_OK) 625 return error; 626 627 CreateChildJob* job = new(nothrow) CreateChildJob(parentReference, 628 reference); 629 if (!job) 630 return B_NO_MEMORY; 631 632 error = job->Init(partition->Offset(), partition->Size(), partition->Type(), 633 partition->Name(), partition->Parameters()); 634 if (error != B_OK) { 635 delete job; 636 return error; 637 } 638 639 return _AddJob(job); 640 } 641 642 643 // _GenerateDeleteChildJob 644 status_t 645 DiskDeviceJobGenerator::_GenerateDeleteChildJob(BPartition* parent, 646 BPartition* partition) 647 { 648 PartitionReference* parentReference; 649 status_t error = _GetPartitionReference(parent, parentReference); 650 if (error != B_OK) 651 return error; 652 653 PartitionReference* reference; 654 error = _GetPartitionReference(partition, reference); 655 if (error != B_OK) 656 return error; 657 658 return _AddJob(new(nothrow) DeleteChildJob(parentReference, reference)); 659 } 660 661 662 // _GenerateResizeJob 663 status_t 664 DiskDeviceJobGenerator::_GenerateResizeJob(BPartition* partition) 665 { 666 BPartition* parent = partition->Parent(); 667 if (!parent) 668 return B_BAD_VALUE; 669 670 PartitionReference* parentReference; 671 status_t error = _GetPartitionReference(parent, parentReference); 672 if (error != B_OK) 673 return error; 674 675 PartitionReference* reference; 676 error = _GetPartitionReference(partition, reference); 677 if (error != B_OK) 678 return error; 679 680 return _AddJob(new(nothrow) ResizeJob(parentReference, reference, 681 partition->Size(), partition->ContentSize())); 682 } 683 684 685 // _GenerateMoveJob 686 status_t 687 DiskDeviceJobGenerator::_GenerateMoveJob(BPartition* partition) 688 { 689 BPartition* parent = partition->Parent(); 690 if (!parent) 691 return B_BAD_VALUE; 692 693 PartitionReference* parentReference; 694 status_t error = _GetPartitionReference(parent, parentReference); 695 if (error != B_OK) 696 return error; 697 698 PartitionReference* reference; 699 error = _GetPartitionReference(partition, reference); 700 if (error != B_OK) 701 return error; 702 703 // collect all descendants whose contents need to be moved 704 fContentsToMoveCount = 0; 705 error = _CollectContentsToMove(partition); 706 if (error != B_OK) 707 return B_OK; 708 709 // create and init the job 710 MoveJob* job = new(nothrow) MoveJob(parentReference, reference); 711 if (!job) 712 return B_NO_MEMORY; 713 714 error = job->Init(partition->Offset(), fContentsToMove, 715 fContentsToMoveCount); 716 if (error != B_OK) { 717 delete job; 718 return error; 719 } 720 721 return _AddJob(job); 722 } 723 724 725 // _GenerateSetNameJob 726 status_t 727 DiskDeviceJobGenerator::_GenerateSetNameJob(BPartition* parent, 728 BPartition* partition) 729 { 730 PartitionReference* parentReference; 731 status_t error = _GetPartitionReference(parent, parentReference); 732 if (error != B_OK) 733 return error; 734 735 PartitionReference* reference; 736 error = _GetPartitionReference(partition, reference); 737 if (error != B_OK) 738 return error; 739 740 SetStringJob* job = new(nothrow) SetStringJob(parentReference, reference); 741 if (!job) 742 return B_NO_MEMORY; 743 744 error = job->Init(partition->Name(), B_DISK_DEVICE_JOB_SET_NAME); 745 if (error != B_OK) { 746 delete job; 747 return error; 748 } 749 750 return _AddJob(job); 751 } 752 753 754 // _GenerateSetTypeJob 755 status_t 756 DiskDeviceJobGenerator::_GenerateSetTypeJob(BPartition* parent, 757 BPartition* partition) 758 { 759 PartitionReference* parentReference; 760 status_t error = _GetPartitionReference(parent, parentReference); 761 if (error != B_OK) 762 return error; 763 764 PartitionReference* reference; 765 error = _GetPartitionReference(partition, reference); 766 if (error != B_OK) 767 return error; 768 769 SetStringJob* job = new(nothrow) SetStringJob(parentReference, reference); 770 if (!job) 771 return B_NO_MEMORY; 772 773 error = job->Init(partition->Type(), B_DISK_DEVICE_JOB_SET_TYPE); 774 if (error != B_OK) { 775 delete job; 776 return error; 777 } 778 779 return _AddJob(job); 780 } 781 782 783 // _GenerateSetParametersJob 784 status_t 785 DiskDeviceJobGenerator::_GenerateSetParametersJob(BPartition* parent, 786 BPartition* partition) 787 { 788 PartitionReference* parentReference; 789 status_t error = _GetPartitionReference(parent, parentReference); 790 if (error != B_OK) 791 return error; 792 793 PartitionReference* reference; 794 error = _GetPartitionReference(partition, reference); 795 if (error != B_OK) 796 return error; 797 798 SetStringJob* job = new(nothrow) SetStringJob(parentReference, reference); 799 if (!job) 800 return B_NO_MEMORY; 801 802 error = job->Init(partition->Parameters(), 803 B_DISK_DEVICE_JOB_SET_PARAMETERS); 804 if (error != B_OK) { 805 delete job; 806 return error; 807 } 808 809 return _AddJob(job); 810 } 811 812 813 // _CollectContentsToMove 814 status_t 815 DiskDeviceJobGenerator::_CollectContentsToMove(BPartition* partition) 816 { 817 BMutablePartition* shadow = _GetMutablePartition(partition); 818 if (shadow->Status() == B_PARTITION_UNRECOGNIZED) 819 return B_ERROR; 820 821 // if the partition has contents, push its ID 822 if (shadow->ContentType() 823 && !(shadow->ChangeFlags() & B_PARTITION_CHANGED_INITIALIZATION)) { 824 status_t error = _PushContentsToMove(partition); 825 if (error != B_OK) 826 return error; 827 } 828 829 // recurse 830 for (int32 i = 0; BPartition* child = partition->ChildAt(i); i++) { 831 status_t error = _CollectContentsToMove(child); 832 if (error != B_OK) 833 return error; 834 } 835 return B_OK; 836 } 837 838 839 // _PushContentsToMove 840 status_t 841 DiskDeviceJobGenerator::_PushContentsToMove(BPartition* partition) 842 { 843 if (fContentsToMoveCount >= fPartitionCount) 844 return B_ERROR; 845 846 PartitionReference* reference; 847 status_t error = _GetPartitionReference(partition, reference); 848 if (error != B_OK) 849 return error; 850 851 fContentsToMove[fContentsToMoveCount++] = reference; 852 853 return B_OK; 854 } 855 856 857 // _GetPartitionReference 858 status_t 859 DiskDeviceJobGenerator::_GetPartitionReference(BPartition* partition, 860 PartitionReference*& reference) 861 { 862 if (!partition) 863 return B_BAD_VALUE; 864 865 for (int32 i = 0; i < fPartitionCount; i++) { 866 PartitionRefInfo& info = fPartitionRefs[i]; 867 868 if (info.partition == partition) { 869 reference = info.reference; 870 return B_OK; 871 } 872 873 if (info.partition == NULL) { 874 // create partition reference 875 info.reference = new(nothrow) PartitionReference(); 876 if (!info.reference) 877 return B_NO_MEMORY; 878 879 // set partition ID and change counter 880 user_partition_data* partitionData = partition->fPartitionData; 881 if (partitionData) { 882 info.reference->SetPartitionID(partitionData->id); 883 info.reference->SetChangeCounter(partitionData->change_counter); 884 } 885 886 info.partition = partition; 887 reference = info.reference; 888 return B_OK; 889 } 890 } 891 892 // Out of slots -- that can't happen. 893 return B_ERROR; 894 } 895 896 897 // _CompareMoveInfoOffset 898 int 899 DiskDeviceJobGenerator::_CompareMoveInfoPosition(const void* _a, const void* _b) 900 { 901 const MoveInfo* a = static_cast<const MoveInfo*>(_a); 902 const MoveInfo* b = static_cast<const MoveInfo*>(_b); 903 if (a->position < b->position) 904 return -1; 905 if (a->position > b->position) 906 return 1; 907 return 0; 908 } 909