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