1 /* 2 * Copyright 2003-2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold, ingo_weinhold@gmx.de 7 * Tomas Kucera, kucerat@centrum.cz 8 */ 9 10 11 #include "write_support.h" 12 13 #include <errno.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 18 #include <new> 19 20 #include <DiskDeviceTypes.h> 21 #include <KernelExport.h> 22 23 #include <AutoDeleter.h> 24 25 #include "intel.h" 26 #include "PartitionLocker.h" 27 #include "PartitionMap.h" 28 #include "PartitionMapParser.h" 29 #include "PartitionMapWriter.h" 30 31 32 //#define TRACE(x) ; 33 #define TRACE(x) dprintf x 34 35 // Maximal size of move buffer (in sectors). 36 static const int32 MAX_MOVE_BUFFER = 2 * 1024 * 4; 37 38 // for logical partitions in Intel Extended Partition 39 // Count of free sectors after Partition Table Sector (at logical partition). 40 static const uint32 FREE_SECTORS_AFTER_PTS = 63; 41 // Count of free sectors after Master Boot Record. 42 static const uint32 FREE_SECTORS_AFTER_MBR = 63; 43 // size of logical partition header in blocks 44 static const uint32 PTS_OFFSET = FREE_SECTORS_AFTER_PTS + 1; 45 static const uint32 MBR_OFFSET = FREE_SECTORS_AFTER_MBR + 1; 46 47 48 typedef partitionable_space_data PartitionPosition; 49 50 typedef void (*fc_get_sibling_partitions)(partition_data* partition, 51 partition_data* child, off_t childOffset, partition_data** prec, 52 partition_data** follow, off_t* prec_offset, off_t* prec_size, 53 off_t* follow_offset, off_t* follow_size); 54 55 typedef int32 (*fc_fill_partitionable_spaces_buffer)(partition_data* partition, 56 PartitionPosition* positions); 57 58 59 status_t pm_get_partitionable_spaces(partition_data* partition, 60 partitionable_space_data* buffer, int32 count, int32* actualCount); 61 status_t ep_get_partitionable_spaces(partition_data* partition, 62 partitionable_space_data* buffer, int32 count, int32* actualCount); 63 64 65 // #pragma mark - Intel Partition Map - support functions 66 67 68 // pm_get_supported_operations 69 uint32 70 pm_get_supported_operations(partition_data* partition, uint32 mask) 71 { 72 uint32 flags = B_DISK_SYSTEM_SUPPORTS_RESIZING 73 | B_DISK_SYSTEM_SUPPORTS_MOVING 74 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 75 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING; 76 77 // creating child 78 int32 countSpaces = 0; 79 if (partition->child_count < 4 80 // free space check 81 && pm_get_partitionable_spaces(partition, NULL, 0, &countSpaces) 82 == B_BUFFER_OVERFLOW 83 && countSpaces > 0) { 84 flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD; 85 } 86 87 return flags; 88 } 89 90 91 // pm_get_supported_child_operations 92 uint32 93 pm_get_supported_child_operations(partition_data* partition, 94 partition_data* child, uint32 mask) 95 { 96 return B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 97 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 98 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 99 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD; 100 } 101 102 103 // pm_is_sub_system_for 104 bool 105 pm_is_sub_system_for(partition_data* partition) 106 { 107 // primary partition map doesn't naturally live in any other child partition 108 return false; 109 } 110 111 bool 112 get_partition_from_offset_ep(partition_data* partition, off_t offset, 113 partition_data** nextPartition) 114 { 115 for (int32 i = 0; i < partition->child_count; i++) { 116 partition_data* sibling = get_child_partition(partition->id, i); 117 if (sibling != NULL && sibling->offset == offset) { 118 *nextPartition = sibling; 119 return true; 120 } 121 } 122 123 return false; 124 } 125 126 127 // #pragma mark - Intel Partition Map - validate functions 128 129 130 // sector_align (auxiliary function) 131 static inline off_t 132 sector_align(off_t offset, int32 blockSize) 133 { 134 return offset / blockSize * blockSize; 135 } 136 137 138 // sector_align_up (auxiliary function) 139 static inline off_t 140 sector_align_up(off_t offset, int32 blockSize) 141 { 142 return (offset + blockSize - 1) / blockSize * blockSize; 143 } 144 145 146 // validate_resize (auxiliary function) 147 static bool 148 validate_resize(partition_data* partition, off_t* size) 149 { 150 off_t newSize = *size; 151 // size remains the same? 152 if (newSize == partition->size) 153 return true; 154 155 if (newSize < 0) 156 newSize = 0; 157 else 158 newSize = sector_align(newSize, partition->block_size); 159 160 // grow partition? 161 if (newSize > partition->size) { 162 *size = newSize; 163 return true; 164 } 165 166 // shrink partition 167 // no child has to be over the new size of the parent partition 168 // TODO: shouldn't be just: off_t currentEnd = newSize; ??? probably not 169 // If child->offset is relative to parent, then yes! 170 off_t currentEnd = partition->offset + newSize; 171 for (int32 i = 0; i < partition->child_count; i++) { 172 partition_data* child = get_child_partition(partition->id, i); 173 if (child && child->offset + child->size > currentEnd) 174 currentEnd = child->offset + child->size; 175 } 176 newSize = currentEnd - partition->offset; 177 // make the size a multiple of the block size (greater one) 178 newSize = sector_align_up(newSize, partition->block_size); 179 *size = newSize; 180 return true; 181 } 182 183 184 // pm_validate_resize 185 bool 186 pm_validate_resize(partition_data* partition, off_t* size) 187 { 188 TRACE(("intel: pm_validate_resize\n")); 189 190 if (!partition || !size) 191 return false; 192 193 return validate_resize(partition, size); 194 } 195 196 197 // get_sibling_partitions_pm (auxiliary function) 198 /*! 199 according to childOffset returns previous and next sibling or NULL 200 precious, next output parameters 201 partition - Intel Partition Map 202 */ 203 static void 204 get_sibling_partitions_pm(partition_data* partition, 205 partition_data* child, off_t childOffset, partition_data** previous, 206 partition_data** next, off_t* previousOffset, off_t* previousSize, 207 off_t* nextOffset, off_t* nextSize) 208 { 209 // finding out sibling partitions 210 partition_data* previousSibling = NULL; 211 partition_data* nextSibling = NULL; 212 for (int32 i = 0; i < partition->child_count; i++) { 213 partition_data* sibling = get_child_partition(partition->id, i); 214 if (sibling && sibling != child) { 215 if (sibling->offset <= childOffset) { 216 if (!previousSibling || previousSibling->offset < sibling->offset) 217 previousSibling = sibling; 218 } else { 219 // sibling->offset > childOffset 220 if (!nextSibling || nextSibling->offset > sibling->offset) 221 nextSibling = sibling; 222 } 223 } 224 } 225 *previous = previousSibling; 226 *next = nextSibling; 227 if (previousSibling) { 228 *previousOffset = previousSibling->offset; 229 *previousSize = previousSibling->size; 230 } 231 if (nextSibling) { 232 *nextOffset = nextSibling->offset; 233 *nextSize = nextSibling->size; 234 } 235 } 236 237 238 // get_sibling_partitions_ep (auxiliary function) 239 /*! 240 according to childOffset returns previous and next sibling or NULL 241 previous, next output parameters 242 partition - Intel Extended Partition 243 */ 244 static void 245 get_sibling_partitions_ep(partition_data* partition, 246 partition_data* child, off_t childOffset, partition_data** previous, 247 partition_data** next, off_t* previousOffset, off_t* previousSize, 248 off_t* nextOffset, off_t* nextSize) 249 { 250 // finding out sibling partitions 251 partition_data* previousSibling = NULL; 252 partition_data* nextSibling = NULL; 253 for (int32 i = 0; i < partition->child_count; i++) { 254 partition_data* sibling = get_child_partition(partition->id, i); 255 if (sibling && sibling != child) { 256 if (sibling->offset <= childOffset) { 257 if (!previousSibling || previousSibling->offset < sibling->offset) 258 previousSibling = sibling; 259 } else { 260 // get_offset_ep(sibling) > childOffset 261 if (!nextSibling || nextSibling->offset > sibling->offset) 262 nextSibling = sibling; 263 } 264 } 265 } 266 *previous = previousSibling; 267 *next = nextSibling; 268 if (previousSibling) { 269 *previousOffset = previousSibling->offset; 270 *previousSize = previousSibling->size; 271 } 272 if (nextSibling) { 273 *nextOffset = nextSibling->offset; 274 *nextSize = nextSibling->size; 275 } 276 } 277 278 279 // validate_resize_child (auxiliary function) 280 static bool 281 validate_resize_child(partition_data* partition, partition_data* child, 282 off_t childOffset, off_t childSize, off_t* size, 283 fc_get_sibling_partitions getSiblingPartitions) 284 { 285 // size remains the same? 286 if (*size == childSize) 287 return true; 288 // shrink partition? 289 if (*size < childSize) { 290 if (*size < 0) 291 *size = 0; 292 // make the size a multiple of the block size 293 *size = sector_align(*size, partition->block_size); 294 return true; 295 } 296 // grow partition 297 // child must completely lie within the parent partition 298 if (childOffset + *size > partition->offset + partition->size) 299 *size = partition->offset + partition->size - childOffset; 300 301 // child must not intersect with sibling partitions 302 // finding out sibling partitions 303 partition_data* previousSibling = NULL; 304 partition_data* nextSibling = NULL; 305 off_t previousOffset = 0, previousSize = 0, nextOffset = 0, nextSize = 0; 306 307 getSiblingPartitions(partition, child, childOffset, &previousSibling, 308 &nextSibling, &previousOffset, &previousSize, &nextOffset, &nextSize); 309 310 if (nextSibling && (nextOffset < childOffset + *size)) 311 *size = nextOffset - childOffset; 312 *size = sector_align(*size, partition->block_size); 313 return true; 314 } 315 316 317 // pm_validate_resize_child 318 bool 319 pm_validate_resize_child(partition_data* partition, partition_data* child, 320 off_t* size) 321 { 322 TRACE(("intel: pm_validate_resize_child\n")); 323 324 if (!partition || !child || !size) 325 return false; 326 327 return validate_resize_child(partition, child, child->offset, 328 child->size, size, get_sibling_partitions_pm); 329 } 330 331 332 // pm_validate_move 333 bool 334 pm_validate_move(partition_data* partition, off_t* start) 335 { 336 TRACE(("intel: pm_validate_move\n")); 337 338 if (!partition || !start) 339 return false; 340 // nothing to do here 341 return true; 342 } 343 344 345 // validate_move_child (auxiliary function) 346 static bool 347 validate_move_child(partition_data* partition, partition_data* child, 348 off_t childOffset, off_t childSize, off_t* _start, 349 fc_get_sibling_partitions getSiblingPartitions) 350 { 351 off_t start = *_start; 352 353 if (start < 0) 354 start = 0; 355 else if (start + childSize > partition->size) 356 start = partition->size - childSize; 357 358 start = sector_align(start, partition->block_size); 359 360 // finding out sibling partitions 361 partition_data* previousSibling = NULL; 362 partition_data* nextSibling = NULL; 363 off_t previousOffset = 0, previousSize = 0, nextOffset = 0, nextSize = 0; 364 365 getSiblingPartitions(partition, child, childOffset, &previousSibling, 366 &nextSibling, &previousOffset, &previousSize, &nextOffset, &nextSize); 367 368 // we cannot move child over sibling partition 369 if (start < childOffset) { 370 // moving left 371 if (previousSibling && previousOffset + previousSize > start) { 372 start = previousOffset + previousSize; 373 start = sector_align_up(start, partition->block_size); 374 } 375 } else { 376 // moving right 377 if (nextSibling && nextOffset < start + childSize) { 378 start = nextOffset - childSize; 379 start = sector_align(start, partition->block_size); 380 } 381 } 382 *_start = start; 383 return true; 384 } 385 386 387 // pm_validate_move_child 388 bool 389 pm_validate_move_child(partition_data* partition, partition_data* child, 390 off_t* start) 391 { 392 TRACE(("intel: pm_validate_move_child\n")); 393 394 if (!partition || !child || !start) 395 return false; 396 if (*start == child->offset) 397 return true; 398 399 return validate_move_child(partition, child, child->offset, 400 child->size, start, get_sibling_partitions_pm); 401 } 402 403 // is_type_valid_pm (auxiliary function) 404 /*! 405 type has to be known, only one extended partition is allowed 406 partition - intel partition map 407 child can be NULL 408 */ 409 static bool 410 is_type_valid_pm(const char* type, partition_data* partition, 411 PrimaryPartition* child = NULL) 412 { 413 // validity check of the type 414 PartitionType ptype; 415 ptype.SetType(type); 416 if (!ptype.IsValid() || ptype.IsEmpty()) 417 return false; 418 419 // only one extended partition is allowed 420 if (ptype.IsExtended()) { 421 PartitionMap* map = (PartitionMap*)partition->content_cookie; 422 if (!map) 423 return false; 424 for (int32 i = 0; i < partition->child_count; i++) { 425 PrimaryPartition* primary = map->PrimaryPartitionAt(i); 426 if (primary && primary->IsExtended() && primary != child) 427 return false; 428 } 429 } 430 return true; 431 } 432 433 434 // pm_validate_set_type 435 bool 436 pm_validate_set_type(partition_data* partition, const char* type) 437 { 438 TRACE(("intel: pm_validate_set_type\n")); 439 440 if (!partition || !type) 441 return false; 442 443 partition_data* parent = get_parent_partition(partition->id); 444 if (!parent) 445 return false; 446 PrimaryPartition* child = (PrimaryPartition*)partition->cookie; 447 if (!child) 448 return false; 449 450 // validity check of the type 451 return is_type_valid_pm(type, parent, child); 452 } 453 454 // pm_validate_initialize 455 bool 456 pm_validate_initialize(partition_data* partition, char* name, 457 const char* parameters) 458 { 459 TRACE(("intel: pm_validate_initialize\n")); 460 461 if (!partition || !(pm_get_supported_operations(partition) 462 & B_DISK_SYSTEM_SUPPORTS_INITIALIZING)) { 463 return false; 464 } 465 466 // name is ignored 467 if (name) 468 name[0] = '\0'; 469 470 // parameters are ignored, too 471 472 return true; 473 } 474 475 476 // validate_create_child_partition (auxiliary function) 477 static bool 478 validate_create_child_partition(partition_data* partition, off_t* start, 479 off_t* size, fc_get_sibling_partitions getSiblingPartitions) 480 { 481 // make the start and size a multiple of the block size 482 *start = sector_align(*start, partition->block_size); 483 if (*size < 0) 484 *size = 0; 485 else 486 *size = sector_align(*size, partition->block_size); 487 488 // child must completely lie within the parent partition 489 if (*start >= partition->offset + partition->size) 490 return false; 491 if (*start + *size > partition->offset + partition->size) 492 *size = partition->offset + partition->size - *start; 493 494 // new child must not intersect with sibling partitions 495 // finding out sibling partitions 496 partition_data* previousSibling = NULL; 497 partition_data* nextSibling = NULL; 498 off_t previousOffset = 0, previousSize = 0, nextOffset = 0, nextSize = 0; 499 500 getSiblingPartitions(partition, NULL, *start, &previousSibling, 501 &nextSibling, &previousOffset, &previousSize, &nextOffset, &nextSize); 502 503 // position check of the new partition 504 if (previousSibling && (previousOffset + previousSize > *start)) { 505 *start = previousOffset + previousSize; 506 *start = sector_align_up(*start, partition->block_size); 507 } 508 509 if (nextSibling && (nextOffset < *start + *size)) 510 *size = nextOffset - *start; 511 *size = sector_align(*size, partition->block_size); 512 if (*size == 0) 513 return false; 514 515 return true; 516 } 517 518 519 // pm_validate_create_child 520 /*! 521 index - returns position of the new partition (first free record in MBR) 522 */ 523 bool 524 pm_validate_create_child(partition_data* partition, off_t* start, off_t* size, 525 const char* type, const char* name, const char* parameters, int32* index) 526 { 527 TRACE(("intel: pm_validate_create_child\n")); 528 529 if (!partition || !(pm_get_supported_operations(partition) 530 & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) 531 || !start || !size || !type || !index) { 532 return false; 533 } 534 535 // TODO: check name 536 // TODO: check parameters 537 // type check 538 if (!is_type_valid_pm(type, partition)) 539 return false; 540 541 // finding out index of the new partition (first free record in MBR) 542 // at least one record has to be free 543 PartitionMap* map = (PartitionMap*)partition->content_cookie; 544 if (!map) 545 return false; 546 int32 newIndex = -1; 547 for (int32 i = 0; i < 4; i++) { 548 PrimaryPartition* primary = map->PrimaryPartitionAt(i); 549 if (primary->IsEmpty()) { 550 newIndex = i; 551 break; 552 } 553 } 554 // this cannot happen 555 if (newIndex < 0) 556 return false; 557 *index = newIndex; 558 559 if (*start < partition->offset + MBR_OFFSET * partition->block_size) { 560 *start = partition->offset + MBR_OFFSET * partition->block_size; 561 *start = sector_align_up(*start, partition->block_size); 562 } 563 564 return validate_create_child_partition(partition, start, size, 565 get_sibling_partitions_pm); 566 } 567 568 569 // cmp_partition_position 570 static int 571 cmp_partition_position(const void* o1, const void* o2) 572 { 573 off_t offset1 = ((PartitionPosition*)o1)->offset; 574 off_t offset2 = ((PartitionPosition*)o2)->offset; 575 576 if (offset1 < offset2) 577 return -1; 578 if (offset1 > offset2) 579 return 1; 580 581 return 0; 582 } 583 584 585 // fill_partitionable_spaces_buffer_pm 586 /*! 587 positions - output buffer with sufficient size 588 returns partition count 589 */ 590 static int32 591 fill_partitionable_spaces_buffer_pm(partition_data* partition, 592 PartitionPosition* positions) 593 { 594 int32 partition_count = 0; 595 for (int32 i = 0; i < partition->child_count; i++) { 596 const partition_data* child = get_child_partition(partition->id, i); 597 if (child) { 598 positions[partition_count].offset = child->offset; 599 positions[partition_count].size = child->size; 600 partition_count++; 601 } 602 } 603 return partition_count; 604 } 605 606 607 // fill_partitionable_spaces_buffer_ep 608 /*! 609 positions - output buffer with sufficient size 610 returns partition count 611 */ 612 static int32 613 fill_partitionable_spaces_buffer_ep(partition_data* partition, 614 PartitionPosition* positions) 615 { 616 int32 partition_count = 0; 617 for (int32 i = 0; i < partition->child_count; i++) { 618 const partition_data* child = get_child_partition(partition->id, i); 619 if (child) { 620 positions[partition_count].offset = child->offset; 621 positions[partition_count].size = child->size; 622 partition_count++; 623 } 624 } 625 return partition_count; 626 } 627 628 629 // get_partitionable_spaces (auxiliary function) 630 static status_t 631 get_partitionable_spaces(partition_data* partition, 632 partitionable_space_data* buffer, int32 count, int32* _actualCount, 633 fc_fill_partitionable_spaces_buffer fillBuffer, off_t startOffset, 634 off_t limitSize = 0, off_t headerSize = 0) 635 { 636 PartitionPosition* positions 637 = new(nothrow) PartitionPosition[partition->child_count]; 638 if (!positions) 639 return B_NO_MEMORY; 640 // fill the array 641 int32 partition_count = fillBuffer(partition, positions); 642 // sort the array 643 qsort(positions, partition_count, sizeof(PartitionPosition), 644 cmp_partition_position); 645 646 // first sektor is MBR or EBR 647 off_t offset = startOffset + headerSize; 648 off_t size = 0; 649 int32 actualCount = 0; 650 651 // offset alignment (to upper bound) 652 offset = sector_align_up(offset, partition->block_size); 653 // finding out all partitionable spaces 654 for (int32 i = 0; i < partition_count; i++) { 655 size = positions[i].offset - offset; 656 size = sector_align(size, partition->block_size); 657 if (size >= limitSize) { 658 if (actualCount < count) { 659 buffer[actualCount].offset = offset; 660 buffer[actualCount].size = size; 661 } 662 actualCount++; 663 } 664 offset = positions[i].offset + positions[i].size + headerSize; 665 offset = sector_align_up(offset, partition->block_size); 666 } 667 // space in the end of partition 668 size = partition->offset + partition->size - offset; 669 size = sector_align(size, partition->block_size); 670 if (size > 0) { 671 if (actualCount < count) { 672 buffer[actualCount].offset = offset; 673 buffer[actualCount].size = size; 674 } 675 actualCount++; 676 } 677 678 // cleanup 679 if (positions) 680 delete[] positions; 681 682 TRACE(("intel: get_partitionable_spaces - found: %ld\n", actualCount)); 683 684 *_actualCount = actualCount; 685 686 if (count < actualCount) 687 return B_BUFFER_OVERFLOW; 688 return B_OK; 689 } 690 691 692 // pm_get_partitionable_spaces 693 status_t 694 pm_get_partitionable_spaces(partition_data* partition, 695 partitionable_space_data* buffer, int32 count, int32* actualCount) 696 { 697 TRACE(("intel: pm_get_partitionable_spaces\n")); 698 699 if (!partition || !partition->content_type 700 || strcmp(partition->content_type, kPartitionTypeIntel) 701 || !actualCount) { 702 return B_BAD_VALUE; 703 } 704 if (count > 0 && !buffer) 705 return B_BAD_VALUE; 706 707 return get_partitionable_spaces(partition, buffer, count, actualCount, 708 fill_partitionable_spaces_buffer_pm, MBR_OFFSET * partition->block_size, 709 0, 0); 710 } 711 712 713 // pm_get_next_supported_type 714 status_t 715 pm_get_next_supported_type(partition_data* partition, int32* cookie, 716 char* _type) 717 { 718 TRACE(("intel: pm_get_next_supported_type\n")); 719 720 if (!partition || !partition->content_type 721 || strcmp(partition->content_type, kPartitionTypeIntel) 722 || !cookie || !_type) { 723 return B_BAD_VALUE; 724 } 725 726 if (*cookie > 255) 727 return B_ENTRY_NOT_FOUND; 728 if (*cookie < 1) 729 *cookie = 1; 730 731 uint8 type = *cookie; 732 733 // get type 734 PartitionType ptype; 735 ptype.SetType(type); 736 if (!ptype.IsValid()) 737 return B_ENTRY_NOT_FOUND; 738 739 ptype.GetTypeString(_type); 740 741 // find next type 742 if (ptype.FindNext()) 743 *cookie = ptype.Type(); 744 else 745 *cookie = 256; 746 747 return B_OK; 748 } 749 750 // pm_shadow_changed 751 status_t 752 pm_shadow_changed(partition_data* partition, partition_data* child, 753 uint32 operation) 754 { 755 TRACE(("intel: pm_shadow_changed(%p, %p, %lu)\n", partition, child, 756 operation)); 757 758 switch (operation) { 759 case B_PARTITION_SHADOW: 760 { 761 // get the physical partition 762 partition_data* physicalPartition = get_partition( 763 partition->id); 764 if (!physicalPartition) { 765 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW): no " 766 "physical partition with ID %ld\n", partition->id); 767 return B_ERROR; 768 } 769 770 // clone the map 771 if (!physicalPartition->content_cookie) { 772 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW): no " 773 "content cookie, physical partition: %ld\n", partition->id); 774 return B_ERROR; 775 } 776 777 PartitionMapCookie* map = new(nothrow) PartitionMapCookie; 778 if (!map) 779 return B_NO_MEMORY; 780 781 status_t error = map->Assign( 782 *(PartitionMapCookie*)physicalPartition->content_cookie); 783 if (error != B_OK) { 784 delete map; 785 return error; 786 } 787 788 partition->content_cookie = map; 789 790 return B_OK; 791 } 792 793 case B_PARTITION_SHADOW_CHILD: 794 { 795 // get the physical child partition 796 partition_data* physical = get_partition(child->id); 797 if (!physical) { 798 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): " 799 "no physical partition with ID %ld\n", child->id); 800 return B_ERROR; 801 } 802 803 if (!physical->cookie) { 804 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): " 805 "no cookie, physical partition: %ld\n", child->id); 806 return B_ERROR; 807 } 808 809 // primary partition index 810 int32 index = ((PrimaryPartition*)physical->cookie)->Index(); 811 812 if (!partition->content_cookie) { 813 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): " 814 "no content cookie, physical partition: %ld\n", 815 partition->id); 816 return B_ERROR; 817 } 818 819 // get the primary partition 820 PartitionMapCookie* map 821 = ((PartitionMapCookie*)partition->content_cookie); 822 PrimaryPartition* primary = map->PrimaryPartitionAt(index); 823 824 if (!primary || primary->IsEmpty()) { 825 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): " 826 "partition %ld is empty, primary index: %ld\n", child->id, 827 index); 828 return B_BAD_VALUE; 829 } 830 831 child->cookie = primary; 832 833 return B_OK; 834 } 835 836 case B_PARTITION_INITIALIZE: 837 { 838 // create an empty partition map 839 PartitionMapCookie* map = new(nothrow) PartitionMapCookie; 840 if (!map) 841 return B_NO_MEMORY; 842 843 partition->content_cookie = map; 844 845 return B_OK; 846 } 847 848 case B_PARTITION_CREATE_CHILD: 849 { 850 if (!partition->content_cookie) { 851 dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): " 852 "no content cookie, partition: %ld\n", partition->id); 853 return B_ERROR; 854 } 855 856 PartitionMapCookie* map 857 = ((PartitionMapCookie*)partition->content_cookie); 858 859 // find an empty primary partition slot 860 PrimaryPartition* primary = NULL; 861 for (int32 i = 0; i < 4; i++) { 862 if (map->PrimaryPartitionAt(i)->IsEmpty()) { 863 primary = map->PrimaryPartitionAt(i); 864 break; 865 } 866 } 867 868 if (!primary) { 869 dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): " 870 "no empty primary slot, partition: %ld\n", partition->id); 871 return B_ERROR; 872 } 873 874 // apply type 875 PartitionType type; 876 type.SetType(child->type); 877 if (!type.IsValid()) { 878 dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): " 879 "invalid partition type, partition: %ld\n", partition->id); 880 return B_ERROR; 881 } 882 883 primary->SetType(type.Type()); 884 885 // TODO: Apply parameters! 886 887 child->cookie = primary; 888 889 return B_OK; 890 } 891 892 case B_PARTITION_DEFRAGMENT: 893 case B_PARTITION_REPAIR: 894 case B_PARTITION_RESIZE: 895 case B_PARTITION_RESIZE_CHILD: 896 case B_PARTITION_MOVE: 897 case B_PARTITION_MOVE_CHILD: 898 case B_PARTITION_SET_NAME: 899 case B_PARTITION_SET_CONTENT_NAME: 900 case B_PARTITION_SET_TYPE: 901 case B_PARTITION_SET_PARAMETERS: 902 case B_PARTITION_SET_CONTENT_PARAMETERS: 903 case B_PARTITION_DELETE_CHILD: 904 break; 905 } 906 907 return B_ERROR; 908 } 909 910 911 // #pragma mark - Intel Partition Map - writing functions 912 913 914 // pm_resize 915 status_t 916 pm_resize(int fd, partition_id partitionID, off_t size, disk_job_id job) 917 { 918 TRACE(("intel: pm_resize\n")); 919 920 if (fd < 0) 921 return B_ERROR; 922 923 PartitionWriteLocker locker(partitionID); 924 if (!locker.IsLocked()) 925 return B_ERROR; 926 927 // get out partition 928 partition_data* partition = get_partition(partitionID); 929 if (!partition) 930 return B_BAD_VALUE; 931 932 // validate the new size 933 // TODO: The parameter has already been checked and must not be altered! 934 off_t validatedSize = size; 935 if (!pm_validate_resize(partition, &validatedSize)) 936 return B_BAD_VALUE; 937 938 // update data stuctures 939 update_disk_device_job_progress(job, 0.0); 940 941 // TODO: partition->size is not supposed to be touched. 942 partition->size = validatedSize; 943 partition->content_size = validatedSize; 944 945 // all changes applied 946 update_disk_device_job_progress(job, 1.0); 947 partition_modified(partitionID); 948 return B_OK; 949 } 950 951 952 // pm_resize_child 953 status_t 954 pm_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job) 955 { 956 TRACE(("intel: pm_resize_child\n")); 957 958 if (fd < 0) 959 return B_ERROR; 960 961 PartitionWriteLocker locker(partitionID); 962 if (!locker.IsLocked()) 963 return B_ERROR; 964 965 // get out partition, child and partition map structure 966 partition_data* partition = get_parent_partition(partitionID); 967 partition_data* child = get_partition(partitionID); 968 if (!partition || !child) 969 return B_BAD_VALUE; 970 PartitionMap* map = (PartitionMap*)partition->content_cookie; 971 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 972 if (!map || !primary) 973 return B_BAD_VALUE; 974 975 // validate the new size 976 // TODO: The parameter has already been checked and must not be altered! 977 off_t validatedSize = size; 978 if (!pm_validate_resize_child(partition, child, &validatedSize)) 979 return B_BAD_VALUE; 980 if (child->size == validatedSize) 981 return B_OK; 982 983 // update data stuctures and write changes 984 update_disk_device_job_progress(job, 0.0); 985 primary->SetSize(validatedSize); 986 987 // TODO: The partition is not supposed to be locked here! 988 PartitionMapWriter writer(fd, primary->BlockSize()); 989 // TODO: disk size? 990 status_t error = writer.WriteMBR(map, false); 991 if (error != B_OK) { 992 // putting into previous state 993 primary->SetSize(child->size); 994 return error; 995 } 996 997 child->size = validatedSize; 998 999 // all changes applied 1000 update_disk_device_job_progress(job, 1.0); 1001 partition_modified(partitionID); 1002 return B_OK; 1003 } 1004 1005 1006 // pm_move 1007 status_t 1008 pm_move(int fd, partition_id partitionID, off_t offset, disk_job_id job) 1009 { 1010 TRACE(("intel: pm_move\n")); 1011 1012 if (fd < 0) 1013 return B_ERROR; 1014 1015 // TODO: Should be a no-op! 1016 1017 PartitionWriteLocker locker(partitionID); 1018 if (!locker.IsLocked()) 1019 return B_ERROR; 1020 1021 // get out partition 1022 partition_data* partition = get_partition(partitionID); 1023 if (!partition) 1024 return B_BAD_VALUE; 1025 1026 // validate the new start 1027 if (!pm_validate_move(partition, &offset)) 1028 return B_BAD_VALUE; 1029 1030 // nothing to do here 1031 return B_OK; 1032 } 1033 1034 1035 // allocate_buffer (auxiliary function) 1036 /*! 1037 tries to allocate buffer with the size: blockSize * tryAlloc 1038 if it's not possible, tries smaller buffer (until the size: blockSize * 1) 1039 returns pointer to the buffer (it's size is: blockSize * allocated) 1040 or returns NULL - B_NO_MEMORY 1041 */ 1042 static uint8* 1043 allocate_buffer(uint32 blockSize, int32 tryAlloc, int32* allocated) 1044 { 1045 uint8* buffer = NULL; 1046 for (int32 i = tryAlloc; i > 1; i /= 2) { 1047 buffer = new(nothrow) uint8[i * blockSize]; 1048 if (buffer) { 1049 *allocated = i; 1050 return buffer; 1051 } 1052 } 1053 *allocated = 0; 1054 return NULL; 1055 } 1056 1057 1058 // move_block (auxiliary function) 1059 static status_t 1060 move_block(int fd, off_t fromOffset, off_t toOffset, uint8* buffer, int32 size) 1061 { 1062 status_t error = B_OK; 1063 // read block to buffer 1064 if (read_pos(fd, fromOffset, buffer, size) != size) { 1065 error = errno; 1066 if (error == B_OK) 1067 error = B_IO_ERROR; 1068 TRACE(("intel: move_block(): reading failed: %lx\n", error)); 1069 return error; 1070 } 1071 1072 // write block from buffer 1073 if (write_pos(fd, toOffset, buffer, size) != size) { 1074 error = errno; 1075 if (error == B_OK) 1076 error = B_IO_ERROR; 1077 TRACE(("intel: move_block(): writing failed: %lx\n", error)); 1078 } 1079 1080 return error; 1081 } 1082 1083 1084 // move_partition (auxiliary function) 1085 static status_t 1086 move_partition(int fd, off_t fromOffset, off_t toOffset, off_t size, 1087 uint8* buffer, int32 buffer_size, disk_job_id job) 1088 { 1089 // TODO: This should be a service function of the DDM! 1090 // TODO: This seems to be broken if source and destination overlap. 1091 status_t error = B_OK; 1092 off_t cycleCount = size / buffer_size; 1093 int32 remainingSize = size - cycleCount * buffer_size; 1094 update_disk_device_job_progress(job, 0.0); 1095 for (off_t i = 0; i < cycleCount; i++) { 1096 error = move_block(fd, fromOffset, toOffset, buffer, buffer_size); 1097 if (error != B_OK) 1098 return error; 1099 fromOffset += buffer_size; 1100 toOffset += buffer_size; 1101 update_disk_device_job_progress(job, (float)i / cycleCount); 1102 } 1103 if (remainingSize) 1104 error = move_block(fd, fromOffset, toOffset, buffer, remainingSize); 1105 update_disk_device_job_progress(job, 1.0); 1106 return error; 1107 } 1108 1109 1110 // pm_move_child 1111 status_t 1112 pm_move_child(int fd, partition_id partitionID, partition_id childID, 1113 off_t offset, disk_job_id job) 1114 { 1115 TRACE(("intel: pm_move_child\n")); 1116 1117 if (fd < 0) 1118 return B_ERROR; 1119 1120 PartitionWriteLocker locker(partitionID); 1121 if (!locker.IsLocked()) 1122 return B_ERROR; 1123 1124 // get partition, child and partition map structure 1125 partition_data* partition = get_partition(partitionID); 1126 partition_data* child = get_partition(childID); 1127 if (!partition || !child) 1128 return B_BAD_VALUE; 1129 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1130 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 1131 if (!map || !primary) 1132 return B_BAD_VALUE; 1133 1134 // TODO: The parameter has already been checked and must not be altered! 1135 off_t validatedOffset = offset; 1136 if (!pm_validate_move_child(partition, child, &validatedOffset)) 1137 return B_BAD_VALUE; 1138 1139 // if the old offset is the same, there is nothing to do 1140 if (child->offset == validatedOffset) 1141 return B_OK; 1142 1143 // buffer allocation 1144 int32 allocated; 1145 uint8* buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER, 1146 &allocated); 1147 if (!buffer) 1148 return B_NO_MEMORY; 1149 1150 // partition moving 1151 // TODO: The partition is not supposed to be locked at this point! 1152 update_disk_device_job_progress(job, 0.0); 1153 status_t error = B_OK; 1154 error = move_partition(fd, child->offset, validatedOffset, child->size, 1155 buffer, allocated * partition->block_size, job); 1156 delete[] buffer; 1157 if (error != B_OK) 1158 return error; 1159 1160 // partition moved 1161 // updating data structure 1162 child->offset = validatedOffset; 1163 primary->SetOffset(validatedOffset); 1164 1165 PartitionMapWriter writer(fd, partition->block_size); 1166 // TODO: disk size? 1167 error = writer.WriteMBR(map, false); 1168 if (error != B_OK) 1169 // something went wrong - this is fatal (partition has been moved) 1170 // but MBR is not updated 1171 return error; 1172 1173 // all changes applied 1174 update_disk_device_job_progress(job, 1.0); 1175 partition_modified(childID); 1176 return B_OK; 1177 } 1178 1179 1180 // pm_set_type 1181 status_t 1182 pm_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job) 1183 { 1184 TRACE(("intel: pm_set_type\n")); 1185 1186 if (fd < 0 || !type) 1187 return B_BAD_VALUE; 1188 1189 PartitionWriteLocker locker(partitionID); 1190 if (!locker.IsLocked()) 1191 return B_ERROR; 1192 1193 // get parent partition, child and partition map structure 1194 partition_data* partition = get_parent_partition(partitionID); 1195 partition_data* child = get_partition(partitionID); 1196 if (!partition || !child) 1197 return B_BAD_VALUE; 1198 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1199 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 1200 if (!map || !primary) 1201 return B_BAD_VALUE; 1202 1203 // TODO: The parameter has already been checked and must not be altered! 1204 if (!pm_validate_set_type(child, type)) 1205 return B_BAD_VALUE; 1206 1207 // if the old type is the same, there is nothing to do 1208 if (child->type && !strcmp(type, child->type)) 1209 return B_OK; 1210 1211 PartitionType ptype; 1212 ptype.SetType(type); 1213 // this is impossible 1214 if (!ptype.IsValid() || ptype.IsEmpty()) 1215 return false; 1216 // TODO: Incompatible return value! 1217 1218 // setting type to the partition 1219 update_disk_device_job_progress(job, 0.0); 1220 uint8 oldType = primary->Type(); 1221 primary->SetType(ptype.Type()); 1222 1223 // TODO: The partition is not supposed to be locked at this point! 1224 PartitionMapWriter writer(fd, primary->BlockSize()); 1225 // TODO: disk size? 1226 status_t error = writer.WriteMBR(map, false); 1227 if (error != B_OK) { 1228 // something went wrong - putting into previous state 1229 primary->SetType(oldType); 1230 return error; 1231 } 1232 1233 free(child->type); 1234 child->type = strdup(type); 1235 if (!child->type) 1236 return B_NO_MEMORY; 1237 1238 // all changes applied 1239 update_disk_device_job_progress(job, 1.0); 1240 partition_modified(partitionID); 1241 return B_OK; 1242 } 1243 1244 1245 // pm_initialize 1246 status_t 1247 pm_initialize(int fd, partition_id partitionID, const char* name, 1248 const char* parameters, off_t partitionSize, disk_job_id job) 1249 { 1250 TRACE(("intel: pm_initialize\n")); 1251 1252 if (fd < 0) 1253 return B_ERROR; 1254 1255 PartitionWriteLocker locker(partitionID); 1256 if (!locker.IsLocked()) 1257 return B_ERROR; 1258 1259 // get partition and partition map structure 1260 partition_data* partition = get_partition(partitionID); 1261 if (!partition) 1262 return B_BAD_VALUE; 1263 update_disk_device_job_progress(job, 0.0); 1264 1265 // we will write an empty partition map 1266 PartitionMap map; 1267 1268 // write the sector to disk 1269 PartitionMapWriter writer(fd, partition->block_size); 1270 // TODO: disk size or 2 * SECTOR_SIZE? 1271 status_t error = writer.WriteMBR(&map, true); 1272 if (error != B_OK) 1273 return error; 1274 1275 // rescan partition 1276 error = scan_partition(partitionID); 1277 if (error != B_OK) 1278 return error; 1279 1280 // all changes applied 1281 update_disk_device_job_progress(job, 1.0); 1282 partition_modified(partitionID); 1283 1284 return B_OK; 1285 } 1286 1287 1288 status_t 1289 pm_uninitialize(int fd, partition_id partitionID, off_t partitionSize, 1290 uint32 blockSize, disk_job_id job) 1291 { 1292 if (blockSize == 0) 1293 return B_BAD_VALUE; 1294 1295 // We overwrite the first block, which contains the partition table. 1296 // Allocate a buffer, we can clear and write. 1297 void* block = malloc(blockSize); 1298 if (block == NULL) 1299 return B_NO_MEMORY; 1300 MemoryDeleter blockDeleter(block); 1301 1302 memset(block, 0, blockSize); 1303 1304 if (write_pos(fd, 0, block, blockSize) < 0) 1305 return errno; 1306 1307 update_disk_device_job_progress(job, 1.0); 1308 1309 return B_OK; 1310 } 1311 1312 1313 // pm_create_child 1314 /*! childID is used for the return value, but is also an optional input 1315 parameter -- -1 to be ignored 1316 */ 1317 status_t 1318 pm_create_child(int fd, partition_id partitionID, off_t offset, off_t size, 1319 const char* type, const char* name, const char* parameters, 1320 disk_job_id job, partition_id* childID) 1321 { 1322 TRACE(("intel: pm_create_child\n")); 1323 1324 if (fd < 0 || !childID) 1325 return B_BAD_VALUE; 1326 1327 PartitionWriteLocker locker(partitionID); 1328 if (!locker.IsLocked()) 1329 return B_ERROR; 1330 1331 // get partition and partition map structure 1332 partition_data* partition = get_partition(partitionID); 1333 if (!partition) 1334 return B_BAD_VALUE; 1335 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1336 if (!map) 1337 return B_BAD_VALUE; 1338 1339 // validate the offset, size and get index of the new partition 1340 // TODO: The parameters have already been checked and must not be altered! 1341 off_t validatedOffset = offset; 1342 off_t validatedSize = size; 1343 int32 index = 0; 1344 1345 if (!pm_validate_create_child(partition, &validatedOffset, &validatedSize, 1346 type, name, parameters, &index)) { 1347 return B_BAD_VALUE; 1348 } 1349 1350 // finding out free primary partition in the map (index from 1351 // pm_validate_create_child) 1352 PrimaryPartition* primary = map->PrimaryPartitionAt(index); 1353 if (!primary->IsEmpty()) 1354 return B_BAD_DATA; 1355 1356 // creating partition 1357 update_disk_device_job_progress(job, 0.0); 1358 partition_data* child = create_child_partition(partition->id, index, 1359 validatedOffset, validatedSize, *childID); 1360 if (!child) 1361 return B_ERROR; 1362 1363 PartitionType ptype; 1364 ptype.SetType(type); 1365 1366 // check parameters 1367 void* handle = parse_driver_settings_string(parameters); 1368 if (handle == NULL) 1369 return B_ERROR; 1370 1371 bool active = get_driver_boolean_parameter(handle, "active", false, true); 1372 delete_driver_settings(handle); 1373 1374 // set the active flags to false 1375 if (active) { 1376 for (int i = 0; i < 4; i++) { 1377 PrimaryPartition* partition = map->PrimaryPartitionAt(i); 1378 partition->SetActive(false); 1379 } 1380 } 1381 1382 primary->SetPartitionTableOffset(0); 1383 primary->SetOffset(validatedOffset); 1384 primary->SetSize(validatedSize); 1385 primary->SetType(ptype.Type()); 1386 primary->SetActive(active); 1387 1388 // write changes to disk 1389 PartitionMapWriter writer(fd, primary->BlockSize()); 1390 1391 // TODO: The partition is not supposed to be locked at this point! 1392 status_t error = writer.WriteMBR(map, false); 1393 if (error != B_OK) { 1394 // putting into previous state 1395 primary->Unset(); 1396 delete_partition(child->id); 1397 return error; 1398 } 1399 1400 *childID = child->id; 1401 1402 child->block_size = primary->BlockSize(); 1403 // (no name) 1404 child->type = strdup(type); 1405 // parameters 1406 child->parameters = strdup(parameters); 1407 child->cookie = primary; 1408 // check for allocation problems 1409 if (!child->type || !child->parameters) 1410 return B_NO_MEMORY; 1411 1412 // rescan partition if needed 1413 if (strcmp(type, INTEL_EXTENDED_PARTITION_NAME) == 0) { 1414 writer.ClearExtendedHead(primary); 1415 error = scan_partition(partitionID); 1416 if (error != B_OK) 1417 return error; 1418 } 1419 1420 // all changes applied 1421 update_disk_device_job_progress(job, 1.0); 1422 partition_modified(partitionID); 1423 return B_OK; 1424 } 1425 1426 1427 // pm_delete_child 1428 status_t 1429 pm_delete_child(int fd, partition_id partitionID, partition_id childID, 1430 disk_job_id job) 1431 { 1432 TRACE(("intel: pm_delete_child\n")); 1433 1434 if (fd < 0) 1435 return B_ERROR; 1436 1437 PartitionWriteLocker locker(partitionID); 1438 if (!locker.IsLocked()) 1439 return B_ERROR; 1440 1441 partition_data* partition = get_partition(partitionID); 1442 partition_data* child = get_partition(childID); 1443 if (!partition || !child) 1444 return B_BAD_VALUE; 1445 1446 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1447 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 1448 if (!map || !primary) 1449 return B_BAD_VALUE; 1450 1451 // deleting child 1452 update_disk_device_job_progress(job, 0.0); 1453 if (!delete_partition(childID)) 1454 return B_ERROR; 1455 primary->Unset(); 1456 1457 // write changes to disk 1458 PartitionMapWriter writer(fd, primary->BlockSize()); 1459 // TODO: disk size or 2 * SECTOR_SIZE? 1460 // TODO: The partition is not supposed to be locked at this point! 1461 status_t error = writer.WriteMBR(map, false); 1462 if (error != B_OK) 1463 return error; 1464 1465 // all changes applied 1466 update_disk_device_job_progress(job, 1.0); 1467 partition_modified(partitionID); 1468 return B_OK; 1469 } 1470 1471 1472 // #pragma mark - Intel Extended Partition - support functions 1473 1474 1475 // ep_get_supported_operations 1476 uint32 1477 ep_get_supported_operations(partition_data* partition, uint32 mask) 1478 { 1479 uint32 flags = B_DISK_SYSTEM_SUPPORTS_RESIZING 1480 | B_DISK_SYSTEM_SUPPORTS_MOVING 1481 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS; 1482 1483 // initializing 1484 if (partition_data* parent = get_parent_partition(partition->id)) { 1485 if (partition->type 1486 && strcmp(partition->type, kPartitionTypeIntelExtended) == 0 1487 && strcmp(parent->content_type, kPartitionTypeIntel) == 0) { 1488 flags |= B_DISK_SYSTEM_SUPPORTS_INITIALIZING; 1489 } 1490 } 1491 1492 // creating child 1493 int32 countSpaces = 0; 1494 if (ep_get_partitionable_spaces(partition, NULL, 0, &countSpaces) 1495 == B_BUFFER_OVERFLOW 1496 && countSpaces > 0) { 1497 flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD; 1498 } 1499 1500 return flags; 1501 } 1502 1503 1504 // ep_get_supported_child_operations 1505 uint32 1506 ep_get_supported_child_operations(partition_data* partition, 1507 partition_data* child, uint32 mask) 1508 { 1509 return B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 1510 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 1511 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 1512 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD; 1513 } 1514 1515 1516 // ep_is_sub_system_for 1517 bool 1518 ep_is_sub_system_for(partition_data* partition) 1519 { 1520 if (partition == NULL) 1521 return false; 1522 1523 TRACE(("intel: ep_is_sub_system_for(%ld: %lld, %lld, %ld, %s)\n", 1524 partition->id, partition->offset, partition->size, 1525 partition->block_size, partition->content_type)); 1526 1527 // Intel Extended Partition can live in child partition of Intel Partition 1528 // Map 1529 return partition->content_type 1530 && !strcmp(partition->content_type, kPartitionTypeIntel); 1531 } 1532 1533 1534 // #pragma mark - Intel Extended Partition - validate functions 1535 1536 1537 // ep_validate_resize 1538 bool 1539 ep_validate_resize(partition_data* partition, off_t* size) 1540 { 1541 TRACE(("intel: ep_validate_resize\n")); 1542 1543 if (!partition || !size) 1544 return false; 1545 1546 return validate_resize(partition, size); 1547 } 1548 1549 1550 // ep_validate_resize_child 1551 bool 1552 ep_validate_resize_child(partition_data* partition, partition_data* child, 1553 off_t* _size) 1554 { 1555 TRACE(("intel: ep_validate_resize_child\n")); 1556 1557 if (!partition || !child || !_size) 1558 return false; 1559 1560 // validate position 1561 off_t size = *_size; 1562 if (!validate_resize_child(partition, child, child->offset, 1563 child->size, &size, get_sibling_partitions_ep)) 1564 return false; 1565 *_size = size; 1566 return true; 1567 } 1568 1569 1570 // ep_validate_move 1571 bool 1572 ep_validate_move(partition_data* partition, off_t* start) 1573 { 1574 TRACE(("intel: ep_validate_move\n")); 1575 1576 if (!partition || !start) 1577 return false; 1578 // nothing to do here 1579 return true; 1580 } 1581 1582 1583 // ep_validate_move_child 1584 bool 1585 ep_validate_move_child(partition_data* partition, partition_data* child, 1586 off_t* _start) 1587 { 1588 TRACE(("intel: ep_validate_move_child\n")); 1589 1590 if (!partition || !child || !_start) 1591 return false; 1592 if (*_start == child->offset) 1593 return true; 1594 1595 // validate position 1596 off_t start = *_start; 1597 if (!validate_move_child(partition, child, child->offset, 1598 child->size, &start, get_sibling_partitions_ep)) 1599 return false; 1600 *_start = start; 1601 return true; 1602 } 1603 1604 1605 // is_type_valid_ep (auxiliary function) 1606 static inline bool 1607 is_type_valid_ep(const char* type) 1608 { 1609 // validity check of the type - it has to be known 1610 PartitionType ptype; 1611 ptype.SetType(type); 1612 return (ptype.IsValid() && !ptype.IsEmpty() && !ptype.IsExtended()); 1613 } 1614 1615 1616 // ep_validate_set_type 1617 bool 1618 ep_validate_set_type(partition_data* partition, const char* type) 1619 { 1620 TRACE(("intel: ep_validate_set_type\n")); 1621 1622 if (!partition || !type) 1623 return false; 1624 1625 // validity check of the type 1626 return is_type_valid_ep(type); 1627 } 1628 1629 1630 // ep_validate_initialize 1631 bool 1632 ep_validate_initialize(partition_data* partition, char* name, 1633 const char* parameters) 1634 { 1635 TRACE(("intel: ep_validate_initialize\n")); 1636 1637 if (!partition || !(ep_get_supported_operations(partition) 1638 & B_DISK_SYSTEM_SUPPORTS_INITIALIZING)) { 1639 return false; 1640 } 1641 // name is ignored - we cannot set it to the Intel Extended Partition 1642 // TODO: check parameters - don't know whether any parameters could be set 1643 // to the Intel Extended Partition 1644 return true; 1645 } 1646 1647 1648 // ep_validate_create_child 1649 bool 1650 ep_validate_create_child(partition_data* partition, off_t* offset, off_t* size, 1651 const char* type, const char* name, const char* parameters, int32* index) 1652 // index - returns position of the new partition (the last one) 1653 { 1654 return false; 1655 } 1656 1657 1658 // ep_get_partitionable_spaces 1659 status_t 1660 ep_get_partitionable_spaces(partition_data* partition, 1661 partitionable_space_data* buffer, int32 count, int32* actualCount) 1662 { 1663 TRACE(("intel: ep_get_partitionable_spaces\n")); 1664 1665 if (!partition || !partition->content_type 1666 || strcmp(partition->content_type, kPartitionTypeIntelExtended) 1667 || !actualCount) { 1668 return B_BAD_VALUE; 1669 } 1670 if (count > 0 && !buffer) 1671 return B_BAD_VALUE; 1672 1673 return get_partitionable_spaces(partition, buffer, count, actualCount, 1674 fill_partitionable_spaces_buffer_ep, 1675 partition->offset + PTS_OFFSET * partition->block_size, 1676 PTS_OFFSET * partition->block_size, 1677 PTS_OFFSET * partition->block_size); 1678 } 1679 1680 1681 // ep_get_next_supported_type 1682 status_t 1683 ep_get_next_supported_type(partition_data* partition, int32* cookie, 1684 char* _type) 1685 { 1686 TRACE(("intel: ep_get_next_supported_type\n")); 1687 1688 if (!partition || !partition->content_type 1689 || strcmp(partition->content_type, kPartitionTypeIntelExtended) 1690 || !cookie || !_type) { 1691 return B_BAD_VALUE; 1692 } 1693 1694 if (*cookie > 255) 1695 return B_ENTRY_NOT_FOUND; 1696 if (*cookie < 1) 1697 *cookie = 1; 1698 1699 uint8 type = *cookie; 1700 1701 // get type 1702 PartitionType ptype; 1703 ptype.SetType(type); 1704 while (ptype.IsValid() && !ptype.IsExtended()) 1705 ptype.FindNext(); 1706 1707 if (!ptype.IsValid()) 1708 return B_ENTRY_NOT_FOUND; 1709 1710 ptype.GetTypeString(_type); 1711 1712 // find next type 1713 if (ptype.FindNext()) 1714 *cookie = ptype.Type(); 1715 else 1716 *cookie = 256; 1717 1718 return B_OK; 1719 } 1720 1721 1722 // ep_shadow_changed 1723 status_t 1724 ep_shadow_changed(partition_data* partition, partition_data* child, 1725 uint32 operation) 1726 { 1727 TRACE(("intel: ep_shadow_changed\n")); 1728 1729 if (!partition) 1730 return B_BAD_VALUE; 1731 1732 // nothing to do here 1733 return B_OK; 1734 } 1735 1736 1737 bool 1738 check_partition_location_ep(partition_data* partition, off_t offset, 1739 off_t size, off_t ptsOffset) 1740 { 1741 if (!partition) 1742 return false; 1743 1744 // make sure we are sector aligned 1745 off_t alignedOffset = sector_align(offset, partition->block_size); 1746 if (alignedOffset != offset) 1747 return false; 1748 1749 // partition does not lie within extended partition 1750 if (offset < partition->offset 1751 || (offset > partition->offset + partition->size 1752 && offset + size <= partition->offset + partition->size)) 1753 return false; 1754 1755 // check if the new partition table is within an existing partition 1756 // or that the new partition does not overwrite an existing partition 1757 // table. 1758 for (int32 i = 0; i < partition->child_count; i++) { 1759 partition_data* sibling = get_child_partition(partition->id, i); 1760 LogicalPartition* logical = (LogicalPartition*)sibling->cookie; 1761 if (logical == NULL) 1762 return false; 1763 if (ptsOffset > logical->Offset() 1764 && ptsOffset < logical->Offset() + logical->Size()) 1765 return false; 1766 if ((logical->PartitionTableOffset() >= offset 1767 && logical->PartitionTableOffset() < offset + size) 1768 || logical->PartitionTableOffset() == ptsOffset) 1769 return false; 1770 } 1771 1772 return true; 1773 } 1774 1775 1776 // #pragma mark - Intel Extended Partition - write functions 1777 1778 1779 // ep_resize 1780 status_t 1781 ep_resize(int fd, partition_id partitionID, off_t size, disk_job_id job) 1782 { 1783 TRACE(("intel: ep_resize\n")); 1784 1785 if (fd < 0) 1786 return B_ERROR; 1787 1788 PartitionWriteLocker locker(partitionID); 1789 if (!locker.IsLocked()) 1790 return B_ERROR; 1791 1792 // get out partition 1793 partition_data* partition = get_partition(partitionID); 1794 if (!partition) 1795 return B_BAD_VALUE; 1796 1797 // validate the new size 1798 // TODO: The parameter has already been checked and must not be altered! 1799 off_t validatedSize = size; 1800 if (!ep_validate_resize(partition, &validatedSize)) 1801 return B_BAD_VALUE; 1802 1803 // update data stuctures 1804 update_disk_device_job_progress(job, 0.0); 1805 1806 // TODO: partition->size is not supposed to be touched. 1807 partition->size = validatedSize; 1808 partition->content_size = validatedSize; 1809 1810 // all changes applied 1811 update_disk_device_job_progress(job, 1.0); 1812 partition_modified(partitionID); 1813 return B_OK; 1814 } 1815 1816 1817 // ep_resize_child 1818 status_t 1819 ep_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job) 1820 { 1821 TRACE(("intel: ep_resize_child\n")); 1822 1823 if (fd < 0) 1824 return B_ERROR; 1825 1826 PartitionWriteLocker locker(partitionID); 1827 if (!locker.IsLocked()) 1828 return B_ERROR; 1829 1830 // get out partition, child and LogicalPartition structure 1831 partition_data* partition = get_parent_partition(partitionID); 1832 partition_data* child = get_partition(partitionID); 1833 if (!partition || !child) 1834 return B_BAD_VALUE; 1835 LogicalPartition* logical = (LogicalPartition*)child->cookie; 1836 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 1837 if (!logical || !primary) 1838 return B_BAD_VALUE; 1839 1840 // validate the new size 1841 // TODO: The parameter has already been checked and must not be altered! 1842 off_t validatedSize = size; 1843 if (!ep_validate_resize_child(partition, child, &validatedSize)) 1844 return B_BAD_VALUE; 1845 if (child->size == validatedSize) 1846 return B_OK; 1847 1848 // update data stuctures and write changes 1849 update_disk_device_job_progress(job, 0.0); 1850 logical->SetSize(validatedSize); 1851 1852 PartitionMapWriter writer(fd, partition->block_size); 1853 // TODO: The partition is not supposed to be locked here! 1854 status_t error = writer.WriteLogical(logical, primary, false); 1855 if (error != B_OK) { 1856 // putting into previous state 1857 logical->SetSize(child->size); 1858 return error; 1859 } 1860 LogicalPartition* prev = logical->Previous(); 1861 error = prev ? writer.WriteLogical(prev, primary, false) 1862 : writer.WriteLogical(logical, primary, false); 1863 if (error != B_OK) 1864 // this should be not so fatal 1865 return error; 1866 1867 child->size = validatedSize; 1868 1869 // all changes applied 1870 update_disk_device_job_progress(job, 1.0); 1871 partition_modified(partitionID); 1872 return B_OK; 1873 } 1874 1875 1876 // ep_move 1877 status_t 1878 ep_move(int fd, partition_id partitionID, off_t offset, disk_job_id job) 1879 { 1880 TRACE(("intel: ep_move\n")); 1881 1882 if (fd < 0) 1883 return B_ERROR; 1884 1885 PartitionWriteLocker locker(partitionID); 1886 if (!locker.IsLocked()) 1887 return B_ERROR; 1888 1889 // get out partition 1890 partition_data* partition = get_partition(partitionID); 1891 if (!partition) 1892 return B_BAD_VALUE; 1893 1894 // validate the new start 1895 // TODO: The parameter has already been checked and must not be altered! 1896 if (!ep_validate_move(partition, &offset)) 1897 return B_BAD_VALUE; 1898 1899 // nothing to do here 1900 return B_OK; 1901 } 1902 1903 1904 // ep_move_child 1905 status_t 1906 ep_move_child(int fd, partition_id partitionID, partition_id childID, 1907 off_t offset, disk_job_id job) 1908 { 1909 TRACE(("intel: ep_move_child\n")); 1910 1911 if (fd < 0) 1912 return B_ERROR; 1913 1914 PartitionWriteLocker locker(partitionID); 1915 if (!locker.IsLocked()) 1916 return B_ERROR; 1917 1918 // get partition, child and LogicalPartition structure 1919 partition_data* partition = get_partition(partitionID); 1920 partition_data* child = get_partition(childID); 1921 if (!partition || !child) 1922 return B_BAD_VALUE; 1923 LogicalPartition* logical = (LogicalPartition*)child->cookie; 1924 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 1925 if (!logical || !primary) 1926 return B_BAD_VALUE; 1927 1928 // TODO: The parameter has already been checked and must not be altered! 1929 off_t validatedOffset = offset; 1930 if (!ep_validate_move_child(partition, child, &validatedOffset)) 1931 return B_BAD_VALUE; 1932 1933 // if the old offset is the same, there is nothing to do 1934 if (child->offset == validatedOffset) 1935 return B_OK; 1936 1937 off_t diffOffset = validatedOffset - child->offset; 1938 1939 // buffer allocation 1940 int32 allocated; 1941 uint8* buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER, 1942 &allocated); 1943 if (!buffer) 1944 return B_NO_MEMORY; 1945 1946 // partition moving 1947 update_disk_device_job_progress(job, 0.0); 1948 status_t error = B_OK; 1949 // move partition with its header (partition table) 1950 off_t pts_offset = logical->Offset() - logical->PartitionTableOffset(); 1951 error = move_partition(fd, child->offset - pts_offset, 1952 validatedOffset - pts_offset, child->size + pts_offset, buffer, 1953 allocated * partition->block_size, job); 1954 delete[] buffer; 1955 if (error != B_OK) 1956 return error; 1957 1958 // partition moved 1959 // updating data structure 1960 child->offset = validatedOffset; 1961 logical->SetOffset(logical->Offset() + diffOffset); 1962 logical->SetPartitionTableOffset(logical->PartitionTableOffset() + diffOffset); 1963 1964 PartitionMapWriter writer(fd, partition->block_size); 1965 // TODO: If partition->offset is > prev->offset, then writing 1966 // the previous logical partition table will fail! 1967 // TODO: The partition is not supposed to be locked here! 1968 error = writer.WriteLogical(logical, primary, false); 1969 if (error != B_OK) 1970 // something went wrong - this is fatal (partition has been moved) 1971 // but EBR is not updated 1972 return error; 1973 LogicalPartition* prev = logical->Previous(); 1974 error = prev ? writer.WriteLogical(prev, primary, false) 1975 : writer.WriteLogical(logical, primary, false); 1976 if (error != B_OK) 1977 // this is fatal - linked list is not updated 1978 return error; 1979 1980 // all changes applied 1981 update_disk_device_job_progress(job, 1.0); 1982 partition_modified(childID); 1983 return B_OK; 1984 } 1985 1986 1987 // ep_set_type 1988 status_t 1989 ep_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job) 1990 { 1991 TRACE(("intel: ep_set_type\n")); 1992 1993 if (fd < 0 || !type) 1994 return B_BAD_VALUE; 1995 1996 PartitionWriteLocker locker(partitionID); 1997 if (!locker.IsLocked()) 1998 return B_ERROR; 1999 2000 // get partition, child and LogicalPartition structure 2001 partition_data* partition = get_parent_partition(partitionID); 2002 partition_data* child = get_partition(partitionID); 2003 if (!partition || !child) 2004 return B_BAD_VALUE; 2005 LogicalPartition* logical = (LogicalPartition*)child->cookie; 2006 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2007 if (!logical || !primary) 2008 return B_BAD_VALUE; 2009 2010 // TODO: The parameter has already been checked and must not be altered! 2011 if (!ep_validate_set_type(child, type)) 2012 return B_BAD_VALUE; 2013 2014 // if the old type is the same, there is nothing to do 2015 if (child->type && !strcmp(type, child->type)) 2016 return B_OK; 2017 2018 PartitionType ptype; 2019 ptype.SetType(type); 2020 // this is impossible 2021 if (!ptype.IsValid() || ptype.IsEmpty() || ptype.IsExtended()) 2022 return false; 2023 2024 // setting type to the partition 2025 update_disk_device_job_progress(job, 0.0); 2026 uint8 oldType = logical->Type(); 2027 logical->SetType(ptype.Type()); 2028 2029 PartitionMapWriter writer(fd, partition->block_size); 2030 // TODO: The partition is not supposed to be locked here! 2031 status_t error = writer.WriteLogical(logical, primary, false); 2032 if (error != B_OK) { 2033 // something went wrong - putting into previous state 2034 logical->SetType(oldType); 2035 return error; 2036 } 2037 2038 free(child->type); 2039 child->type = strdup(type); 2040 if (!child->type) 2041 return B_NO_MEMORY; 2042 2043 // all changes applied 2044 update_disk_device_job_progress(job, 1.0); 2045 partition_modified(partitionID); 2046 return B_OK; 2047 } 2048 2049 2050 // ep_initialize 2051 status_t 2052 ep_initialize(int fd, partition_id partitionID, const char* name, 2053 const char* parameters, off_t partitionSize, disk_job_id job) 2054 { 2055 TRACE(("intel: ep_initialize\n")); 2056 2057 if (fd < 0) 2058 return B_ERROR; 2059 2060 PartitionWriteLocker locker(partitionID); 2061 if (!locker.IsLocked()) 2062 return B_ERROR; 2063 2064 // get partition 2065 partition_data* partition = get_partition(partitionID); 2066 if (!partition) 2067 return B_BAD_VALUE; 2068 2069 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2070 if (!primary) 2071 return B_BAD_VALUE; 2072 2073 // name is ignored - we cannot set it to the Intel Extended Partition 2074 // TODO: The parameter has already been checked and must not be altered! 2075 if (!ep_validate_initialize(partition, NULL, parameters)) 2076 return B_BAD_VALUE; 2077 2078 // partition init (we have no child partition) 2079 update_disk_device_job_progress(job, 0.0); 2080 // fill in the partition_data structure 2081 partition->status = B_PARTITION_VALID; 2082 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 2083 partition->content_size = partition->size; 2084 // (no content_name and content_parameters) 2085 // (content_type is set by the system) 2086 partition->content_cookie = primary; 2087 2088 // we delete code area in EBR - nothing should be there 2089 partition_table table; 2090 table.clear_code_area(); 2091 2092 PartitionMapWriter writer(fd, partition->block_size); 2093 // TODO: The partition is not supposed to be locked here! 2094 status_t error = writer.ClearExtendedHead(primary); 2095 if (error != B_OK) 2096 return error; 2097 2098 // all changes applied 2099 update_disk_device_job_progress(job, 1.0); 2100 partition_modified(partitionID); 2101 return B_OK; 2102 } 2103 2104 2105 // ep_create_child 2106 /*! 2107 childID is used for the return value, but is also an optional input 2108 parameter -- -1 to be ignored 2109 */ 2110 status_t 2111 ep_create_child(int fd, partition_id partitionID, off_t offset, off_t size, 2112 const char* type, const char* name, const char* parameters, disk_job_id job, 2113 partition_id* childID) 2114 { 2115 TRACE(("intel: ep_create_child\n")); 2116 2117 if (fd < 0 || !childID) 2118 return B_BAD_VALUE; 2119 2120 // aquire lock 2121 PartitionWriteLocker locker(partitionID); 2122 if (!locker.IsLocked()) 2123 return B_ERROR; 2124 2125 // get partition data 2126 partition_data* partition = get_partition(partitionID); 2127 partition_data* parent = get_parent_partition(partitionID); 2128 if (partition == NULL || parent == NULL) 2129 return B_BAD_VALUE; 2130 2131 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2132 if (!primary) 2133 return B_BAD_VALUE; 2134 2135 // parse parameters 2136 void* handle = parse_driver_settings_string(parameters); 2137 if (handle == NULL) 2138 return B_ERROR; 2139 2140 bool active = get_driver_boolean_parameter(handle, "active", false, true); 2141 2142 off_t ptsOffset = 0; 2143 const char* buffer = get_driver_parameter( 2144 handle, "partition_table_offset", NULL, NULL); 2145 if (buffer != NULL) 2146 ptsOffset = strtoull(buffer, NULL, 10); 2147 else { 2148 delete_driver_settings(handle); 2149 return B_BAD_VALUE; 2150 } 2151 delete_driver_settings(handle); 2152 2153 // check the partition location 2154 if (!check_partition_location_ep(partition, offset, size, ptsOffset)) 2155 return B_BAD_VALUE; 2156 2157 // creating partition 2158 update_disk_device_job_progress(job, 0.0); 2159 partition_data* child = create_child_partition(partition->id, 2160 partition->child_count, offset, size, *childID); 2161 if (!child) 2162 return B_ERROR; 2163 2164 // setup logical partition 2165 LogicalPartition* logical = new(nothrow) LogicalPartition; 2166 if (!logical) 2167 return B_NO_MEMORY; 2168 2169 PartitionType ptype; 2170 ptype.SetType(type); 2171 logical->SetPartitionTableOffset(ptsOffset - parent->offset); 2172 logical->SetOffset(offset); 2173 logical->SetSize(size); 2174 logical->SetType(ptype.Type()); 2175 logical->SetActive(active); 2176 logical->SetPrimaryPartition(primary); 2177 logical->SetBlockSize(partition->block_size); 2178 primary->AddLogicalPartition(logical); 2179 2180 int parentFD = open_partition(parent->id, O_RDWR); 2181 if (parentFD < 0) { 2182 primary->RemoveLogicalPartition(logical); 2183 delete logical; 2184 return B_IO_ERROR; 2185 } 2186 2187 // write changes to disk 2188 PartitionMapWriter writer(parentFD, primary->BlockSize()); 2189 2190 // Write the logical partition's EBR first in case of failure. 2191 // This way we will not add a partition to the previous logical 2192 // partition. If there is no previous logical partition then write 2193 // the current partition's EBR to the first sector of the primary partition 2194 status_t error = writer.WriteLogical(logical, primary, true); 2195 if (error != B_OK) { 2196 primary->RemoveLogicalPartition(logical); 2197 delete logical; 2198 return error; 2199 } 2200 2201 LogicalPartition* previous = logical->Previous(); 2202 if (previous != NULL) { 2203 error = writer.WriteLogical(previous, primary, true); 2204 if (error != B_OK) { 2205 primary->RemoveLogicalPartition(logical); 2206 delete logical; 2207 return error; 2208 } 2209 } 2210 *childID = child->id; 2211 2212 child->block_size = logical->BlockSize(); 2213 child->type = strdup(type); 2214 child->parameters = strdup(parameters); 2215 child->cookie = logical; 2216 // check for allocation problems 2217 if (!child->type || !child->parameters) 2218 error = B_NO_MEMORY; 2219 2220 // all changes applied 2221 update_disk_device_job_progress(job, 1.0); 2222 partition_modified(partitionID); 2223 return B_OK; 2224 } 2225 2226 2227 // ep_delete_child 2228 status_t 2229 ep_delete_child(int fd, partition_id partitionID, partition_id childID, 2230 disk_job_id job) 2231 { 2232 TRACE(("intel: ep_delete_child\n")); 2233 2234 if (fd < 0) 2235 return B_ERROR; 2236 2237 PartitionWriteLocker locker(partitionID); 2238 if (!locker.IsLocked()) 2239 return B_ERROR; 2240 2241 partition_data* partition = get_partition(partitionID); 2242 partition_data* parent = get_parent_partition(partitionID); 2243 partition_data* child = get_partition(childID); 2244 if (partition == NULL || parent == NULL || child == NULL) 2245 return B_BAD_VALUE; 2246 2247 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2248 LogicalPartition* logical = (LogicalPartition*)child->cookie; 2249 if (primary == NULL || logical == NULL) 2250 return B_BAD_VALUE; 2251 2252 // deleting child 2253 update_disk_device_job_progress(job, 0.0); 2254 if (!delete_partition(childID)) 2255 return B_ERROR; 2256 2257 LogicalPartition* previous = logical->Previous(); 2258 LogicalPartition* next = logical->Next(); 2259 2260 primary->RemoveLogicalPartition(logical); 2261 delete logical; 2262 2263 int parentFD = open_partition(parent->id, O_RDWR); 2264 if (parentFD < 0) 2265 return B_IO_ERROR; 2266 2267 // write changes to disk 2268 PartitionMapWriter writer(parentFD, primary->BlockSize()); 2269 2270 status_t error; 2271 if (previous != NULL) { 2272 error = writer.WriteLogical(previous, primary, true); 2273 } else { 2274 error = writer.WriteExtendedHead(next, primary, true); 2275 2276 if (next != NULL) { 2277 next->SetPartitionTableOffset(primary->Offset()); 2278 2279 partition_data* nextSibling = NULL; 2280 if (get_partition_from_offset_ep(partition, next->Offset(), 2281 &nextSibling)) { 2282 char buffer[128]; 2283 sprintf(buffer, "active %s ;\npartition_table_offset %lld ;\n", 2284 next->Active() ? "true" : "false", 2285 next->PartitionTableOffset()); 2286 nextSibling->parameters = strdup(buffer); 2287 } 2288 } 2289 } 2290 2291 close(parentFD); 2292 2293 if (error != B_OK) 2294 return error; 2295 2296 // all changes applied 2297 update_disk_device_job_progress(job, 1.0); 2298 partition_modified(partitionID); 2299 return B_OK; 2300 } 2301 2302