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