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 return _AddJob(new(nothrow) UninitializeJob(reference)); 527 } 528 529 530 // _GenerateSetContentNameJob 531 status_t 532 DiskDeviceJobGenerator::_GenerateSetContentNameJob(BPartition* partition) 533 { 534 PartitionReference* reference; 535 status_t error = _GetPartitionReference(partition, reference); 536 if (error != B_OK) 537 return error; 538 539 SetStringJob* job = new(nothrow) SetStringJob(reference); 540 if (!job) 541 return B_NO_MEMORY; 542 543 error = job->Init(partition->ContentName(), 544 B_DISK_DEVICE_JOB_SET_CONTENT_NAME); 545 if (error != B_OK) { 546 delete job; 547 return error; 548 } 549 550 return _AddJob(job); 551 } 552 553 554 // _GenerateSetContentParametersJob 555 status_t 556 DiskDeviceJobGenerator::_GenerateSetContentParametersJob(BPartition* partition) 557 { 558 PartitionReference* reference; 559 status_t error = _GetPartitionReference(partition, reference); 560 if (error != B_OK) 561 return error; 562 563 SetStringJob* job = new(nothrow) SetStringJob(reference); 564 if (!job) 565 return B_NO_MEMORY; 566 567 error = job->Init(partition->ContentParameters(), 568 B_DISK_DEVICE_JOB_SET_CONTENT_PARAMETERS); 569 if (error != B_OK) { 570 delete job; 571 return error; 572 } 573 574 return _AddJob(job); 575 } 576 577 578 // _GenerateDefragmentJob 579 status_t 580 DiskDeviceJobGenerator::_GenerateDefragmentJob(BPartition* partition) 581 { 582 PartitionReference* reference; 583 status_t error = _GetPartitionReference(partition, reference); 584 if (error != B_OK) 585 return error; 586 587 return _AddJob(new(nothrow) DefragmentJob(reference)); 588 } 589 590 591 // _GenerateRepairJob 592 status_t 593 DiskDeviceJobGenerator::_GenerateRepairJob(BPartition* partition, bool repair) 594 { 595 PartitionReference* reference; 596 status_t error = _GetPartitionReference(partition, reference); 597 if (error != B_OK) 598 return error; 599 600 return _AddJob(new(nothrow) RepairJob(reference, repair)); 601 } 602 603 604 // _GenerateCreateChildJob 605 status_t 606 DiskDeviceJobGenerator::_GenerateCreateChildJob(BPartition* parent, 607 BPartition* partition) 608 { 609 PartitionReference* parentReference; 610 status_t error = _GetPartitionReference(parent, parentReference); 611 if (error != B_OK) 612 return error; 613 614 PartitionReference* reference; 615 error = _GetPartitionReference(partition, reference); 616 if (error != B_OK) 617 return error; 618 619 CreateChildJob* job = new(nothrow) CreateChildJob(parentReference, 620 reference); 621 if (!job) 622 return B_NO_MEMORY; 623 624 error = job->Init(partition->Offset(), partition->Size(), partition->Type(), 625 partition->Name(), partition->Parameters()); 626 if (error != B_OK) { 627 delete job; 628 return error; 629 } 630 631 return _AddJob(job); 632 } 633 634 635 // _GenerateDeleteChildJob 636 status_t 637 DiskDeviceJobGenerator::_GenerateDeleteChildJob(BPartition* parent, 638 BPartition* partition) 639 { 640 PartitionReference* parentReference; 641 status_t error = _GetPartitionReference(parent, parentReference); 642 if (error != B_OK) 643 return error; 644 645 PartitionReference* reference; 646 error = _GetPartitionReference(partition, reference); 647 if (error != B_OK) 648 return error; 649 650 return _AddJob(new(nothrow) DeleteChildJob(parentReference, reference)); 651 } 652 653 654 // _GenerateResizeJob 655 status_t 656 DiskDeviceJobGenerator::_GenerateResizeJob(BPartition* partition) 657 { 658 BPartition* parent = partition->Parent(); 659 if (!parent) 660 return B_BAD_VALUE; 661 662 PartitionReference* parentReference; 663 status_t error = _GetPartitionReference(parent, parentReference); 664 if (error != B_OK) 665 return error; 666 667 PartitionReference* reference; 668 error = _GetPartitionReference(partition, reference); 669 if (error != B_OK) 670 return error; 671 672 return _AddJob(new(nothrow) ResizeJob(parentReference, reference, 673 partition->Size(), partition->ContentSize())); 674 } 675 676 677 // _GenerateMoveJob 678 status_t 679 DiskDeviceJobGenerator::_GenerateMoveJob(BPartition* partition) 680 { 681 BPartition* parent = partition->Parent(); 682 if (!parent) 683 return B_BAD_VALUE; 684 685 PartitionReference* parentReference; 686 status_t error = _GetPartitionReference(parent, parentReference); 687 if (error != B_OK) 688 return error; 689 690 PartitionReference* reference; 691 error = _GetPartitionReference(partition, reference); 692 if (error != B_OK) 693 return error; 694 695 // collect all descendants whose contents need to be moved 696 fContentsToMoveCount = 0; 697 error = _CollectContentsToMove(partition); 698 if (error != B_OK) 699 return B_OK; 700 701 // create and init the job 702 MoveJob* job = new(nothrow) MoveJob(parentReference, reference); 703 if (!job) 704 return B_NO_MEMORY; 705 706 error = job->Init(partition->Offset(), fContentsToMove, 707 fContentsToMoveCount); 708 if (error != B_OK) { 709 delete job; 710 return error; 711 } 712 713 return _AddJob(job); 714 } 715 716 717 // _GenerateSetNameJob 718 status_t 719 DiskDeviceJobGenerator::_GenerateSetNameJob(BPartition* parent, 720 BPartition* partition) 721 { 722 PartitionReference* parentReference; 723 status_t error = _GetPartitionReference(parent, parentReference); 724 if (error != B_OK) 725 return error; 726 727 PartitionReference* reference; 728 error = _GetPartitionReference(partition, reference); 729 if (error != B_OK) 730 return error; 731 732 SetStringJob* job = new(nothrow) SetStringJob(parentReference, reference); 733 if (!job) 734 return B_NO_MEMORY; 735 736 error = job->Init(partition->Name(), B_DISK_DEVICE_JOB_SET_NAME); 737 if (error != B_OK) { 738 delete job; 739 return error; 740 } 741 742 return _AddJob(job); 743 } 744 745 746 // _GenerateSetTypeJob 747 status_t 748 DiskDeviceJobGenerator::_GenerateSetTypeJob(BPartition* parent, 749 BPartition* partition) 750 { 751 PartitionReference* parentReference; 752 status_t error = _GetPartitionReference(parent, parentReference); 753 if (error != B_OK) 754 return error; 755 756 PartitionReference* reference; 757 error = _GetPartitionReference(partition, reference); 758 if (error != B_OK) 759 return error; 760 761 SetStringJob* job = new(nothrow) SetStringJob(parentReference, reference); 762 if (!job) 763 return B_NO_MEMORY; 764 765 error = job->Init(partition->Type(), B_DISK_DEVICE_JOB_SET_TYPE); 766 if (error != B_OK) { 767 delete job; 768 return error; 769 } 770 771 return _AddJob(job); 772 } 773 774 775 // _GenerateSetParametersJob 776 status_t 777 DiskDeviceJobGenerator::_GenerateSetParametersJob(BPartition* parent, 778 BPartition* partition) 779 { 780 PartitionReference* parentReference; 781 status_t error = _GetPartitionReference(parent, parentReference); 782 if (error != B_OK) 783 return error; 784 785 PartitionReference* reference; 786 error = _GetPartitionReference(partition, reference); 787 if (error != B_OK) 788 return error; 789 790 SetStringJob* job = new(nothrow) SetStringJob(parentReference, reference); 791 if (!job) 792 return B_NO_MEMORY; 793 794 error = job->Init(partition->Parameters(), 795 B_DISK_DEVICE_JOB_SET_PARAMETERS); 796 if (error != B_OK) { 797 delete job; 798 return error; 799 } 800 801 return _AddJob(job); 802 } 803 804 805 // _CollectContentsToMove 806 status_t 807 DiskDeviceJobGenerator::_CollectContentsToMove(BPartition* partition) 808 { 809 BMutablePartition* shadow = _GetMutablePartition(partition); 810 if (shadow->Status() == B_PARTITION_UNRECOGNIZED) 811 return B_ERROR; 812 813 // if the partition has contents, push its ID 814 if (shadow->ContentType() 815 && !(shadow->ChangeFlags() & B_PARTITION_CHANGED_INITIALIZATION)) { 816 status_t error = _PushContentsToMove(partition); 817 if (error != B_OK) 818 return error; 819 } 820 821 // recurse 822 for (int32 i = 0; BPartition* child = partition->ChildAt(i); i++) { 823 status_t error = _CollectContentsToMove(child); 824 if (error != B_OK) 825 return error; 826 } 827 return B_OK; 828 } 829 830 831 // _PushContentsToMove 832 status_t 833 DiskDeviceJobGenerator::_PushContentsToMove(BPartition* partition) 834 { 835 if (fContentsToMoveCount >= fPartitionCount) 836 return B_ERROR; 837 838 PartitionReference* reference; 839 status_t error = _GetPartitionReference(partition, reference); 840 if (error != B_OK) 841 return error; 842 843 fContentsToMove[fContentsToMoveCount++] = reference; 844 845 return B_OK; 846 } 847 848 849 // _GetPartitionReference 850 status_t 851 DiskDeviceJobGenerator::_GetPartitionReference(BPartition* partition, 852 PartitionReference*& reference) 853 { 854 if (!partition) 855 return B_BAD_VALUE; 856 857 for (int32 i = 0; i < fPartitionCount; i++) { 858 PartitionRefInfo& info = fPartitionRefs[i]; 859 860 if (info.partition == partition) { 861 reference = info.reference; 862 return B_OK; 863 } 864 865 if (info.partition == NULL) { 866 // create partition reference 867 info.reference = new(nothrow) PartitionReference(); 868 if (!info.reference) 869 return B_NO_MEMORY; 870 871 // set partition ID and change counter 872 user_partition_data* partitionData = partition->fPartitionData; 873 if (partitionData) { 874 info.reference->SetPartitionID(partitionData->id); 875 info.reference->SetChangeCounter(partitionData->change_counter); 876 } 877 878 info.partition = partition; 879 reference = info.reference; 880 return B_OK; 881 } 882 } 883 884 // Out of slots -- that can't happen. 885 return B_ERROR; 886 } 887 888 889 // _CompareMoveInfoOffset 890 int 891 DiskDeviceJobGenerator::_CompareMoveInfoPosition(const void* _a, const void* _b) 892 { 893 const MoveInfo* a = static_cast<const MoveInfo*>(_a); 894 const MoveInfo* b = static_cast<const MoveInfo*>(_b); 895 if (a->position < b->position) 896 return -1; 897 if (a->position > b->position) 898 return 1; 899 return 0; 900 } 901