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