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