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: %" B_PRId32 "\n", 683 actualCount)); 684 685 *_actualCount = actualCount; 686 687 if (count < actualCount) 688 return B_BUFFER_OVERFLOW; 689 return B_OK; 690 } 691 692 693 // pm_get_partitionable_spaces 694 status_t 695 pm_get_partitionable_spaces(partition_data* partition, 696 partitionable_space_data* buffer, int32 count, int32* actualCount) 697 { 698 TRACE(("intel: pm_get_partitionable_spaces\n")); 699 700 if (!partition || !partition->content_type 701 || strcmp(partition->content_type, kPartitionTypeIntel) 702 || !actualCount) { 703 return B_BAD_VALUE; 704 } 705 if (count > 0 && !buffer) 706 return B_BAD_VALUE; 707 708 return get_partitionable_spaces(partition, buffer, count, actualCount, 709 fill_partitionable_spaces_buffer_pm, MBR_OFFSET * partition->block_size, 710 0, 0); 711 } 712 713 714 // pm_get_next_supported_type 715 status_t 716 pm_get_next_supported_type(partition_data* partition, int32* cookie, 717 char* _type) 718 { 719 TRACE(("intel: pm_get_next_supported_type\n")); 720 721 if (!partition || !partition->content_type 722 || strcmp(partition->content_type, kPartitionTypeIntel) 723 || !cookie || !_type) { 724 return B_BAD_VALUE; 725 } 726 727 if (*cookie > 255) 728 return B_ENTRY_NOT_FOUND; 729 if (*cookie < 1) 730 *cookie = 1; 731 732 uint8 type = *cookie; 733 734 // get type 735 PartitionType ptype; 736 ptype.SetType(type); 737 if (!ptype.IsValid()) 738 return B_ENTRY_NOT_FOUND; 739 740 ptype.GetTypeString(_type); 741 742 // find next type 743 if (ptype.FindNext()) 744 *cookie = ptype.Type(); 745 else 746 *cookie = 256; 747 748 return B_OK; 749 } 750 751 // pm_shadow_changed 752 status_t 753 pm_shadow_changed(partition_data* partition, partition_data* child, 754 uint32 operation) 755 { 756 TRACE(("intel: pm_shadow_changed(%p, %p, %" B_PRIu32 ")\n", partition, 757 child, operation)); 758 759 switch (operation) { 760 case B_PARTITION_SHADOW: 761 { 762 // get the physical partition 763 partition_data* physicalPartition = get_partition( 764 partition->id); 765 if (!physicalPartition) { 766 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW): no " 767 "physical partition with ID %" B_PRId32 "\n", 768 partition->id); 769 return B_ERROR; 770 } 771 772 // clone the map 773 if (!physicalPartition->content_cookie) { 774 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW): no " 775 "content cookie, physical partition: %" B_PRId32 "\n", 776 partition->id); 777 return B_ERROR; 778 } 779 780 PartitionMapCookie* map = new(nothrow) PartitionMapCookie; 781 if (!map) 782 return B_NO_MEMORY; 783 784 status_t error = map->Assign( 785 *(PartitionMapCookie*)physicalPartition->content_cookie); 786 if (error != B_OK) { 787 delete map; 788 return error; 789 } 790 791 partition->content_cookie = map; 792 793 return B_OK; 794 } 795 796 case B_PARTITION_SHADOW_CHILD: 797 { 798 // get the physical child partition 799 partition_data* physical = get_partition(child->id); 800 if (!physical) { 801 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): " 802 "no physical partition with ID %" B_PRId32 "\n", child->id); 803 return B_ERROR; 804 } 805 806 if (!physical->cookie) { 807 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): " 808 "no cookie, physical partition: %" B_PRId32 "\n", 809 child->id); 810 return B_ERROR; 811 } 812 813 // primary partition index 814 int32 index = ((PrimaryPartition*)physical->cookie)->Index(); 815 816 if (!partition->content_cookie) { 817 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): " 818 "no content cookie, physical partition: %" B_PRId32 "\n", 819 partition->id); 820 return B_ERROR; 821 } 822 823 // get the primary partition 824 PartitionMapCookie* map 825 = ((PartitionMapCookie*)partition->content_cookie); 826 PrimaryPartition* primary = map->PrimaryPartitionAt(index); 827 828 if (!primary || primary->IsEmpty()) { 829 dprintf("intel: pm_shadow_changed(B_PARTITION_SHADOW_CHILD): " 830 "partition %" B_PRId32 " is empty, primary index: " 831 "%" B_PRId32 "\n", child->id, index); 832 return B_BAD_VALUE; 833 } 834 835 child->cookie = primary; 836 837 return B_OK; 838 } 839 840 case B_PARTITION_INITIALIZE: 841 { 842 // create an empty partition map 843 PartitionMapCookie* map = new(nothrow) PartitionMapCookie; 844 if (!map) 845 return B_NO_MEMORY; 846 847 partition->content_cookie = map; 848 849 return B_OK; 850 } 851 852 case B_PARTITION_CREATE_CHILD: 853 { 854 if (!partition->content_cookie) { 855 dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): " 856 "no content cookie, partition: %" B_PRId32 "\n", 857 partition->id); 858 return B_ERROR; 859 } 860 861 PartitionMapCookie* map 862 = ((PartitionMapCookie*)partition->content_cookie); 863 864 // find an empty primary partition slot 865 PrimaryPartition* primary = NULL; 866 for (int32 i = 0; i < 4; i++) { 867 if (map->PrimaryPartitionAt(i)->IsEmpty()) { 868 primary = map->PrimaryPartitionAt(i); 869 break; 870 } 871 } 872 873 if (!primary) { 874 dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): " 875 "no empty primary slot, partition: %" B_PRId32 "\n", 876 partition->id); 877 return B_ERROR; 878 } 879 880 // apply type 881 PartitionType type; 882 type.SetType(child->type); 883 if (!type.IsValid()) { 884 dprintf("intel: pm_shadow_changed(B_PARTITION_CREATE_CHILD): " 885 "invalid partition type, partition: %" B_PRId32 "\n", 886 partition->id); 887 return B_ERROR; 888 } 889 890 primary->SetType(type.Type()); 891 892 // TODO: Apply parameters! 893 894 child->cookie = primary; 895 896 return B_OK; 897 } 898 899 case B_PARTITION_DEFRAGMENT: 900 case B_PARTITION_REPAIR: 901 case B_PARTITION_RESIZE: 902 case B_PARTITION_RESIZE_CHILD: 903 case B_PARTITION_MOVE: 904 case B_PARTITION_MOVE_CHILD: 905 case B_PARTITION_SET_NAME: 906 case B_PARTITION_SET_CONTENT_NAME: 907 case B_PARTITION_SET_TYPE: 908 case B_PARTITION_SET_PARAMETERS: 909 case B_PARTITION_SET_CONTENT_PARAMETERS: 910 case B_PARTITION_DELETE_CHILD: 911 break; 912 } 913 914 return B_ERROR; 915 } 916 917 918 // #pragma mark - Intel Partition Map - writing functions 919 920 921 // pm_resize 922 status_t 923 pm_resize(int fd, partition_id partitionID, off_t size, disk_job_id job) 924 { 925 TRACE(("intel: pm_resize\n")); 926 927 if (fd < 0) 928 return B_ERROR; 929 930 PartitionWriteLocker locker(partitionID); 931 if (!locker.IsLocked()) 932 return B_ERROR; 933 934 // get out partition 935 partition_data* partition = get_partition(partitionID); 936 if (!partition) 937 return B_BAD_VALUE; 938 939 // validate the new size 940 // TODO: The parameter has already been checked and must not be altered! 941 off_t validatedSize = size; 942 if (!pm_validate_resize(partition, &validatedSize)) 943 return B_BAD_VALUE; 944 945 // update data stuctures 946 update_disk_device_job_progress(job, 0.0); 947 948 // TODO: partition->size is not supposed to be touched. 949 partition->size = validatedSize; 950 partition->content_size = validatedSize; 951 952 // all changes applied 953 update_disk_device_job_progress(job, 1.0); 954 partition_modified(partitionID); 955 return B_OK; 956 } 957 958 959 // pm_resize_child 960 status_t 961 pm_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job) 962 { 963 TRACE(("intel: pm_resize_child\n")); 964 965 if (fd < 0) 966 return B_ERROR; 967 968 PartitionWriteLocker locker(partitionID); 969 if (!locker.IsLocked()) 970 return B_ERROR; 971 972 // get out partition, child and partition map structure 973 partition_data* partition = get_parent_partition(partitionID); 974 partition_data* child = get_partition(partitionID); 975 if (!partition || !child) 976 return B_BAD_VALUE; 977 PartitionMap* map = (PartitionMap*)partition->content_cookie; 978 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 979 if (!map || !primary) 980 return B_BAD_VALUE; 981 982 // validate the new size 983 // TODO: The parameter has already been checked and must not be altered! 984 off_t validatedSize = size; 985 if (!pm_validate_resize_child(partition, child, &validatedSize)) 986 return B_BAD_VALUE; 987 if (child->size == validatedSize) 988 return B_OK; 989 990 // update data stuctures and write changes 991 update_disk_device_job_progress(job, 0.0); 992 primary->SetSize(validatedSize); 993 994 // TODO: The partition is not supposed to be locked here! 995 PartitionMapWriter writer(fd, primary->BlockSize()); 996 // TODO: disk size? 997 status_t error = writer.WriteMBR(map, false); 998 if (error != B_OK) { 999 // putting into previous state 1000 primary->SetSize(child->size); 1001 return error; 1002 } 1003 1004 child->size = validatedSize; 1005 1006 // all changes applied 1007 update_disk_device_job_progress(job, 1.0); 1008 partition_modified(partitionID); 1009 return B_OK; 1010 } 1011 1012 1013 // pm_move 1014 status_t 1015 pm_move(int fd, partition_id partitionID, off_t offset, disk_job_id job) 1016 { 1017 TRACE(("intel: pm_move\n")); 1018 1019 if (fd < 0) 1020 return B_ERROR; 1021 1022 // TODO: Should be a no-op! 1023 1024 PartitionWriteLocker locker(partitionID); 1025 if (!locker.IsLocked()) 1026 return B_ERROR; 1027 1028 // get out partition 1029 partition_data* partition = get_partition(partitionID); 1030 if (!partition) 1031 return B_BAD_VALUE; 1032 1033 // validate the new start 1034 if (!pm_validate_move(partition, &offset)) 1035 return B_BAD_VALUE; 1036 1037 // nothing to do here 1038 return B_OK; 1039 } 1040 1041 1042 // allocate_buffer (auxiliary function) 1043 /*! 1044 tries to allocate buffer with the size: blockSize * tryAlloc 1045 if it's not possible, tries smaller buffer (until the size: blockSize * 1) 1046 returns pointer to the buffer (it's size is: blockSize * allocated) 1047 or returns NULL - B_NO_MEMORY 1048 */ 1049 static uint8* 1050 allocate_buffer(uint32 blockSize, int32 tryAlloc, int32* allocated) 1051 { 1052 uint8* buffer = NULL; 1053 for (int32 i = tryAlloc; i > 1; i /= 2) { 1054 buffer = new(nothrow) uint8[i * blockSize]; 1055 if (buffer) { 1056 *allocated = i; 1057 return buffer; 1058 } 1059 } 1060 *allocated = 0; 1061 return NULL; 1062 } 1063 1064 1065 // move_block (auxiliary function) 1066 static status_t 1067 move_block(int fd, off_t fromOffset, off_t toOffset, uint8* buffer, int32 size) 1068 { 1069 status_t error = B_OK; 1070 // read block to buffer 1071 if (read_pos(fd, fromOffset, buffer, size) != size) { 1072 error = errno; 1073 if (error == B_OK) 1074 error = B_IO_ERROR; 1075 TRACE(("intel: move_block(): reading failed: %" B_PRIx32 "\n", error)); 1076 return error; 1077 } 1078 1079 // write block from buffer 1080 if (write_pos(fd, toOffset, buffer, size) != size) { 1081 error = errno; 1082 if (error == B_OK) 1083 error = B_IO_ERROR; 1084 TRACE(("intel: move_block(): writing failed: %" B_PRIx32 "\n", error)); 1085 } 1086 1087 return error; 1088 } 1089 1090 1091 // move_partition (auxiliary function) 1092 static status_t 1093 move_partition(int fd, off_t fromOffset, off_t toOffset, off_t size, 1094 uint8* buffer, int32 buffer_size, disk_job_id job) 1095 { 1096 // TODO: This should be a service function of the DDM! 1097 // TODO: This seems to be broken if source and destination overlap. 1098 status_t error = B_OK; 1099 off_t cycleCount = size / buffer_size; 1100 int32 remainingSize = size - cycleCount * buffer_size; 1101 update_disk_device_job_progress(job, 0.0); 1102 for (off_t i = 0; i < cycleCount; i++) { 1103 error = move_block(fd, fromOffset, toOffset, buffer, buffer_size); 1104 if (error != B_OK) 1105 return error; 1106 fromOffset += buffer_size; 1107 toOffset += buffer_size; 1108 update_disk_device_job_progress(job, (float)i / cycleCount); 1109 } 1110 if (remainingSize) 1111 error = move_block(fd, fromOffset, toOffset, buffer, remainingSize); 1112 update_disk_device_job_progress(job, 1.0); 1113 return error; 1114 } 1115 1116 1117 // pm_move_child 1118 status_t 1119 pm_move_child(int fd, partition_id partitionID, partition_id childID, 1120 off_t offset, disk_job_id job) 1121 { 1122 TRACE(("intel: pm_move_child\n")); 1123 1124 if (fd < 0) 1125 return B_ERROR; 1126 1127 PartitionWriteLocker locker(partitionID); 1128 if (!locker.IsLocked()) 1129 return B_ERROR; 1130 1131 // get partition, child and partition map structure 1132 partition_data* partition = get_partition(partitionID); 1133 partition_data* child = get_partition(childID); 1134 if (!partition || !child) 1135 return B_BAD_VALUE; 1136 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1137 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 1138 if (!map || !primary) 1139 return B_BAD_VALUE; 1140 1141 // TODO: The parameter has already been checked and must not be altered! 1142 off_t validatedOffset = offset; 1143 if (!pm_validate_move_child(partition, child, &validatedOffset)) 1144 return B_BAD_VALUE; 1145 1146 // if the old offset is the same, there is nothing to do 1147 if (child->offset == validatedOffset) 1148 return B_OK; 1149 1150 // buffer allocation 1151 int32 allocated; 1152 uint8* buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER, 1153 &allocated); 1154 if (!buffer) 1155 return B_NO_MEMORY; 1156 1157 // partition moving 1158 // TODO: The partition is not supposed to be locked at this point! 1159 update_disk_device_job_progress(job, 0.0); 1160 status_t error = B_OK; 1161 error = move_partition(fd, child->offset, validatedOffset, child->size, 1162 buffer, allocated * partition->block_size, job); 1163 delete[] buffer; 1164 if (error != B_OK) 1165 return error; 1166 1167 // partition moved 1168 // updating data structure 1169 child->offset = validatedOffset; 1170 primary->SetOffset(validatedOffset); 1171 1172 PartitionMapWriter writer(fd, partition->block_size); 1173 // TODO: disk size? 1174 error = writer.WriteMBR(map, false); 1175 if (error != B_OK) 1176 // something went wrong - this is fatal (partition has been moved) 1177 // but MBR is not updated 1178 return error; 1179 1180 // all changes applied 1181 update_disk_device_job_progress(job, 1.0); 1182 partition_modified(childID); 1183 return B_OK; 1184 } 1185 1186 1187 // pm_set_type 1188 status_t 1189 pm_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job) 1190 { 1191 TRACE(("intel: pm_set_type\n")); 1192 1193 if (fd < 0 || !type) 1194 return B_BAD_VALUE; 1195 1196 PartitionWriteLocker locker(partitionID); 1197 if (!locker.IsLocked()) 1198 return B_ERROR; 1199 1200 // get parent partition, child and partition map structure 1201 partition_data* partition = get_parent_partition(partitionID); 1202 partition_data* child = get_partition(partitionID); 1203 if (!partition || !child) 1204 return B_BAD_VALUE; 1205 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1206 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 1207 if (!map || !primary) 1208 return B_BAD_VALUE; 1209 1210 // TODO: The parameter has already been checked and must not be altered! 1211 if (!pm_validate_set_type(child, type)) 1212 return B_BAD_VALUE; 1213 1214 // if the old type is the same, there is nothing to do 1215 if (child->type && !strcmp(type, child->type)) 1216 return B_OK; 1217 1218 PartitionType ptype; 1219 ptype.SetType(type); 1220 // this is impossible 1221 if (!ptype.IsValid() || ptype.IsEmpty()) 1222 return false; 1223 // TODO: Incompatible return value! 1224 1225 // setting type to the partition 1226 update_disk_device_job_progress(job, 0.0); 1227 uint8 oldType = primary->Type(); 1228 primary->SetType(ptype.Type()); 1229 1230 // TODO: The partition is not supposed to be locked at this point! 1231 PartitionMapWriter writer(fd, primary->BlockSize()); 1232 // TODO: disk size? 1233 status_t error = writer.WriteMBR(map, false); 1234 if (error != B_OK) { 1235 // something went wrong - putting into previous state 1236 primary->SetType(oldType); 1237 return error; 1238 } 1239 1240 free(child->type); 1241 child->type = strdup(type); 1242 if (!child->type) 1243 return B_NO_MEMORY; 1244 1245 // all changes applied 1246 update_disk_device_job_progress(job, 1.0); 1247 partition_modified(partitionID); 1248 return B_OK; 1249 } 1250 1251 1252 // pm_initialize 1253 status_t 1254 pm_initialize(int fd, partition_id partitionID, const char* name, 1255 const char* parameters, off_t partitionSize, disk_job_id job) 1256 { 1257 TRACE(("intel: pm_initialize\n")); 1258 1259 if (fd < 0) 1260 return B_ERROR; 1261 1262 PartitionWriteLocker locker(partitionID); 1263 if (!locker.IsLocked()) 1264 return B_ERROR; 1265 1266 // get partition and partition map structure 1267 partition_data* partition = get_partition(partitionID); 1268 if (!partition) 1269 return B_BAD_VALUE; 1270 update_disk_device_job_progress(job, 0.0); 1271 1272 // we will write an empty partition map 1273 PartitionMap map; 1274 1275 // write the sector to disk 1276 PartitionMapWriter writer(fd, partition->block_size); 1277 // TODO: disk size or 2 * SECTOR_SIZE? 1278 status_t error = writer.WriteMBR(&map, true); 1279 if (error != B_OK) 1280 return error; 1281 1282 // rescan partition 1283 error = scan_partition(partitionID); 1284 if (error != B_OK) 1285 return error; 1286 1287 // all changes applied 1288 update_disk_device_job_progress(job, 1.0); 1289 partition_modified(partitionID); 1290 1291 return B_OK; 1292 } 1293 1294 1295 status_t 1296 pm_uninitialize(int fd, partition_id partitionID, off_t partitionSize, 1297 uint32 blockSize, disk_job_id job) 1298 { 1299 if (blockSize == 0) 1300 return B_BAD_VALUE; 1301 1302 // We overwrite the first block, which contains the partition table. 1303 // Allocate a buffer, we can clear and write. 1304 void* block = malloc(blockSize); 1305 if (block == NULL) 1306 return B_NO_MEMORY; 1307 MemoryDeleter blockDeleter(block); 1308 1309 memset(block, 0, blockSize); 1310 1311 if (write_pos(fd, 0, block, blockSize) < 0) 1312 return errno; 1313 1314 update_disk_device_job_progress(job, 1.0); 1315 1316 return B_OK; 1317 } 1318 1319 1320 // pm_create_child 1321 /*! childID is used for the return value, but is also an optional input 1322 parameter -- -1 to be ignored 1323 */ 1324 status_t 1325 pm_create_child(int fd, partition_id partitionID, off_t offset, off_t size, 1326 const char* type, const char* name, const char* parameters, 1327 disk_job_id job, partition_id* childID) 1328 { 1329 TRACE(("intel: pm_create_child\n")); 1330 1331 if (fd < 0 || !childID) 1332 return B_BAD_VALUE; 1333 1334 PartitionWriteLocker locker(partitionID); 1335 if (!locker.IsLocked()) 1336 return B_ERROR; 1337 1338 // get partition and partition map structure 1339 partition_data* partition = get_partition(partitionID); 1340 if (!partition) 1341 return B_BAD_VALUE; 1342 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1343 if (!map) 1344 return B_BAD_VALUE; 1345 1346 // validate the offset, size and get index of the new partition 1347 // TODO: The parameters have already been checked and must not be altered! 1348 off_t validatedOffset = offset; 1349 off_t validatedSize = size; 1350 int32 index = 0; 1351 1352 if (!pm_validate_create_child(partition, &validatedOffset, &validatedSize, 1353 type, name, parameters, &index)) { 1354 return B_BAD_VALUE; 1355 } 1356 1357 // finding out free primary partition in the map (index from 1358 // pm_validate_create_child) 1359 PrimaryPartition* primary = map->PrimaryPartitionAt(index); 1360 if (!primary->IsEmpty()) 1361 return B_BAD_DATA; 1362 1363 // creating partition 1364 update_disk_device_job_progress(job, 0.0); 1365 partition_data* child = create_child_partition(partition->id, index, 1366 validatedOffset, validatedSize, *childID); 1367 if (!child) 1368 return B_ERROR; 1369 1370 PartitionType ptype; 1371 ptype.SetType(type); 1372 1373 // check parameters 1374 void* handle = parse_driver_settings_string(parameters); 1375 if (handle == NULL) 1376 return B_ERROR; 1377 1378 bool active = get_driver_boolean_parameter(handle, "active", false, true); 1379 delete_driver_settings(handle); 1380 1381 // set the active flags to false 1382 if (active) { 1383 for (int i = 0; i < 4; i++) { 1384 PrimaryPartition* partition = map->PrimaryPartitionAt(i); 1385 partition->SetActive(false); 1386 } 1387 } 1388 1389 primary->SetPartitionTableOffset(0); 1390 primary->SetOffset(validatedOffset); 1391 primary->SetSize(validatedSize); 1392 primary->SetType(ptype.Type()); 1393 primary->SetActive(active); 1394 1395 // write changes to disk 1396 PartitionMapWriter writer(fd, primary->BlockSize()); 1397 1398 // TODO: The partition is not supposed to be locked at this point! 1399 status_t error = writer.WriteMBR(map, false); 1400 if (error != B_OK) { 1401 // putting into previous state 1402 primary->Unset(); 1403 delete_partition(child->id); 1404 return error; 1405 } 1406 1407 *childID = child->id; 1408 1409 child->block_size = primary->BlockSize(); 1410 // (no name) 1411 child->type = strdup(type); 1412 // parameters 1413 child->parameters = strdup(parameters); 1414 child->cookie = primary; 1415 // check for allocation problems 1416 if (!child->type || !child->parameters) 1417 return B_NO_MEMORY; 1418 1419 // rescan partition if needed 1420 if (strcmp(type, INTEL_EXTENDED_PARTITION_NAME) == 0) { 1421 writer.ClearExtendedHead(primary); 1422 error = scan_partition(partitionID); 1423 if (error != B_OK) 1424 return error; 1425 } 1426 1427 // all changes applied 1428 update_disk_device_job_progress(job, 1.0); 1429 partition_modified(partitionID); 1430 return B_OK; 1431 } 1432 1433 1434 // pm_delete_child 1435 status_t 1436 pm_delete_child(int fd, partition_id partitionID, partition_id childID, 1437 disk_job_id job) 1438 { 1439 TRACE(("intel: pm_delete_child\n")); 1440 1441 if (fd < 0) 1442 return B_ERROR; 1443 1444 PartitionWriteLocker locker(partitionID); 1445 if (!locker.IsLocked()) 1446 return B_ERROR; 1447 1448 partition_data* partition = get_partition(partitionID); 1449 partition_data* child = get_partition(childID); 1450 if (!partition || !child) 1451 return B_BAD_VALUE; 1452 1453 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1454 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 1455 if (!map || !primary) 1456 return B_BAD_VALUE; 1457 1458 // deleting child 1459 update_disk_device_job_progress(job, 0.0); 1460 if (!delete_partition(childID)) 1461 return B_ERROR; 1462 primary->Unset(); 1463 1464 // write changes to disk 1465 PartitionMapWriter writer(fd, primary->BlockSize()); 1466 // TODO: disk size or 2 * SECTOR_SIZE? 1467 // TODO: The partition is not supposed to be locked at this point! 1468 status_t error = writer.WriteMBR(map, false); 1469 if (error != B_OK) 1470 return error; 1471 1472 // all changes applied 1473 update_disk_device_job_progress(job, 1.0); 1474 partition_modified(partitionID); 1475 return B_OK; 1476 } 1477 1478 1479 // #pragma mark - Intel Extended Partition - support functions 1480 1481 1482 // ep_get_supported_operations 1483 uint32 1484 ep_get_supported_operations(partition_data* partition, uint32 mask) 1485 { 1486 uint32 flags = B_DISK_SYSTEM_SUPPORTS_RESIZING 1487 | B_DISK_SYSTEM_SUPPORTS_MOVING 1488 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS; 1489 1490 // initializing 1491 if (partition_data* parent = get_parent_partition(partition->id)) { 1492 if (partition->type 1493 && strcmp(partition->type, kPartitionTypeIntelExtended) == 0 1494 && strcmp(parent->content_type, kPartitionTypeIntel) == 0) { 1495 flags |= B_DISK_SYSTEM_SUPPORTS_INITIALIZING; 1496 } 1497 } 1498 1499 // creating child 1500 int32 countSpaces = 0; 1501 if (ep_get_partitionable_spaces(partition, NULL, 0, &countSpaces) 1502 == B_BUFFER_OVERFLOW 1503 && countSpaces > 0) { 1504 flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD; 1505 } 1506 1507 return flags; 1508 } 1509 1510 1511 // ep_get_supported_child_operations 1512 uint32 1513 ep_get_supported_child_operations(partition_data* partition, 1514 partition_data* child, uint32 mask) 1515 { 1516 return B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 1517 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 1518 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 1519 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD; 1520 } 1521 1522 1523 // ep_is_sub_system_for 1524 bool 1525 ep_is_sub_system_for(partition_data* partition) 1526 { 1527 if (partition == NULL) 1528 return false; 1529 1530 TRACE(("intel: ep_is_sub_system_for(%" B_PRId32 ": %" B_PRId64 ", " 1531 "%" B_PRId64 ", %" B_PRId32 ", %s)\n", partition->id, partition->offset, 1532 partition->size, partition->block_size, partition->content_type)); 1533 1534 // Intel Extended Partition can live in child partition of Intel Partition 1535 // Map 1536 return partition->content_type 1537 && !strcmp(partition->content_type, kPartitionTypeIntel); 1538 } 1539 1540 1541 // #pragma mark - Intel Extended Partition - validate functions 1542 1543 1544 // ep_validate_resize 1545 bool 1546 ep_validate_resize(partition_data* partition, off_t* size) 1547 { 1548 TRACE(("intel: ep_validate_resize\n")); 1549 1550 if (!partition || !size) 1551 return false; 1552 1553 return validate_resize(partition, size); 1554 } 1555 1556 1557 // ep_validate_resize_child 1558 bool 1559 ep_validate_resize_child(partition_data* partition, partition_data* child, 1560 off_t* _size) 1561 { 1562 TRACE(("intel: ep_validate_resize_child\n")); 1563 1564 if (!partition || !child || !_size) 1565 return false; 1566 1567 // validate position 1568 off_t size = *_size; 1569 if (!validate_resize_child(partition, child, child->offset, 1570 child->size, &size, get_sibling_partitions_ep)) 1571 return false; 1572 *_size = size; 1573 return true; 1574 } 1575 1576 1577 // ep_validate_move 1578 bool 1579 ep_validate_move(partition_data* partition, off_t* start) 1580 { 1581 TRACE(("intel: ep_validate_move\n")); 1582 1583 if (!partition || !start) 1584 return false; 1585 // nothing to do here 1586 return true; 1587 } 1588 1589 1590 // ep_validate_move_child 1591 bool 1592 ep_validate_move_child(partition_data* partition, partition_data* child, 1593 off_t* _start) 1594 { 1595 TRACE(("intel: ep_validate_move_child\n")); 1596 1597 if (!partition || !child || !_start) 1598 return false; 1599 if (*_start == child->offset) 1600 return true; 1601 1602 // validate position 1603 off_t start = *_start; 1604 if (!validate_move_child(partition, child, child->offset, 1605 child->size, &start, get_sibling_partitions_ep)) 1606 return false; 1607 *_start = start; 1608 return true; 1609 } 1610 1611 1612 // is_type_valid_ep (auxiliary function) 1613 static inline bool 1614 is_type_valid_ep(const char* type) 1615 { 1616 // validity check of the type - it has to be known 1617 PartitionType ptype; 1618 ptype.SetType(type); 1619 return (ptype.IsValid() && !ptype.IsEmpty() && !ptype.IsExtended()); 1620 } 1621 1622 1623 // ep_validate_set_type 1624 bool 1625 ep_validate_set_type(partition_data* partition, const char* type) 1626 { 1627 TRACE(("intel: ep_validate_set_type\n")); 1628 1629 if (!partition || !type) 1630 return false; 1631 1632 // validity check of the type 1633 return is_type_valid_ep(type); 1634 } 1635 1636 1637 // ep_validate_initialize 1638 bool 1639 ep_validate_initialize(partition_data* partition, char* name, 1640 const char* parameters) 1641 { 1642 TRACE(("intel: ep_validate_initialize\n")); 1643 1644 if (!partition || !(ep_get_supported_operations(partition) 1645 & B_DISK_SYSTEM_SUPPORTS_INITIALIZING)) { 1646 return false; 1647 } 1648 // name is ignored - we cannot set it to the Intel Extended Partition 1649 // TODO: check parameters - don't know whether any parameters could be set 1650 // to the Intel Extended Partition 1651 return true; 1652 } 1653 1654 1655 // ep_validate_create_child 1656 bool 1657 ep_validate_create_child(partition_data* partition, off_t* offset, off_t* size, 1658 const char* type, const char* name, const char* parameters, int32* index) 1659 // index - returns position of the new partition (the last one) 1660 { 1661 return false; 1662 } 1663 1664 1665 // ep_get_partitionable_spaces 1666 status_t 1667 ep_get_partitionable_spaces(partition_data* partition, 1668 partitionable_space_data* buffer, int32 count, int32* actualCount) 1669 { 1670 TRACE(("intel: ep_get_partitionable_spaces\n")); 1671 1672 if (!partition || !partition->content_type 1673 || strcmp(partition->content_type, kPartitionTypeIntelExtended) 1674 || !actualCount) { 1675 return B_BAD_VALUE; 1676 } 1677 if (count > 0 && !buffer) 1678 return B_BAD_VALUE; 1679 1680 return get_partitionable_spaces(partition, buffer, count, actualCount, 1681 fill_partitionable_spaces_buffer_ep, 1682 partition->offset + PTS_OFFSET * partition->block_size, 1683 PTS_OFFSET * partition->block_size, 1684 PTS_OFFSET * partition->block_size); 1685 } 1686 1687 1688 // ep_get_next_supported_type 1689 status_t 1690 ep_get_next_supported_type(partition_data* partition, int32* cookie, 1691 char* _type) 1692 { 1693 TRACE(("intel: ep_get_next_supported_type\n")); 1694 1695 if (!partition || !partition->content_type 1696 || strcmp(partition->content_type, kPartitionTypeIntelExtended) 1697 || !cookie || !_type) { 1698 return B_BAD_VALUE; 1699 } 1700 1701 if (*cookie > 255) 1702 return B_ENTRY_NOT_FOUND; 1703 if (*cookie < 1) 1704 *cookie = 1; 1705 1706 uint8 type = *cookie; 1707 1708 // get type 1709 PartitionType ptype; 1710 ptype.SetType(type); 1711 while (ptype.IsValid() && !ptype.IsExtended()) 1712 ptype.FindNext(); 1713 1714 if (!ptype.IsValid()) 1715 return B_ENTRY_NOT_FOUND; 1716 1717 ptype.GetTypeString(_type); 1718 1719 // find next type 1720 if (ptype.FindNext()) 1721 *cookie = ptype.Type(); 1722 else 1723 *cookie = 256; 1724 1725 return B_OK; 1726 } 1727 1728 1729 // ep_shadow_changed 1730 status_t 1731 ep_shadow_changed(partition_data* partition, partition_data* child, 1732 uint32 operation) 1733 { 1734 TRACE(("intel: ep_shadow_changed\n")); 1735 1736 if (!partition) 1737 return B_BAD_VALUE; 1738 1739 // nothing to do here 1740 return B_OK; 1741 } 1742 1743 1744 bool 1745 check_partition_location_ep(partition_data* partition, off_t offset, 1746 off_t size, off_t ptsOffset) 1747 { 1748 if (!partition) 1749 return false; 1750 1751 // make sure we are sector aligned 1752 off_t alignedOffset = sector_align(offset, partition->block_size); 1753 if (alignedOffset != offset) 1754 return false; 1755 1756 // partition does not lie within extended partition 1757 if (offset < partition->offset 1758 || (offset > partition->offset + partition->size 1759 && offset + size <= partition->offset + partition->size)) 1760 return false; 1761 1762 // check if the new partition table is within an existing partition 1763 // or that the new partition does not overwrite an existing partition 1764 // table. 1765 for (int32 i = 0; i < partition->child_count; i++) { 1766 partition_data* sibling = get_child_partition(partition->id, i); 1767 LogicalPartition* logical = (LogicalPartition*)sibling->cookie; 1768 if (logical == NULL) 1769 return false; 1770 if (ptsOffset > logical->Offset() 1771 && ptsOffset < logical->Offset() + logical->Size()) 1772 return false; 1773 if ((logical->PartitionTableOffset() >= offset 1774 && logical->PartitionTableOffset() < offset + size) 1775 || logical->PartitionTableOffset() == ptsOffset) 1776 return false; 1777 } 1778 1779 return true; 1780 } 1781 1782 1783 // #pragma mark - Intel Extended Partition - write functions 1784 1785 1786 // ep_resize 1787 status_t 1788 ep_resize(int fd, partition_id partitionID, off_t size, disk_job_id job) 1789 { 1790 TRACE(("intel: ep_resize\n")); 1791 1792 if (fd < 0) 1793 return B_ERROR; 1794 1795 PartitionWriteLocker locker(partitionID); 1796 if (!locker.IsLocked()) 1797 return B_ERROR; 1798 1799 // get out partition 1800 partition_data* partition = get_partition(partitionID); 1801 if (!partition) 1802 return B_BAD_VALUE; 1803 1804 // validate the new size 1805 // TODO: The parameter has already been checked and must not be altered! 1806 off_t validatedSize = size; 1807 if (!ep_validate_resize(partition, &validatedSize)) 1808 return B_BAD_VALUE; 1809 1810 // update data stuctures 1811 update_disk_device_job_progress(job, 0.0); 1812 1813 // TODO: partition->size is not supposed to be touched. 1814 partition->size = validatedSize; 1815 partition->content_size = validatedSize; 1816 1817 // all changes applied 1818 update_disk_device_job_progress(job, 1.0); 1819 partition_modified(partitionID); 1820 return B_OK; 1821 } 1822 1823 1824 // ep_resize_child 1825 status_t 1826 ep_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job) 1827 { 1828 TRACE(("intel: ep_resize_child\n")); 1829 1830 if (fd < 0) 1831 return B_ERROR; 1832 1833 PartitionWriteLocker locker(partitionID); 1834 if (!locker.IsLocked()) 1835 return B_ERROR; 1836 1837 // get out partition, child and LogicalPartition structure 1838 partition_data* partition = get_parent_partition(partitionID); 1839 partition_data* child = get_partition(partitionID); 1840 if (!partition || !child) 1841 return B_BAD_VALUE; 1842 LogicalPartition* logical = (LogicalPartition*)child->cookie; 1843 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 1844 if (!logical || !primary) 1845 return B_BAD_VALUE; 1846 1847 // validate the new size 1848 // TODO: The parameter has already been checked and must not be altered! 1849 off_t validatedSize = size; 1850 if (!ep_validate_resize_child(partition, child, &validatedSize)) 1851 return B_BAD_VALUE; 1852 if (child->size == validatedSize) 1853 return B_OK; 1854 1855 // update data stuctures and write changes 1856 update_disk_device_job_progress(job, 0.0); 1857 logical->SetSize(validatedSize); 1858 1859 PartitionMapWriter writer(fd, partition->block_size); 1860 // TODO: The partition is not supposed to be locked here! 1861 status_t error = writer.WriteLogical(logical, primary, false); 1862 if (error != B_OK) { 1863 // putting into previous state 1864 logical->SetSize(child->size); 1865 return error; 1866 } 1867 LogicalPartition* prev = logical->Previous(); 1868 error = prev ? writer.WriteLogical(prev, primary, false) 1869 : writer.WriteLogical(logical, primary, false); 1870 if (error != B_OK) 1871 // this should be not so fatal 1872 return error; 1873 1874 child->size = validatedSize; 1875 1876 // all changes applied 1877 update_disk_device_job_progress(job, 1.0); 1878 partition_modified(partitionID); 1879 return B_OK; 1880 } 1881 1882 1883 // ep_move 1884 status_t 1885 ep_move(int fd, partition_id partitionID, off_t offset, disk_job_id job) 1886 { 1887 TRACE(("intel: ep_move\n")); 1888 1889 if (fd < 0) 1890 return B_ERROR; 1891 1892 PartitionWriteLocker locker(partitionID); 1893 if (!locker.IsLocked()) 1894 return B_ERROR; 1895 1896 // get out partition 1897 partition_data* partition = get_partition(partitionID); 1898 if (!partition) 1899 return B_BAD_VALUE; 1900 1901 // validate the new start 1902 // TODO: The parameter has already been checked and must not be altered! 1903 if (!ep_validate_move(partition, &offset)) 1904 return B_BAD_VALUE; 1905 1906 // nothing to do here 1907 return B_OK; 1908 } 1909 1910 1911 // ep_move_child 1912 status_t 1913 ep_move_child(int fd, partition_id partitionID, partition_id childID, 1914 off_t offset, disk_job_id job) 1915 { 1916 TRACE(("intel: ep_move_child\n")); 1917 1918 if (fd < 0) 1919 return B_ERROR; 1920 1921 PartitionWriteLocker locker(partitionID); 1922 if (!locker.IsLocked()) 1923 return B_ERROR; 1924 1925 // get partition, child and LogicalPartition structure 1926 partition_data* partition = get_partition(partitionID); 1927 partition_data* child = get_partition(childID); 1928 if (!partition || !child) 1929 return B_BAD_VALUE; 1930 LogicalPartition* logical = (LogicalPartition*)child->cookie; 1931 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 1932 if (!logical || !primary) 1933 return B_BAD_VALUE; 1934 1935 // TODO: The parameter has already been checked and must not be altered! 1936 off_t validatedOffset = offset; 1937 if (!ep_validate_move_child(partition, child, &validatedOffset)) 1938 return B_BAD_VALUE; 1939 1940 // if the old offset is the same, there is nothing to do 1941 if (child->offset == validatedOffset) 1942 return B_OK; 1943 1944 off_t diffOffset = validatedOffset - child->offset; 1945 1946 // buffer allocation 1947 int32 allocated; 1948 uint8* buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER, 1949 &allocated); 1950 if (!buffer) 1951 return B_NO_MEMORY; 1952 1953 // partition moving 1954 update_disk_device_job_progress(job, 0.0); 1955 status_t error = B_OK; 1956 // move partition with its header (partition table) 1957 off_t pts_offset = logical->Offset() - logical->PartitionTableOffset(); 1958 error = move_partition(fd, child->offset - pts_offset, 1959 validatedOffset - pts_offset, child->size + pts_offset, buffer, 1960 allocated * partition->block_size, job); 1961 delete[] buffer; 1962 if (error != B_OK) 1963 return error; 1964 1965 // partition moved 1966 // updating data structure 1967 child->offset = validatedOffset; 1968 logical->SetOffset(logical->Offset() + diffOffset); 1969 logical->SetPartitionTableOffset(logical->PartitionTableOffset() + diffOffset); 1970 1971 PartitionMapWriter writer(fd, partition->block_size); 1972 // TODO: If partition->offset is > prev->offset, then writing 1973 // the previous logical partition table will fail! 1974 // TODO: The partition is not supposed to be locked here! 1975 error = writer.WriteLogical(logical, primary, false); 1976 if (error != B_OK) 1977 // something went wrong - this is fatal (partition has been moved) 1978 // but EBR is not updated 1979 return error; 1980 LogicalPartition* prev = logical->Previous(); 1981 error = prev ? writer.WriteLogical(prev, primary, false) 1982 : writer.WriteLogical(logical, primary, false); 1983 if (error != B_OK) 1984 // this is fatal - linked list is not updated 1985 return error; 1986 1987 // all changes applied 1988 update_disk_device_job_progress(job, 1.0); 1989 partition_modified(childID); 1990 return B_OK; 1991 } 1992 1993 1994 // ep_set_type 1995 status_t 1996 ep_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job) 1997 { 1998 TRACE(("intel: ep_set_type\n")); 1999 2000 if (fd < 0 || !type) 2001 return B_BAD_VALUE; 2002 2003 PartitionWriteLocker locker(partitionID); 2004 if (!locker.IsLocked()) 2005 return B_ERROR; 2006 2007 // get partition, child and LogicalPartition structure 2008 partition_data* partition = get_parent_partition(partitionID); 2009 partition_data* child = get_partition(partitionID); 2010 if (!partition || !child) 2011 return B_BAD_VALUE; 2012 LogicalPartition* logical = (LogicalPartition*)child->cookie; 2013 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2014 if (!logical || !primary) 2015 return B_BAD_VALUE; 2016 2017 // TODO: The parameter has already been checked and must not be altered! 2018 if (!ep_validate_set_type(child, type)) 2019 return B_BAD_VALUE; 2020 2021 // if the old type is the same, there is nothing to do 2022 if (child->type && !strcmp(type, child->type)) 2023 return B_OK; 2024 2025 PartitionType ptype; 2026 ptype.SetType(type); 2027 // this is impossible 2028 if (!ptype.IsValid() || ptype.IsEmpty() || ptype.IsExtended()) 2029 return false; 2030 2031 // setting type to the partition 2032 update_disk_device_job_progress(job, 0.0); 2033 uint8 oldType = logical->Type(); 2034 logical->SetType(ptype.Type()); 2035 2036 PartitionMapWriter writer(fd, partition->block_size); 2037 // TODO: The partition is not supposed to be locked here! 2038 status_t error = writer.WriteLogical(logical, primary, false); 2039 if (error != B_OK) { 2040 // something went wrong - putting into previous state 2041 logical->SetType(oldType); 2042 return error; 2043 } 2044 2045 free(child->type); 2046 child->type = strdup(type); 2047 if (!child->type) 2048 return B_NO_MEMORY; 2049 2050 // all changes applied 2051 update_disk_device_job_progress(job, 1.0); 2052 partition_modified(partitionID); 2053 return B_OK; 2054 } 2055 2056 2057 // ep_initialize 2058 status_t 2059 ep_initialize(int fd, partition_id partitionID, const char* name, 2060 const char* parameters, off_t partitionSize, disk_job_id job) 2061 { 2062 TRACE(("intel: ep_initialize\n")); 2063 2064 if (fd < 0) 2065 return B_ERROR; 2066 2067 PartitionWriteLocker locker(partitionID); 2068 if (!locker.IsLocked()) 2069 return B_ERROR; 2070 2071 // get partition 2072 partition_data* partition = get_partition(partitionID); 2073 if (!partition) 2074 return B_BAD_VALUE; 2075 2076 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2077 if (!primary) 2078 return B_BAD_VALUE; 2079 2080 // name is ignored - we cannot set it to the Intel Extended Partition 2081 // TODO: The parameter has already been checked and must not be altered! 2082 if (!ep_validate_initialize(partition, NULL, parameters)) 2083 return B_BAD_VALUE; 2084 2085 // partition init (we have no child partition) 2086 update_disk_device_job_progress(job, 0.0); 2087 // fill in the partition_data structure 2088 partition->status = B_PARTITION_VALID; 2089 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 2090 partition->content_size = partition->size; 2091 // (no content_name and content_parameters) 2092 // (content_type is set by the system) 2093 partition->content_cookie = primary; 2094 2095 // we delete code area in EBR - nothing should be there 2096 partition_table table; 2097 table.clear_code_area(); 2098 2099 PartitionMapWriter writer(fd, partition->block_size); 2100 // TODO: The partition is not supposed to be locked here! 2101 status_t error = writer.ClearExtendedHead(primary); 2102 if (error != B_OK) 2103 return error; 2104 2105 // all changes applied 2106 update_disk_device_job_progress(job, 1.0); 2107 partition_modified(partitionID); 2108 return B_OK; 2109 } 2110 2111 2112 // ep_create_child 2113 /*! 2114 childID is used for the return value, but is also an optional input 2115 parameter -- -1 to be ignored 2116 */ 2117 status_t 2118 ep_create_child(int fd, partition_id partitionID, off_t offset, off_t size, 2119 const char* type, const char* name, const char* parameters, disk_job_id job, 2120 partition_id* childID) 2121 { 2122 TRACE(("intel: ep_create_child\n")); 2123 2124 if (fd < 0 || !childID) 2125 return B_BAD_VALUE; 2126 2127 // aquire lock 2128 PartitionWriteLocker locker(partitionID); 2129 if (!locker.IsLocked()) 2130 return B_ERROR; 2131 2132 // get partition data 2133 partition_data* partition = get_partition(partitionID); 2134 partition_data* parent = get_parent_partition(partitionID); 2135 if (partition == NULL || parent == NULL) 2136 return B_BAD_VALUE; 2137 2138 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2139 if (!primary) 2140 return B_BAD_VALUE; 2141 2142 // parse parameters 2143 void* handle = parse_driver_settings_string(parameters); 2144 if (handle == NULL) 2145 return B_ERROR; 2146 2147 bool active = get_driver_boolean_parameter(handle, "active", false, true); 2148 2149 off_t ptsOffset = 0; 2150 const char* buffer = get_driver_parameter( 2151 handle, "partition_table_offset", NULL, NULL); 2152 if (buffer != NULL) 2153 ptsOffset = strtoull(buffer, NULL, 10); 2154 else { 2155 delete_driver_settings(handle); 2156 return B_BAD_VALUE; 2157 } 2158 delete_driver_settings(handle); 2159 2160 // check the partition location 2161 if (!check_partition_location_ep(partition, offset, size, ptsOffset)) 2162 return B_BAD_VALUE; 2163 2164 // creating partition 2165 update_disk_device_job_progress(job, 0.0); 2166 partition_data* child = create_child_partition(partition->id, 2167 partition->child_count, offset, size, *childID); 2168 if (!child) 2169 return B_ERROR; 2170 2171 // setup logical partition 2172 LogicalPartition* logical = new(nothrow) LogicalPartition; 2173 if (!logical) 2174 return B_NO_MEMORY; 2175 2176 PartitionType ptype; 2177 ptype.SetType(type); 2178 logical->SetPartitionTableOffset(ptsOffset - parent->offset); 2179 logical->SetOffset(offset); 2180 logical->SetSize(size); 2181 logical->SetType(ptype.Type()); 2182 logical->SetActive(active); 2183 logical->SetPrimaryPartition(primary); 2184 logical->SetBlockSize(partition->block_size); 2185 primary->AddLogicalPartition(logical); 2186 2187 int parentFD = open_partition(parent->id, O_RDWR); 2188 if (parentFD < 0) { 2189 primary->RemoveLogicalPartition(logical); 2190 delete logical; 2191 return B_IO_ERROR; 2192 } 2193 2194 // write changes to disk 2195 PartitionMapWriter writer(parentFD, primary->BlockSize()); 2196 2197 // Write the logical partition's EBR first in case of failure. 2198 // This way we will not add a partition to the previous logical 2199 // partition. If there is no previous logical partition then write 2200 // the current partition's EBR to the first sector of the primary partition 2201 status_t error = writer.WriteLogical(logical, primary, true); 2202 if (error != B_OK) { 2203 primary->RemoveLogicalPartition(logical); 2204 delete logical; 2205 return error; 2206 } 2207 2208 LogicalPartition* previous = logical->Previous(); 2209 if (previous != NULL) { 2210 error = writer.WriteLogical(previous, primary, true); 2211 if (error != B_OK) { 2212 primary->RemoveLogicalPartition(logical); 2213 delete logical; 2214 return error; 2215 } 2216 } 2217 *childID = child->id; 2218 2219 child->block_size = logical->BlockSize(); 2220 child->type = strdup(type); 2221 child->parameters = strdup(parameters); 2222 child->cookie = logical; 2223 // check for allocation problems 2224 if (!child->type || !child->parameters) 2225 error = B_NO_MEMORY; 2226 2227 // all changes applied 2228 update_disk_device_job_progress(job, 1.0); 2229 partition_modified(partitionID); 2230 return B_OK; 2231 } 2232 2233 2234 // ep_delete_child 2235 status_t 2236 ep_delete_child(int fd, partition_id partitionID, partition_id childID, 2237 disk_job_id job) 2238 { 2239 TRACE(("intel: ep_delete_child\n")); 2240 2241 if (fd < 0) 2242 return B_ERROR; 2243 2244 PartitionWriteLocker locker(partitionID); 2245 if (!locker.IsLocked()) 2246 return B_ERROR; 2247 2248 partition_data* partition = get_partition(partitionID); 2249 partition_data* parent = get_parent_partition(partitionID); 2250 partition_data* child = get_partition(childID); 2251 if (partition == NULL || parent == NULL || child == NULL) 2252 return B_BAD_VALUE; 2253 2254 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2255 LogicalPartition* logical = (LogicalPartition*)child->cookie; 2256 if (primary == NULL || logical == NULL) 2257 return B_BAD_VALUE; 2258 2259 // deleting child 2260 update_disk_device_job_progress(job, 0.0); 2261 if (!delete_partition(childID)) 2262 return B_ERROR; 2263 2264 LogicalPartition* previous = logical->Previous(); 2265 LogicalPartition* next = logical->Next(); 2266 2267 primary->RemoveLogicalPartition(logical); 2268 delete logical; 2269 2270 int parentFD = open_partition(parent->id, O_RDWR); 2271 if (parentFD < 0) 2272 return B_IO_ERROR; 2273 2274 // write changes to disk 2275 PartitionMapWriter writer(parentFD, primary->BlockSize()); 2276 2277 status_t error; 2278 if (previous != NULL) { 2279 error = writer.WriteLogical(previous, primary, true); 2280 } else { 2281 error = writer.WriteExtendedHead(next, primary, true); 2282 2283 if (next != NULL) { 2284 next->SetPartitionTableOffset(primary->Offset()); 2285 2286 partition_data* nextSibling = NULL; 2287 if (get_partition_from_offset_ep(partition, next->Offset(), 2288 &nextSibling)) { 2289 char buffer[128]; 2290 sprintf(buffer, "active %s ;\npartition_table_offset %" B_PRId64 2291 " ;\n", next->Active() ? "true" : "false", 2292 next->PartitionTableOffset()); 2293 nextSibling->parameters = strdup(buffer); 2294 } 2295 } 2296 } 2297 2298 close(parentFD); 2299 2300 if (error != B_OK) 2301 return error; 2302 2303 // all changes applied 2304 update_disk_device_job_progress(job, 1.0); 2305 partition_modified(partitionID); 2306 return B_OK; 2307 } 2308 2309