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