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_set_parameters 1253 status_t 1254 pm_set_parameters(int fd, partition_id partitionID, const char* parameters, 1255 disk_job_id job) 1256 { 1257 TRACE(("intel: pm_set_parameters\n")); 1258 1259 if (fd < 0) 1260 return B_BAD_VALUE; 1261 1262 // Nothing to do if there are no parameters provided 1263 if (parameters == NULL) 1264 return B_OK; 1265 1266 PartitionWriteLocker locker(partitionID); 1267 if (!locker.IsLocked()) 1268 return B_ERROR; 1269 1270 // get parent partition, child and partition map structure 1271 partition_data* partition = get_parent_partition(partitionID); 1272 partition_data* child = get_partition(partitionID); 1273 if (partition == NULL || child == NULL) 1274 return B_BAD_VALUE; 1275 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1276 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 1277 if (map ==NULL || primary == NULL) 1278 return B_BAD_VALUE; 1279 1280 // check parameters 1281 void* handle = parse_driver_settings_string(parameters); 1282 if (handle == NULL) 1283 return B_ERROR; 1284 1285 bool active = get_driver_boolean_parameter(handle, "active", false, true); 1286 delete_driver_settings(handle); 1287 1288 // if the old type is the same, there is nothing to do 1289 if (primary->Active() == active) { 1290 TRACE(("intel: pm_set_parameters: no changes required.\n")); 1291 return B_OK; 1292 } 1293 1294 update_disk_device_job_progress(job, 0.0); 1295 1296 // set the active flags to false for other partitions 1297 if (active) { 1298 for (int i = 0; i < 4; i++) { 1299 PrimaryPartition* partition = map->PrimaryPartitionAt(i); 1300 partition->SetActive(false); 1301 } 1302 } 1303 1304 bool oldActive = primary->Active(); 1305 primary->SetActive(active); 1306 1307 // TODO: The partition is not supposed to be locked at this point! 1308 PartitionMapWriter writer(fd, primary->BlockSize()); 1309 // TODO: disk size? 1310 status_t error = writer.WriteMBR(map, false); 1311 if (error != B_OK) { 1312 TRACE(("intel: pm_set_parameters: Failed to rewrite MBR: %s\n", 1313 strerror(error))); 1314 // something went wrong - putting into previous state 1315 primary->SetType(oldActive); 1316 return error; 1317 } 1318 1319 // all changes applied 1320 update_disk_device_job_progress(job, 1.0); 1321 partition_modified(partitionID); 1322 return B_OK; 1323 } 1324 1325 1326 // pm_initialize 1327 status_t 1328 pm_initialize(int fd, partition_id partitionID, const char* name, 1329 const char* parameters, off_t partitionSize, disk_job_id job) 1330 { 1331 TRACE(("intel: pm_initialize\n")); 1332 1333 if (fd < 0) 1334 return B_ERROR; 1335 1336 PartitionWriteLocker locker(partitionID); 1337 if (!locker.IsLocked()) 1338 return B_ERROR; 1339 1340 // get partition and partition map structure 1341 partition_data* partition = get_partition(partitionID); 1342 if (!partition) 1343 return B_BAD_VALUE; 1344 update_disk_device_job_progress(job, 0.0); 1345 1346 // we will write an empty partition map 1347 PartitionMap map; 1348 1349 // write the sector to disk 1350 PartitionMapWriter writer(fd, partition->block_size); 1351 // TODO: disk size or 2 * SECTOR_SIZE? 1352 status_t error = writer.WriteMBR(&map, true); 1353 if (error != B_OK) 1354 return error; 1355 1356 // rescan partition 1357 error = scan_partition(partitionID); 1358 if (error != B_OK) 1359 return error; 1360 1361 // all changes applied 1362 update_disk_device_job_progress(job, 1.0); 1363 partition_modified(partitionID); 1364 1365 return B_OK; 1366 } 1367 1368 1369 status_t 1370 pm_uninitialize(int fd, partition_id partitionID, off_t partitionSize, 1371 uint32 blockSize, disk_job_id job) 1372 { 1373 if (blockSize == 0) 1374 return B_BAD_VALUE; 1375 1376 // We overwrite the first block, which contains the partition table. 1377 // Allocate a buffer, we can clear and write. 1378 void* block = malloc(blockSize); 1379 if (block == NULL) 1380 return B_NO_MEMORY; 1381 MemoryDeleter blockDeleter(block); 1382 1383 memset(block, 0, blockSize); 1384 1385 if (write_pos(fd, 0, block, blockSize) < 0) 1386 return errno; 1387 1388 update_disk_device_job_progress(job, 1.0); 1389 1390 return B_OK; 1391 } 1392 1393 1394 // pm_create_child 1395 /*! childID is used for the return value, but is also an optional input 1396 parameter -- -1 to be ignored 1397 */ 1398 status_t 1399 pm_create_child(int fd, partition_id partitionID, off_t offset, off_t size, 1400 const char* type, const char* name, const char* parameters, 1401 disk_job_id job, partition_id* childID) 1402 { 1403 TRACE(("intel: pm_create_child\n")); 1404 1405 if (fd < 0 || !childID) 1406 return B_BAD_VALUE; 1407 1408 PartitionWriteLocker locker(partitionID); 1409 if (!locker.IsLocked()) 1410 return B_ERROR; 1411 1412 // get partition and partition map structure 1413 partition_data* partition = get_partition(partitionID); 1414 if (!partition) 1415 return B_BAD_VALUE; 1416 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1417 if (!map) 1418 return B_BAD_VALUE; 1419 1420 // validate the offset, size and get index of the new partition 1421 // TODO: The parameters have already been checked and must not be altered! 1422 off_t validatedOffset = offset; 1423 off_t validatedSize = size; 1424 int32 index = 0; 1425 1426 if (!pm_validate_create_child(partition, &validatedOffset, &validatedSize, 1427 type, name, parameters, &index)) { 1428 return B_BAD_VALUE; 1429 } 1430 1431 // finding out free primary partition in the map (index from 1432 // pm_validate_create_child) 1433 PrimaryPartition* primary = map->PrimaryPartitionAt(index); 1434 if (!primary->IsEmpty()) 1435 return B_BAD_DATA; 1436 1437 // creating partition 1438 update_disk_device_job_progress(job, 0.0); 1439 partition_data* child = create_child_partition(partition->id, index, 1440 validatedOffset, validatedSize, *childID); 1441 if (!child) 1442 return B_ERROR; 1443 1444 PartitionType ptype; 1445 ptype.SetType(type); 1446 1447 // check parameters 1448 void* handle = parse_driver_settings_string(parameters); 1449 if (handle == NULL) 1450 return B_ERROR; 1451 1452 bool active = get_driver_boolean_parameter(handle, "active", false, true); 1453 delete_driver_settings(handle); 1454 1455 // set the active flags to false 1456 if (active) { 1457 for (int i = 0; i < 4; i++) { 1458 PrimaryPartition* partition = map->PrimaryPartitionAt(i); 1459 partition->SetActive(false); 1460 } 1461 } 1462 1463 primary->SetPartitionTableOffset(0); 1464 primary->SetOffset(validatedOffset); 1465 primary->SetSize(validatedSize); 1466 primary->SetType(ptype.Type()); 1467 primary->SetActive(active); 1468 1469 // write changes to disk 1470 PartitionMapWriter writer(fd, primary->BlockSize()); 1471 1472 // TODO: The partition is not supposed to be locked at this point! 1473 status_t error = writer.WriteMBR(map, false); 1474 if (error != B_OK) { 1475 // putting into previous state 1476 primary->Unset(); 1477 delete_partition(child->id); 1478 return error; 1479 } 1480 1481 *childID = child->id; 1482 1483 child->block_size = primary->BlockSize(); 1484 // (no name) 1485 child->type = strdup(type); 1486 // parameters 1487 child->parameters = strdup(parameters); 1488 child->cookie = primary; 1489 // check for allocation problems 1490 if (!child->type || !child->parameters) 1491 return B_NO_MEMORY; 1492 1493 // rescan partition if needed 1494 if (strcmp(type, INTEL_EXTENDED_PARTITION_NAME) == 0) { 1495 writer.ClearExtendedHead(primary); 1496 error = scan_partition(partitionID); 1497 if (error != B_OK) 1498 return error; 1499 } 1500 1501 // all changes applied 1502 update_disk_device_job_progress(job, 1.0); 1503 partition_modified(partitionID); 1504 return B_OK; 1505 } 1506 1507 1508 // pm_delete_child 1509 status_t 1510 pm_delete_child(int fd, partition_id partitionID, partition_id childID, 1511 disk_job_id job) 1512 { 1513 TRACE(("intel: pm_delete_child\n")); 1514 1515 if (fd < 0) 1516 return B_ERROR; 1517 1518 PartitionWriteLocker locker(partitionID); 1519 if (!locker.IsLocked()) 1520 return B_ERROR; 1521 1522 partition_data* partition = get_partition(partitionID); 1523 partition_data* child = get_partition(childID); 1524 if (!partition || !child) 1525 return B_BAD_VALUE; 1526 1527 PartitionMap* map = (PartitionMap*)partition->content_cookie; 1528 PrimaryPartition* primary = (PrimaryPartition*)child->cookie; 1529 if (!map || !primary) 1530 return B_BAD_VALUE; 1531 1532 // deleting child 1533 update_disk_device_job_progress(job, 0.0); 1534 if (!delete_partition(childID)) 1535 return B_ERROR; 1536 primary->Unset(); 1537 1538 // write changes to disk 1539 PartitionMapWriter writer(fd, primary->BlockSize()); 1540 // TODO: disk size or 2 * SECTOR_SIZE? 1541 // TODO: The partition is not supposed to be locked at this point! 1542 status_t error = writer.WriteMBR(map, false); 1543 if (error != B_OK) 1544 return error; 1545 1546 // all changes applied 1547 update_disk_device_job_progress(job, 1.0); 1548 partition_modified(partitionID); 1549 return B_OK; 1550 } 1551 1552 1553 // #pragma mark - Intel Extended Partition - support functions 1554 1555 1556 // ep_get_supported_operations 1557 uint32 1558 ep_get_supported_operations(partition_data* partition, uint32 mask) 1559 { 1560 uint32 flags = B_DISK_SYSTEM_SUPPORTS_RESIZING 1561 | B_DISK_SYSTEM_SUPPORTS_MOVING 1562 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS; 1563 1564 // initializing 1565 if (partition_data* parent = get_parent_partition(partition->id)) { 1566 if (partition->type 1567 && strcmp(partition->type, kPartitionTypeIntelExtended) == 0 1568 && strcmp(parent->content_type, kPartitionTypeIntel) == 0) { 1569 flags |= B_DISK_SYSTEM_SUPPORTS_INITIALIZING; 1570 } 1571 } 1572 1573 // creating child 1574 int32 countSpaces = 0; 1575 if (ep_get_partitionable_spaces(partition, NULL, 0, &countSpaces) 1576 == B_BUFFER_OVERFLOW 1577 && countSpaces > 0) { 1578 flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD; 1579 } 1580 1581 return flags; 1582 } 1583 1584 1585 // ep_get_supported_child_operations 1586 uint32 1587 ep_get_supported_child_operations(partition_data* partition, 1588 partition_data* child, uint32 mask) 1589 { 1590 return B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 1591 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 1592 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 1593 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD; 1594 } 1595 1596 1597 // ep_is_sub_system_for 1598 bool 1599 ep_is_sub_system_for(partition_data* partition) 1600 { 1601 if (partition == NULL) 1602 return false; 1603 1604 TRACE(("intel: ep_is_sub_system_for(%" B_PRId32 ": %" B_PRId64 ", " 1605 "%" B_PRId64 ", %" B_PRId32 ", %s)\n", partition->id, partition->offset, 1606 partition->size, partition->block_size, partition->content_type)); 1607 1608 // Intel Extended Partition can live in child partition of Intel Partition 1609 // Map 1610 return partition->content_type 1611 && !strcmp(partition->content_type, kPartitionTypeIntel); 1612 } 1613 1614 1615 // #pragma mark - Intel Extended Partition - validate functions 1616 1617 1618 // ep_validate_resize 1619 bool 1620 ep_validate_resize(partition_data* partition, off_t* size) 1621 { 1622 TRACE(("intel: ep_validate_resize\n")); 1623 1624 if (!partition || !size) 1625 return false; 1626 1627 return validate_resize(partition, size); 1628 } 1629 1630 1631 // ep_validate_resize_child 1632 bool 1633 ep_validate_resize_child(partition_data* partition, partition_data* child, 1634 off_t* _size) 1635 { 1636 TRACE(("intel: ep_validate_resize_child\n")); 1637 1638 if (!partition || !child || !_size) 1639 return false; 1640 1641 // validate position 1642 off_t size = *_size; 1643 if (!validate_resize_child(partition, child, child->offset, 1644 child->size, &size, get_sibling_partitions_ep)) 1645 return false; 1646 *_size = size; 1647 return true; 1648 } 1649 1650 1651 // ep_validate_move 1652 bool 1653 ep_validate_move(partition_data* partition, off_t* start) 1654 { 1655 TRACE(("intel: ep_validate_move\n")); 1656 1657 if (!partition || !start) 1658 return false; 1659 // nothing to do here 1660 return true; 1661 } 1662 1663 1664 // ep_validate_move_child 1665 bool 1666 ep_validate_move_child(partition_data* partition, partition_data* child, 1667 off_t* _start) 1668 { 1669 TRACE(("intel: ep_validate_move_child\n")); 1670 1671 if (!partition || !child || !_start) 1672 return false; 1673 if (*_start == child->offset) 1674 return true; 1675 1676 // validate position 1677 off_t start = *_start; 1678 if (!validate_move_child(partition, child, child->offset, 1679 child->size, &start, get_sibling_partitions_ep)) 1680 return false; 1681 *_start = start; 1682 return true; 1683 } 1684 1685 1686 // is_type_valid_ep (auxiliary function) 1687 static inline bool 1688 is_type_valid_ep(const char* type) 1689 { 1690 // validity check of the type - it has to be known 1691 PartitionType ptype; 1692 ptype.SetType(type); 1693 return (ptype.IsValid() && !ptype.IsEmpty() && !ptype.IsExtended()); 1694 } 1695 1696 1697 // ep_validate_set_type 1698 bool 1699 ep_validate_set_type(partition_data* partition, const char* type) 1700 { 1701 TRACE(("intel: ep_validate_set_type\n")); 1702 1703 if (!partition || !type) 1704 return false; 1705 1706 // validity check of the type 1707 return is_type_valid_ep(type); 1708 } 1709 1710 1711 // ep_validate_initialize 1712 bool 1713 ep_validate_initialize(partition_data* partition, char* name, 1714 const char* parameters) 1715 { 1716 TRACE(("intel: ep_validate_initialize\n")); 1717 1718 if (!partition || !(ep_get_supported_operations(partition) 1719 & B_DISK_SYSTEM_SUPPORTS_INITIALIZING)) { 1720 return false; 1721 } 1722 // name is ignored - we cannot set it to the Intel Extended Partition 1723 // TODO: check parameters - don't know whether any parameters could be set 1724 // to the Intel Extended Partition 1725 return true; 1726 } 1727 1728 1729 // ep_validate_create_child 1730 bool 1731 ep_validate_create_child(partition_data* partition, off_t* offset, off_t* size, 1732 const char* type, const char* name, const char* parameters, int32* index) 1733 // index - returns position of the new partition (the last one) 1734 { 1735 return false; 1736 } 1737 1738 1739 // ep_get_partitionable_spaces 1740 status_t 1741 ep_get_partitionable_spaces(partition_data* partition, 1742 partitionable_space_data* buffer, int32 count, int32* actualCount) 1743 { 1744 TRACE(("intel: ep_get_partitionable_spaces\n")); 1745 1746 if (!partition || !partition->content_type 1747 || strcmp(partition->content_type, kPartitionTypeIntelExtended) 1748 || !actualCount) { 1749 return B_BAD_VALUE; 1750 } 1751 if (count > 0 && !buffer) 1752 return B_BAD_VALUE; 1753 1754 return get_partitionable_spaces(partition, buffer, count, actualCount, 1755 fill_partitionable_spaces_buffer_ep, 1756 partition->offset + PTS_OFFSET * partition->block_size, 1757 PTS_OFFSET * partition->block_size, 1758 PTS_OFFSET * partition->block_size); 1759 } 1760 1761 1762 // ep_get_next_supported_type 1763 status_t 1764 ep_get_next_supported_type(partition_data* partition, int32* cookie, 1765 char* _type) 1766 { 1767 TRACE(("intel: ep_get_next_supported_type\n")); 1768 1769 if (!partition || !partition->content_type 1770 || strcmp(partition->content_type, kPartitionTypeIntelExtended) 1771 || !cookie || !_type) { 1772 return B_BAD_VALUE; 1773 } 1774 1775 if (*cookie > 255) 1776 return B_ENTRY_NOT_FOUND; 1777 if (*cookie < 1) 1778 *cookie = 1; 1779 1780 uint8 type = *cookie; 1781 1782 // get type 1783 PartitionType ptype; 1784 ptype.SetType(type); 1785 while (ptype.IsValid() && !ptype.IsExtended()) 1786 ptype.FindNext(); 1787 1788 if (!ptype.IsValid()) 1789 return B_ENTRY_NOT_FOUND; 1790 1791 ptype.GetTypeString(_type); 1792 1793 // find next type 1794 if (ptype.FindNext()) 1795 *cookie = ptype.Type(); 1796 else 1797 *cookie = 256; 1798 1799 return B_OK; 1800 } 1801 1802 1803 // ep_shadow_changed 1804 status_t 1805 ep_shadow_changed(partition_data* partition, partition_data* child, 1806 uint32 operation) 1807 { 1808 TRACE(("intel: ep_shadow_changed\n")); 1809 1810 if (!partition) 1811 return B_BAD_VALUE; 1812 1813 // nothing to do here 1814 return B_OK; 1815 } 1816 1817 1818 bool 1819 check_partition_location_ep(partition_data* partition, off_t offset, 1820 off_t size, off_t ptsOffset) 1821 { 1822 if (!partition) 1823 return false; 1824 1825 // make sure we are sector aligned 1826 off_t alignedOffset = sector_align(offset, partition->block_size); 1827 if (alignedOffset != offset) 1828 return false; 1829 1830 // partition does not lie within extended partition 1831 if (offset < partition->offset 1832 || (offset > partition->offset + partition->size 1833 && offset + size <= partition->offset + partition->size)) 1834 return false; 1835 1836 // check if the new partition table is within an existing partition 1837 // or that the new partition does not overwrite an existing partition 1838 // table. 1839 for (int32 i = 0; i < partition->child_count; i++) { 1840 partition_data* sibling = get_child_partition(partition->id, i); 1841 LogicalPartition* logical = (LogicalPartition*)sibling->cookie; 1842 if (logical == NULL) 1843 return false; 1844 if (ptsOffset > logical->Offset() 1845 && ptsOffset < logical->Offset() + logical->Size()) 1846 return false; 1847 if ((logical->PartitionTableOffset() >= offset 1848 && logical->PartitionTableOffset() < offset + size) 1849 || logical->PartitionTableOffset() == ptsOffset) 1850 return false; 1851 } 1852 1853 return true; 1854 } 1855 1856 1857 // #pragma mark - Intel Extended Partition - write functions 1858 1859 1860 // ep_resize 1861 status_t 1862 ep_resize(int fd, partition_id partitionID, off_t size, disk_job_id job) 1863 { 1864 TRACE(("intel: ep_resize\n")); 1865 1866 if (fd < 0) 1867 return B_ERROR; 1868 1869 PartitionWriteLocker locker(partitionID); 1870 if (!locker.IsLocked()) 1871 return B_ERROR; 1872 1873 // get out partition 1874 partition_data* partition = get_partition(partitionID); 1875 if (!partition) 1876 return B_BAD_VALUE; 1877 1878 // validate the new size 1879 // TODO: The parameter has already been checked and must not be altered! 1880 off_t validatedSize = size; 1881 if (!ep_validate_resize(partition, &validatedSize)) 1882 return B_BAD_VALUE; 1883 1884 // update data stuctures 1885 update_disk_device_job_progress(job, 0.0); 1886 1887 // TODO: partition->size is not supposed to be touched. 1888 partition->size = validatedSize; 1889 partition->content_size = validatedSize; 1890 1891 // all changes applied 1892 update_disk_device_job_progress(job, 1.0); 1893 partition_modified(partitionID); 1894 return B_OK; 1895 } 1896 1897 1898 // ep_resize_child 1899 status_t 1900 ep_resize_child(int fd, partition_id partitionID, off_t size, disk_job_id job) 1901 { 1902 TRACE(("intel: ep_resize_child\n")); 1903 1904 if (fd < 0) 1905 return B_ERROR; 1906 1907 PartitionWriteLocker locker(partitionID); 1908 if (!locker.IsLocked()) 1909 return B_ERROR; 1910 1911 // get out partition, child and LogicalPartition structure 1912 partition_data* partition = get_parent_partition(partitionID); 1913 partition_data* child = get_partition(partitionID); 1914 if (!partition || !child) 1915 return B_BAD_VALUE; 1916 LogicalPartition* logical = (LogicalPartition*)child->cookie; 1917 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 1918 if (!logical || !primary) 1919 return B_BAD_VALUE; 1920 1921 // validate the new size 1922 // TODO: The parameter has already been checked and must not be altered! 1923 off_t validatedSize = size; 1924 if (!ep_validate_resize_child(partition, child, &validatedSize)) 1925 return B_BAD_VALUE; 1926 if (child->size == validatedSize) 1927 return B_OK; 1928 1929 // update data stuctures and write changes 1930 update_disk_device_job_progress(job, 0.0); 1931 logical->SetSize(validatedSize); 1932 1933 PartitionMapWriter writer(fd, partition->block_size); 1934 // TODO: The partition is not supposed to be locked here! 1935 status_t error = writer.WriteLogical(logical, primary, false); 1936 if (error != B_OK) { 1937 // putting into previous state 1938 logical->SetSize(child->size); 1939 return error; 1940 } 1941 LogicalPartition* prev = logical->Previous(); 1942 error = prev ? writer.WriteLogical(prev, primary, false) 1943 : writer.WriteLogical(logical, primary, false); 1944 if (error != B_OK) 1945 // this should be not so fatal 1946 return error; 1947 1948 child->size = validatedSize; 1949 1950 // all changes applied 1951 update_disk_device_job_progress(job, 1.0); 1952 partition_modified(partitionID); 1953 return B_OK; 1954 } 1955 1956 1957 // ep_move 1958 status_t 1959 ep_move(int fd, partition_id partitionID, off_t offset, disk_job_id job) 1960 { 1961 TRACE(("intel: ep_move\n")); 1962 1963 if (fd < 0) 1964 return B_ERROR; 1965 1966 PartitionWriteLocker locker(partitionID); 1967 if (!locker.IsLocked()) 1968 return B_ERROR; 1969 1970 // get out partition 1971 partition_data* partition = get_partition(partitionID); 1972 if (!partition) 1973 return B_BAD_VALUE; 1974 1975 // validate the new start 1976 // TODO: The parameter has already been checked and must not be altered! 1977 if (!ep_validate_move(partition, &offset)) 1978 return B_BAD_VALUE; 1979 1980 // nothing to do here 1981 return B_OK; 1982 } 1983 1984 1985 // ep_move_child 1986 status_t 1987 ep_move_child(int fd, partition_id partitionID, partition_id childID, 1988 off_t offset, disk_job_id job) 1989 { 1990 TRACE(("intel: ep_move_child\n")); 1991 1992 if (fd < 0) 1993 return B_ERROR; 1994 1995 PartitionWriteLocker locker(partitionID); 1996 if (!locker.IsLocked()) 1997 return B_ERROR; 1998 1999 // get partition, child and LogicalPartition structure 2000 partition_data* partition = get_partition(partitionID); 2001 partition_data* child = get_partition(childID); 2002 if (!partition || !child) 2003 return B_BAD_VALUE; 2004 LogicalPartition* logical = (LogicalPartition*)child->cookie; 2005 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2006 if (!logical || !primary) 2007 return B_BAD_VALUE; 2008 2009 // TODO: The parameter has already been checked and must not be altered! 2010 off_t validatedOffset = offset; 2011 if (!ep_validate_move_child(partition, child, &validatedOffset)) 2012 return B_BAD_VALUE; 2013 2014 // if the old offset is the same, there is nothing to do 2015 if (child->offset == validatedOffset) 2016 return B_OK; 2017 2018 off_t diffOffset = validatedOffset - child->offset; 2019 2020 // buffer allocation 2021 int32 allocated; 2022 uint8* buffer = allocate_buffer(partition->block_size, MAX_MOVE_BUFFER, 2023 &allocated); 2024 if (!buffer) 2025 return B_NO_MEMORY; 2026 2027 // partition moving 2028 update_disk_device_job_progress(job, 0.0); 2029 status_t error = B_OK; 2030 // move partition with its header (partition table) 2031 off_t pts_offset = logical->Offset() - logical->PartitionTableOffset(); 2032 error = move_partition(fd, child->offset - pts_offset, 2033 validatedOffset - pts_offset, child->size + pts_offset, buffer, 2034 allocated * partition->block_size, job); 2035 delete[] buffer; 2036 if (error != B_OK) 2037 return error; 2038 2039 // partition moved 2040 // updating data structure 2041 child->offset = validatedOffset; 2042 logical->SetOffset(logical->Offset() + diffOffset); 2043 logical->SetPartitionTableOffset(logical->PartitionTableOffset() + diffOffset); 2044 2045 PartitionMapWriter writer(fd, partition->block_size); 2046 // TODO: If partition->offset is > prev->offset, then writing 2047 // the previous logical partition table will fail! 2048 // TODO: The partition is not supposed to be locked here! 2049 error = writer.WriteLogical(logical, primary, false); 2050 if (error != B_OK) 2051 // something went wrong - this is fatal (partition has been moved) 2052 // but EBR is not updated 2053 return error; 2054 LogicalPartition* prev = logical->Previous(); 2055 error = prev ? writer.WriteLogical(prev, primary, false) 2056 : writer.WriteLogical(logical, primary, false); 2057 if (error != B_OK) 2058 // this is fatal - linked list is not updated 2059 return error; 2060 2061 // all changes applied 2062 update_disk_device_job_progress(job, 1.0); 2063 partition_modified(childID); 2064 return B_OK; 2065 } 2066 2067 2068 // ep_set_type 2069 status_t 2070 ep_set_type(int fd, partition_id partitionID, const char* type, disk_job_id job) 2071 { 2072 TRACE(("intel: ep_set_type\n")); 2073 2074 if (fd < 0 || !type) 2075 return B_BAD_VALUE; 2076 2077 PartitionWriteLocker locker(partitionID); 2078 if (!locker.IsLocked()) 2079 return B_ERROR; 2080 2081 // get partition, child and LogicalPartition structure 2082 partition_data* partition = get_parent_partition(partitionID); 2083 partition_data* child = get_partition(partitionID); 2084 if (!partition || !child) 2085 return B_BAD_VALUE; 2086 LogicalPartition* logical = (LogicalPartition*)child->cookie; 2087 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2088 if (!logical || !primary) 2089 return B_BAD_VALUE; 2090 2091 // TODO: The parameter has already been checked and must not be altered! 2092 if (!ep_validate_set_type(child, type)) 2093 return B_BAD_VALUE; 2094 2095 // if the old type is the same, there is nothing to do 2096 if (child->type && !strcmp(type, child->type)) 2097 return B_OK; 2098 2099 PartitionType ptype; 2100 ptype.SetType(type); 2101 // this is impossible 2102 if (!ptype.IsValid() || ptype.IsEmpty() || ptype.IsExtended()) 2103 return false; 2104 2105 // setting type to the partition 2106 update_disk_device_job_progress(job, 0.0); 2107 uint8 oldType = logical->Type(); 2108 logical->SetType(ptype.Type()); 2109 2110 PartitionMapWriter writer(fd, partition->block_size); 2111 // TODO: The partition is not supposed to be locked here! 2112 status_t error = writer.WriteLogical(logical, primary, false); 2113 if (error != B_OK) { 2114 // something went wrong - putting into previous state 2115 logical->SetType(oldType); 2116 return error; 2117 } 2118 2119 free(child->type); 2120 child->type = strdup(type); 2121 if (!child->type) 2122 return B_NO_MEMORY; 2123 2124 // all changes applied 2125 update_disk_device_job_progress(job, 1.0); 2126 partition_modified(partitionID); 2127 return B_OK; 2128 } 2129 2130 2131 // ep_initialize 2132 status_t 2133 ep_initialize(int fd, partition_id partitionID, const char* name, 2134 const char* parameters, off_t partitionSize, disk_job_id job) 2135 { 2136 TRACE(("intel: ep_initialize\n")); 2137 2138 if (fd < 0) 2139 return B_ERROR; 2140 2141 PartitionWriteLocker locker(partitionID); 2142 if (!locker.IsLocked()) 2143 return B_ERROR; 2144 2145 // get partition 2146 partition_data* partition = get_partition(partitionID); 2147 if (!partition) 2148 return B_BAD_VALUE; 2149 2150 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2151 if (!primary) 2152 return B_BAD_VALUE; 2153 2154 // name is ignored - we cannot set it to the Intel Extended Partition 2155 // TODO: The parameter has already been checked and must not be altered! 2156 if (!ep_validate_initialize(partition, NULL, parameters)) 2157 return B_BAD_VALUE; 2158 2159 // partition init (we have no child partition) 2160 update_disk_device_job_progress(job, 0.0); 2161 // fill in the partition_data structure 2162 partition->status = B_PARTITION_VALID; 2163 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 2164 partition->content_size = partition->size; 2165 // (no content_name and content_parameters) 2166 // (content_type is set by the system) 2167 partition->content_cookie = primary; 2168 2169 // we delete code area in EBR - nothing should be there 2170 partition_table table; 2171 table.clear_code_area(); 2172 2173 PartitionMapWriter writer(fd, partition->block_size); 2174 // TODO: The partition is not supposed to be locked here! 2175 status_t error = writer.ClearExtendedHead(primary); 2176 if (error != B_OK) 2177 return error; 2178 2179 // all changes applied 2180 update_disk_device_job_progress(job, 1.0); 2181 partition_modified(partitionID); 2182 return B_OK; 2183 } 2184 2185 2186 // ep_create_child 2187 /*! 2188 childID is used for the return value, but is also an optional input 2189 parameter -- -1 to be ignored 2190 */ 2191 status_t 2192 ep_create_child(int fd, partition_id partitionID, off_t offset, off_t size, 2193 const char* type, const char* name, const char* parameters, disk_job_id job, 2194 partition_id* childID) 2195 { 2196 TRACE(("intel: ep_create_child\n")); 2197 2198 if (fd < 0 || !childID) 2199 return B_BAD_VALUE; 2200 2201 // aquire lock 2202 PartitionWriteLocker locker(partitionID); 2203 if (!locker.IsLocked()) 2204 return B_ERROR; 2205 2206 // get partition data 2207 partition_data* partition = get_partition(partitionID); 2208 partition_data* parent = get_parent_partition(partitionID); 2209 if (partition == NULL || parent == NULL) 2210 return B_BAD_VALUE; 2211 2212 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2213 if (!primary) 2214 return B_BAD_VALUE; 2215 2216 // parse parameters 2217 void* handle = parse_driver_settings_string(parameters); 2218 if (handle == NULL) 2219 return B_ERROR; 2220 2221 bool active = get_driver_boolean_parameter(handle, "active", false, true); 2222 2223 off_t ptsOffset = 0; 2224 const char* buffer = get_driver_parameter( 2225 handle, "partition_table_offset", NULL, NULL); 2226 if (buffer != NULL) 2227 ptsOffset = strtoull(buffer, NULL, 10); 2228 else { 2229 delete_driver_settings(handle); 2230 return B_BAD_VALUE; 2231 } 2232 delete_driver_settings(handle); 2233 2234 // check the partition location 2235 if (!check_partition_location_ep(partition, offset, size, ptsOffset)) 2236 return B_BAD_VALUE; 2237 2238 // creating partition 2239 update_disk_device_job_progress(job, 0.0); 2240 partition_data* child = create_child_partition(partition->id, 2241 partition->child_count, offset, size, *childID); 2242 if (!child) 2243 return B_ERROR; 2244 2245 // setup logical partition 2246 LogicalPartition* logical = new(nothrow) LogicalPartition; 2247 if (!logical) 2248 return B_NO_MEMORY; 2249 2250 PartitionType ptype; 2251 ptype.SetType(type); 2252 logical->SetPartitionTableOffset(ptsOffset - parent->offset); 2253 logical->SetOffset(offset); 2254 logical->SetSize(size); 2255 logical->SetType(ptype.Type()); 2256 logical->SetActive(active); 2257 logical->SetPrimaryPartition(primary); 2258 logical->SetBlockSize(partition->block_size); 2259 primary->AddLogicalPartition(logical); 2260 2261 int parentFD = open_partition(parent->id, O_RDWR); 2262 if (parentFD < 0) { 2263 primary->RemoveLogicalPartition(logical); 2264 delete logical; 2265 return B_IO_ERROR; 2266 } 2267 2268 // write changes to disk 2269 PartitionMapWriter writer(parentFD, primary->BlockSize()); 2270 2271 // Write the logical partition's EBR first in case of failure. 2272 // This way we will not add a partition to the previous logical 2273 // partition. If there is no previous logical partition then write 2274 // the current partition's EBR to the first sector of the primary partition 2275 status_t error = writer.WriteLogical(logical, primary, true); 2276 if (error != B_OK) { 2277 primary->RemoveLogicalPartition(logical); 2278 delete logical; 2279 return error; 2280 } 2281 2282 LogicalPartition* previous = logical->Previous(); 2283 if (previous != NULL) { 2284 error = writer.WriteLogical(previous, primary, true); 2285 if (error != B_OK) { 2286 primary->RemoveLogicalPartition(logical); 2287 delete logical; 2288 return error; 2289 } 2290 } 2291 *childID = child->id; 2292 2293 child->block_size = logical->BlockSize(); 2294 child->type = strdup(type); 2295 child->parameters = strdup(parameters); 2296 child->cookie = logical; 2297 // check for allocation problems 2298 if (!child->type || !child->parameters) 2299 error = B_NO_MEMORY; 2300 2301 // all changes applied 2302 update_disk_device_job_progress(job, 1.0); 2303 partition_modified(partitionID); 2304 return B_OK; 2305 } 2306 2307 2308 // ep_delete_child 2309 status_t 2310 ep_delete_child(int fd, partition_id partitionID, partition_id childID, 2311 disk_job_id job) 2312 { 2313 TRACE(("intel: ep_delete_child\n")); 2314 2315 if (fd < 0) 2316 return B_ERROR; 2317 2318 PartitionWriteLocker locker(partitionID); 2319 if (!locker.IsLocked()) 2320 return B_ERROR; 2321 2322 partition_data* partition = get_partition(partitionID); 2323 partition_data* parent = get_parent_partition(partitionID); 2324 partition_data* child = get_partition(childID); 2325 if (partition == NULL || parent == NULL || child == NULL) 2326 return B_BAD_VALUE; 2327 2328 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 2329 LogicalPartition* logical = (LogicalPartition*)child->cookie; 2330 if (primary == NULL || logical == NULL) 2331 return B_BAD_VALUE; 2332 2333 // deleting child 2334 update_disk_device_job_progress(job, 0.0); 2335 if (!delete_partition(childID)) 2336 return B_ERROR; 2337 2338 LogicalPartition* previous = logical->Previous(); 2339 LogicalPartition* next = logical->Next(); 2340 2341 primary->RemoveLogicalPartition(logical); 2342 delete logical; 2343 2344 int parentFD = open_partition(parent->id, O_RDWR); 2345 if (parentFD < 0) 2346 return B_IO_ERROR; 2347 2348 // write changes to disk 2349 PartitionMapWriter writer(parentFD, primary->BlockSize()); 2350 2351 status_t error; 2352 if (previous != NULL) { 2353 error = writer.WriteLogical(previous, primary, true); 2354 } else { 2355 error = writer.WriteExtendedHead(next, primary, true); 2356 2357 if (next != NULL) { 2358 next->SetPartitionTableOffset(primary->Offset()); 2359 2360 partition_data* nextSibling = NULL; 2361 if (get_partition_from_offset_ep(partition, next->Offset(), 2362 &nextSibling)) { 2363 char buffer[128]; 2364 sprintf(buffer, "active %s ;\npartition_table_offset %" B_PRId64 2365 " ;\n", next->Active() ? "true" : "false", 2366 next->PartitionTableOffset()); 2367 nextSibling->parameters = strdup(buffer); 2368 } 2369 } 2370 } 2371 2372 close(parentFD); 2373 2374 if (error != B_OK) 2375 return error; 2376 2377 // all changes applied 2378 update_disk_device_job_progress(job, 1.0); 2379 partition_modified(partitionID); 2380 return B_OK; 2381 } 2382 2383