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