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