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