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 ((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* 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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