1 /* 2 * Copyright 2009, Michael Lotz, mmlr@mlotz.ch. All rights reserved. 3 * Copyright 2007-2013, Axel Dörfler, axeld@pinc-software.de. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "gpt.h" 10 11 #include <KernelExport.h> 12 #include <disk_device_manager/ddm_modules.h> 13 #include <disk_device_types.h> 14 #ifdef _BOOT_MODE 15 # include <boot/partitions.h> 16 #else 17 # include <DiskDeviceTypes.h> 18 # include "PartitionLocker.h" 19 #endif 20 #include <util/kernel_cpp.h> 21 22 #include <errno.h> 23 #include <unistd.h> 24 #include <stdio.h> 25 #include <string.h> 26 27 #ifndef _BOOT_MODE 28 #include "uuid.h" 29 #endif 30 31 #include "Header.h" 32 #include "utility.h" 33 34 35 #define TRACE_EFI_GPT 36 #ifdef TRACE_EFI_GPT 37 # define TRACE(x) dprintf x 38 #else 39 # define TRACE(x) ; 40 #endif 41 42 43 #define EFI_PARTITION_MODULE_NAME "partitioning_systems/efi_gpt/v1" 44 45 46 #ifndef _BOOT_MODE 47 static off_t 48 block_align(partition_data* partition, off_t offset, bool upwards) 49 { 50 // Take HDs into account that hide the fact they are using a 51 // block size of 4096 bytes, and round to that. 52 uint32 blockSize = max_c(partition->block_size, 4096); 53 if (upwards) 54 return ((offset + blockSize - 1) / blockSize) * blockSize; 55 56 return (offset / blockSize) * blockSize; 57 } 58 #endif // !_BOOT_MODE 59 60 61 // #pragma mark - public module interface 62 63 64 static status_t 65 efi_gpt_std_ops(int32 op, ...) 66 { 67 switch (op) { 68 case B_MODULE_INIT: 69 case B_MODULE_UNINIT: 70 return B_OK; 71 } 72 73 return B_ERROR; 74 } 75 76 77 static float 78 efi_gpt_identify_partition(int fd, partition_data* partition, void** _cookie) 79 { 80 EFI::Header* header = new (std::nothrow) EFI::Header(fd, 81 (partition->size - 1) / partition->block_size, partition->block_size); 82 status_t status = header->InitCheck(); 83 if (status != B_OK) { 84 delete header; 85 return -1; 86 } 87 88 *_cookie = header; 89 if (header->IsDirty()) { 90 // Either the main or the backup table is missing, it looks like someone 91 // tried to erase the GPT with something else. Let's lower the priority, 92 // so that other partitioning systems which use either only the start or 93 // only the end of the drive, have a chance to run instead. 94 return 0.75; 95 } 96 return 0.96; 97 // This must be higher as Intel partitioning, as EFI can contain this 98 // partitioning for compatibility 99 } 100 101 102 static status_t 103 efi_gpt_scan_partition(int fd, partition_data* partition, void* _cookie) 104 { 105 TRACE(("efi_gpt_scan_partition(cookie = %p)\n", _cookie)); 106 EFI::Header* header = (EFI::Header*)_cookie; 107 108 partition->status = B_PARTITION_VALID; 109 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 110 partition->content_size = partition->size; 111 partition->content_cookie = header; 112 113 // scan all children 114 115 uint32 index = 0; 116 117 for (uint32 i = 0; i < header->EntryCount(); i++) { 118 const gpt_partition_entry& entry = header->EntryAt(i); 119 120 if (entry.partition_type == kEmptyGUID) 121 continue; 122 123 if (entry.EndBlock() * partition->block_size 124 > (uint64)partition->size) { 125 TRACE(("efi_gpt: child partition exceeds existing space (ends at " 126 "block %" B_PRIu64 ")\n", entry.EndBlock())); 127 continue; 128 } 129 130 if (entry.StartBlock() * partition->block_size == 0) { 131 TRACE(("efi_gpt: child partition starts at 0 (recursive entry)\n")); 132 continue; 133 } 134 135 partition_data* child = create_child_partition(partition->id, index++, 136 partition->offset + entry.StartBlock() * partition->block_size, 137 entry.BlockCount() * partition->block_size, -1); 138 if (child == NULL) { 139 TRACE(("efi_gpt: Creating child at index %" B_PRIu32 " failed\n", 140 index - 1)); 141 return B_ERROR; 142 } 143 144 char name[B_OS_NAME_LENGTH]; 145 to_utf8(entry.name, EFI_PARTITION_NAME_LENGTH, name, sizeof(name)); 146 child->name = strdup(name); 147 child->type = strdup(get_partition_type(entry.partition_type)); 148 child->block_size = partition->block_size; 149 child->cookie = (void*)(addr_t)i; 150 child->content_cookie = header; 151 } 152 153 return B_OK; 154 } 155 156 157 static void 158 efi_gpt_free_identify_partition_cookie(partition_data* partition, void* _cookie) 159 { 160 // Cookie is freed in efi_gpt_free_partition_content_cookie(). 161 } 162 163 164 static void 165 efi_gpt_free_partition_content_cookie(partition_data* partition) 166 { 167 delete (EFI::Header*)partition->content_cookie; 168 } 169 170 171 #ifndef _BOOT_MODE 172 static uint32 173 efi_gpt_get_supported_operations(partition_data* partition, uint32 mask) 174 { 175 uint32 flags = B_DISK_SYSTEM_SUPPORTS_INITIALIZING 176 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 177 | B_DISK_SYSTEM_SUPPORTS_MOVING 178 | B_DISK_SYSTEM_SUPPORTS_RESIZING 179 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD; 180 // TODO: check for available entries and partitionable space and only 181 // add creating child support if both is valid 182 183 return flags; 184 } 185 186 187 static uint32 188 efi_gpt_get_supported_child_operations(partition_data* partition, 189 partition_data* child, uint32 mask) 190 { 191 return B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 192 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 193 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 194 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD; 195 } 196 197 198 static bool 199 efi_gpt_is_sub_system_for(partition_data* partition) 200 { 201 // a GUID Partition Table doesn't usually live inside another partition 202 return false; 203 } 204 205 206 static bool 207 efi_gpt_validate_resize(partition_data* partition, off_t* size) 208 { 209 off_t newSize = *size; 210 if (newSize == partition->size) 211 return true; 212 213 if (newSize < 0) 214 newSize = 0; 215 else 216 newSize = block_align(partition, newSize, false); 217 218 // growing 219 if (newSize > partition->size) { 220 *size = newSize; 221 return true; 222 } 223 224 // shrinking, only so that no child would be truncated 225 off_t newEnd = partition->offset + newSize; 226 for (int32 i = 0; i < partition->child_count; i++) { 227 partition_data* child = get_child_partition(partition->id, i); 228 if (child == NULL) 229 continue; 230 231 if (child->offset + child->size > newEnd) 232 newEnd = child->offset + child->size; 233 } 234 235 newSize = block_align(partition, newEnd - partition->offset, true); 236 *size = newSize; 237 return true; 238 } 239 240 241 static bool 242 efi_gpt_validate_resize_child(partition_data* partition, partition_data* child, 243 off_t* size) 244 { 245 off_t newSize = *size; 246 if (newSize == child->size) 247 return true; 248 249 // shrinking 250 if (newSize < child->size) { 251 if (newSize < 0) 252 newSize = 0; 253 254 *size = block_align(partition, newSize, false); 255 return true; 256 } 257 258 // growing, but only so much that the child doesn't get bigger than 259 // the parent 260 if (child->offset + newSize > partition->offset + partition->size) 261 newSize = partition->offset + partition->size - child->offset; 262 263 // make sure that the child doesn't overlap any sibling partitions 264 off_t newEnd = child->offset + newSize; 265 for (int32 i = 0; i < partition->child_count; i++) { 266 partition_data* other = get_child_partition(partition->id, i); 267 if (other == NULL || other->id == child->id 268 || other->offset < child->offset) 269 continue; 270 271 if (newEnd > other->offset) 272 newEnd = other->offset; 273 } 274 275 *size = block_align(partition, newEnd - child->offset, false); 276 return true; 277 } 278 279 280 static bool 281 efi_gpt_validate_move(partition_data* partition, off_t* start) 282 { 283 // nothing to do 284 return true; 285 } 286 287 288 static bool 289 efi_gpt_validate_move_child(partition_data* partition, partition_data* child, 290 off_t* start) 291 { 292 off_t newStart = *start; 293 if (newStart < 0) 294 newStart = 0; 295 296 if (newStart + child->size > partition->size) 297 newStart = partition->size - child->size; 298 299 newStart = block_align(partition, newStart, false); 300 if (newStart > child->offset) { 301 for (int32 i = 0; i < partition->child_count; i++) { 302 partition_data* other = get_child_partition(partition->id, i); 303 if (other == NULL || other->id == child->id 304 || other->offset < child->offset) 305 continue; 306 307 if (other->offset < newStart + child->size) 308 newStart = other->offset - child->size; 309 } 310 311 newStart = block_align(partition, newStart, false); 312 } else { 313 for (int32 i = 0; i < partition->child_count; i++) { 314 partition_data* other = get_child_partition(partition->id, i); 315 if (other == NULL || other->id == child->id 316 || other->offset > child->offset) 317 continue; 318 319 if (other->offset + other->size > newStart) 320 newStart = other->offset + other->size; 321 } 322 323 newStart = block_align(partition, newStart, true); 324 } 325 326 *start = newStart; 327 return true; 328 } 329 330 331 static bool 332 efi_gpt_validate_set_name(partition_data* partition, char* name) 333 { 334 // TODO: should validate that the utf-8 -> ucs-2 is valid 335 // TODO: should count actual utf-8 chars 336 if (strlen(name) > EFI_PARTITION_NAME_LENGTH) 337 name[EFI_PARTITION_NAME_LENGTH - 1] = 0; 338 return true; 339 } 340 341 342 static bool 343 efi_gpt_validate_set_type(partition_data* partition, const char* type) 344 { 345 guid_t typeGUID; 346 return get_guid_for_partition_type(type, typeGUID); 347 } 348 349 350 static bool 351 efi_gpt_validate_initialize(partition_data* partition, char* name, 352 const char* parameters) 353 { 354 if ((efi_gpt_get_supported_operations(partition, ~0) 355 & B_DISK_SYSTEM_SUPPORTS_INITIALIZING) == 0) 356 return false; 357 358 // name and parameters are ignored 359 if (name != NULL) 360 name[0] = 0; 361 362 return true; 363 } 364 365 366 static bool 367 efi_gpt_validate_create_child(partition_data* partition, off_t* start, 368 off_t* size, const char* type, const char* name, const char* parameters, 369 int32* index) 370 { 371 if ((efi_gpt_get_supported_operations(partition, ~0) 372 & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) == 0) 373 return false; 374 375 if (!efi_gpt_validate_set_type(partition, type)) 376 return false; 377 378 EFI::Header* header = (EFI::Header*)partition->content_cookie; 379 int32 entryIndex = -1; 380 for (uint32 i = 0; i < header->EntryCount(); i++) { 381 const gpt_partition_entry& entry = header->EntryAt(i); 382 if (entry.partition_type == kEmptyGUID) { 383 entryIndex = i; 384 break; 385 } 386 } 387 388 if (entryIndex < 0) 389 return false; 390 391 *index = entryIndex; 392 393 // ensure that child lies between first and last usable block 394 off_t firstUsable = header->FirstUsableBlock() * partition->block_size; 395 if (*start < firstUsable) 396 *start = firstUsable; 397 398 off_t lastUsable = header->LastUsableBlock() * partition->block_size; 399 if (*start + *size > lastUsable) { 400 if (*start > lastUsable) 401 return false; 402 403 *size = lastUsable - *start; 404 } 405 406 // ensure that we don't overlap any siblings 407 for (int32 i = 0; i < partition->child_count; i++) { 408 partition_data* other = get_child_partition(partition->id, i); 409 if (other == NULL) 410 continue; 411 412 if (other->offset < *start && other->offset + other->size > *start) 413 *start = other->offset + other->size; 414 415 if (other->offset > *start && other->offset < *start + *size) 416 *size = other->offset - *start; 417 } 418 419 *start = block_align(partition, *start, true); 420 *size = block_align(partition, *size, false); 421 422 // TODO: support parameters 423 return true; 424 } 425 426 427 static status_t 428 efi_gpt_get_partitionable_spaces(partition_data* partition, 429 partitionable_space_data* buffer, int32 count, int32* actualCount) 430 { 431 // TODO: implement 432 return B_ERROR; 433 } 434 435 436 static status_t 437 efi_gpt_get_next_supported_type(partition_data* partition, int32* cookie, 438 char* type) 439 { 440 // TODO: implement 441 return B_ERROR; 442 } 443 444 445 static status_t 446 efi_gpt_shadow_changed(partition_data* partition, partition_data* child, 447 uint32 operation) 448 { 449 // TODO: implement 450 return B_ERROR; 451 } 452 453 454 static status_t 455 efi_gpt_repair(int fd, partition_id partition, bool checkOnly, disk_job_id job) 456 { 457 // TODO: implement, validate CRCs and restore from backup area if corrupt 458 return B_ERROR; 459 } 460 461 462 static status_t 463 efi_gpt_resize(int fd, partition_id partitionID, off_t size, disk_job_id job) 464 { 465 if (fd < 0) 466 return B_ERROR; 467 468 PartitionWriteLocker locker(partitionID); 469 if (!locker.IsLocked()) 470 return B_ERROR; 471 472 partition_data* partition = get_partition(partitionID); 473 if (partition == NULL) 474 return B_BAD_VALUE; 475 476 off_t validatedSize = size; 477 if (!efi_gpt_validate_resize(partition, &validatedSize)) 478 return B_BAD_VALUE; 479 480 update_disk_device_job_progress(job, 0.0); 481 482 partition->size = validatedSize; 483 partition->content_size = validatedSize; 484 485 update_disk_device_job_progress(job, 1.0); 486 partition_modified(partitionID); 487 return B_OK; 488 } 489 490 491 static status_t 492 efi_gpt_resize_child(int fd, partition_id partitionID, off_t size, 493 disk_job_id job) 494 { 495 if (fd < 0) 496 return B_ERROR; 497 498 PartitionWriteLocker locker(partitionID); 499 if (!locker.IsLocked()) 500 return B_ERROR; 501 502 partition_data* child = get_partition(partitionID); 503 if (child == NULL) 504 return B_BAD_VALUE; 505 506 partition_data* partition = get_parent_partition(partitionID); 507 if (partition == NULL) 508 return B_BAD_VALUE; 509 510 EFI::Header* header = (EFI::Header*)partition->content_cookie; 511 if (header == NULL) 512 return B_BAD_VALUE; 513 514 uint32 entryIndex = (uint32)(addr_t)child->cookie; 515 if (entryIndex >= header->EntryCount()) 516 return B_BAD_VALUE; 517 518 off_t validatedSize = size; 519 if (!efi_gpt_validate_resize_child(partition, child, &validatedSize)) 520 return B_BAD_VALUE; 521 522 if (child->size == validatedSize) 523 return B_OK; 524 525 update_disk_device_job_progress(job, 0.0); 526 527 gpt_partition_entry& entry = header->EntryAt(entryIndex); 528 entry.SetBlockCount(validatedSize / partition->block_size); 529 530 status_t result = header->WriteEntry(fd, entryIndex); 531 if (result != B_OK) { 532 entry.SetBlockCount(child->size / partition->block_size); 533 return result; 534 } 535 536 child->size = validatedSize; 537 538 update_disk_device_job_progress(job, 1.0); 539 partition_modified(partitionID); 540 return B_OK; 541 } 542 543 544 static status_t 545 efi_gpt_move(int fd, partition_id partition, off_t offset, disk_job_id job) 546 { 547 // nothing to do here 548 return B_OK; 549 } 550 551 552 static status_t 553 efi_gpt_move_child(int fd, partition_id partitionID, partition_id childID, 554 off_t offset, disk_job_id job) 555 { 556 if (fd < 0) 557 return B_ERROR; 558 559 PartitionWriteLocker locker(partitionID); 560 if (!locker.IsLocked()) 561 return B_ERROR; 562 563 partition_data* partition = get_partition(partitionID); 564 if (partition == NULL) 565 return B_BAD_VALUE; 566 567 partition_data* child = get_partition(childID); 568 if (child == NULL) 569 return B_BAD_VALUE; 570 571 EFI::Header* header = (EFI::Header*)partition->content_cookie; 572 if (header == NULL) 573 return B_BAD_VALUE; 574 575 uint32 entryIndex = (uint32)(addr_t)child->cookie; 576 if (entryIndex >= header->EntryCount()) 577 return B_BAD_VALUE; 578 579 off_t validatedOffset = offset; 580 if (!efi_gpt_validate_move_child(partition, child, &validatedOffset)) 581 return B_BAD_VALUE; 582 583 if (child->offset == validatedOffset) 584 return B_OK; 585 586 // TODO: implement actual moving, need to move the partition content 587 // (the raw data) here and need to take overlap into account 588 return B_ERROR; 589 590 update_disk_device_job_progress(job, 0.0); 591 592 gpt_partition_entry& entry = header->EntryAt(entryIndex); 593 uint64 blockCount = entry.BlockCount(); 594 entry.SetStartBlock((validatedOffset - partition->offset) 595 / partition->block_size); 596 entry.SetBlockCount(blockCount); 597 598 status_t result = header->WriteEntry(fd, entryIndex); 599 if (result != B_OK) { 600 // fatal error: the data has been moved but the partition table could 601 // not be updated to reflect that change! 602 return result; 603 } 604 605 child->offset = validatedOffset; 606 607 update_disk_device_job_progress(job, 1.0); 608 partition_modified(childID); 609 return B_OK; 610 } 611 612 613 static status_t 614 efi_gpt_set_name(int fd, partition_id partitionID, const char* name, 615 disk_job_id job) 616 { 617 if (fd < 0) 618 return B_ERROR; 619 620 PartitionWriteLocker locker(partitionID); 621 if (!locker.IsLocked()) 622 return B_ERROR; 623 624 partition_data* child = get_partition(partitionID); 625 if (child == NULL) 626 return B_BAD_VALUE; 627 628 partition_data* partition = get_parent_partition(partitionID); 629 if (partition == NULL) 630 return B_BAD_VALUE; 631 632 EFI::Header* header = (EFI::Header*)partition->content_cookie; 633 if (header == NULL) 634 return B_BAD_VALUE; 635 636 uint32 entryIndex = (uint32)(addr_t)child->cookie; 637 if (entryIndex >= header->EntryCount()) 638 return B_BAD_VALUE; 639 640 update_disk_device_job_progress(job, 0.0); 641 642 gpt_partition_entry& entry = header->EntryAt(entryIndex); 643 to_ucs2(name, strlen(name), entry.name, EFI_PARTITION_NAME_LENGTH); 644 645 status_t result = header->WriteEntry(fd, entryIndex); 646 if (result != B_OK) 647 return result; 648 649 char newName[B_OS_NAME_LENGTH]; 650 to_utf8(entry.name, EFI_PARTITION_NAME_LENGTH, newName, sizeof(newName)); 651 child->name = strdup(newName); 652 653 update_disk_device_job_progress(job, 1.0); 654 partition_modified(partitionID); 655 return B_OK; 656 } 657 658 659 static status_t 660 efi_gpt_set_type(int fd, partition_id partitionID, const char* type, 661 disk_job_id job) 662 { 663 if (fd < 0) 664 return B_ERROR; 665 666 PartitionWriteLocker locker(partitionID); 667 if (!locker.IsLocked()) 668 return B_ERROR; 669 670 partition_data* child = get_partition(partitionID); 671 if (child == NULL) 672 return B_BAD_VALUE; 673 674 partition_data* partition = get_parent_partition(partitionID); 675 if (partition == NULL) 676 return B_BAD_VALUE; 677 678 EFI::Header* header = (EFI::Header*)partition->content_cookie; 679 if (header == NULL) 680 return B_BAD_VALUE; 681 682 uint32 entryIndex = (uint32)(addr_t)child->cookie; 683 if (entryIndex >= header->EntryCount()) 684 return B_BAD_VALUE; 685 686 guid_t typeGUID; 687 if (!get_guid_for_partition_type(type, typeGUID)) 688 return B_BAD_VALUE; 689 690 update_disk_device_job_progress(job, 0.0); 691 692 gpt_partition_entry& entry = header->EntryAt(entryIndex); 693 entry.partition_type = typeGUID; 694 695 status_t result = header->WriteEntry(fd, entryIndex); 696 if (result != B_OK) 697 return result; 698 699 child->type = strdup(type); 700 701 update_disk_device_job_progress(job, 1.0); 702 partition_modified(partitionID); 703 return B_OK; 704 } 705 706 707 static status_t 708 efi_gpt_initialize(int fd, partition_id partitionID, const char* name, 709 const char* parameters, off_t partitionSize, disk_job_id job) 710 { 711 if (fd < 0) 712 return B_ERROR; 713 714 partition_data* partition = get_partition(partitionID); 715 if (partition == NULL) 716 return B_BAD_VALUE; 717 718 update_disk_device_job_progress(job, 0.0); 719 720 EFI::Header header((partitionSize - 1) / partition->block_size, 721 partition->block_size); 722 status_t result = header.InitCheck(); 723 if (result != B_OK) 724 return result; 725 726 result = header.Write(fd); 727 if (result != B_OK) 728 return result; 729 730 result = scan_partition(partitionID); 731 if (result != B_OK) 732 return result; 733 734 update_disk_device_job_progress(job, 1.0); 735 partition_modified(partitionID); 736 return B_OK; 737 } 738 739 740 static status_t 741 efi_gpt_uninitialize(int fd, partition_id partitionID, off_t partitionSize, 742 uint32 blockSize, disk_job_id job) 743 { 744 if (fd < 0) 745 return B_ERROR; 746 747 partition_data* partition = get_partition(partitionID); 748 if (partition == NULL) 749 return B_BAD_VALUE; 750 751 update_disk_device_job_progress(job, 0.0); 752 753 const int headerSize = partition->block_size * 3; 754 // The first block is the protective MBR 755 // The second block is the GPT header 756 // The third block is the start of the partition list (it can span more 757 // blocks, but that doesn't matter as soon as the header is erased). 758 759 uint8 buffer[headerSize]; 760 memset(buffer, 0xE5, sizeof(buffer)); 761 762 // Erase the first blocks 763 if (write_pos(fd, 0, &buffer, headerSize) < 0) 764 return errno; 765 766 // Erase the last blocks 767 // Only 2 blocks, as there is no protective MBR 768 if (write_pos(fd, partitionSize - 2 * partition->block_size, 769 &buffer, 2 * partition->block_size) < 0) { 770 return errno; 771 } 772 773 update_disk_device_job_progress(job, 1.0); 774 775 return B_OK; 776 } 777 778 779 static status_t 780 efi_gpt_create_child(int fd, partition_id partitionID, off_t offset, 781 off_t size, const char* type, const char* name, const char* parameters, 782 disk_job_id job, partition_id* childID) 783 { 784 if (fd < 0) 785 return B_ERROR; 786 787 PartitionWriteLocker locker(partitionID); 788 if (!locker.IsLocked()) 789 return B_ERROR; 790 791 partition_data* partition = get_partition(partitionID); 792 if (partition == NULL) 793 return B_BAD_VALUE; 794 795 EFI::Header* header = (EFI::Header*)partition->content_cookie; 796 if (header == NULL) 797 return B_BAD_VALUE; 798 799 off_t validatedOffset = offset; 800 off_t validatedSize = size; 801 uint32 entryIndex = 0; 802 803 if (!efi_gpt_validate_create_child(partition, &validatedOffset, 804 &validatedSize, type, name, parameters, (int32*)&entryIndex)) 805 return B_BAD_VALUE; 806 807 guid_t typeGUID; 808 if (!get_guid_for_partition_type(type, typeGUID)) 809 return B_BAD_VALUE; 810 811 update_disk_device_job_progress(job, 0.0); 812 813 partition_data* child = create_child_partition(partition->id, entryIndex, 814 validatedOffset, validatedSize, *childID); 815 if (child == NULL) 816 return B_ERROR; 817 818 gpt_partition_entry& entry = header->EntryAt(entryIndex); 819 entry.partition_type = typeGUID; 820 uuid_t uuid; 821 uuid_generate_random(uuid); 822 memcpy((uint8*)&entry.unique_guid, uuid, sizeof(guid_t)); 823 to_ucs2(name, strlen(name), entry.name, EFI_PARTITION_NAME_LENGTH); 824 entry.SetStartBlock((validatedOffset - partition->offset) 825 / partition->block_size); 826 entry.SetBlockCount(validatedSize / partition->block_size); 827 entry.SetAttributes(0); // TODO 828 829 status_t result = header->WriteEntry(fd, entryIndex); 830 if (result != B_OK) { 831 delete_partition(child->id); 832 return result; 833 } 834 835 *childID = child->id; 836 child->block_size = partition->block_size; 837 child->name = strdup(name); 838 child->type = strdup(type); 839 child->parameters = strdup(parameters); 840 child->cookie = (void*)(addr_t)entryIndex; 841 842 if (child->type == NULL || child->parameters == NULL) { 843 delete_partition(child->id); 844 return B_NO_MEMORY; 845 } 846 847 update_disk_device_job_progress(job, 1.0); 848 partition_modified(partitionID); 849 return B_OK; 850 } 851 852 853 static status_t 854 efi_gpt_delete_child(int fd, partition_id partitionID, partition_id childID, 855 disk_job_id job) 856 { 857 if (fd < 0) 858 return B_ERROR; 859 860 PartitionWriteLocker locker(partitionID); 861 if (!locker.IsLocked()) 862 return B_ERROR; 863 864 partition_data* partition = get_partition(partitionID); 865 if (partition == NULL) 866 return B_BAD_VALUE; 867 868 partition_data* child = get_partition(childID); 869 if (child == NULL) 870 return B_BAD_VALUE; 871 872 EFI::Header* header = (EFI::Header*)partition->content_cookie; 873 if (header == NULL) 874 return B_BAD_VALUE; 875 876 uint32 entryIndex = (uint32)(addr_t)child->cookie; 877 if (entryIndex >= header->EntryCount()) 878 return B_BAD_VALUE; 879 880 update_disk_device_job_progress(job, 0.0); 881 882 if (!delete_partition(childID)) 883 return B_ERROR; 884 885 gpt_partition_entry& entry = header->EntryAt(entryIndex); 886 memset(&entry, 0, sizeof(gpt_partition_entry)); 887 entry.partition_type = kEmptyGUID; 888 889 status_t result = header->WriteEntry(fd, entryIndex); 890 if (result != B_OK) 891 return result; 892 893 update_disk_device_job_progress(job, 1.0); 894 partition_modified(partitionID); 895 return B_OK; 896 } 897 #endif // !_BOOT_MODE 898 899 900 #ifndef _BOOT_MODE 901 static partition_module_info sEFIPartitionModule = { 902 #else 903 partition_module_info gEFIPartitionModule = { 904 #endif 905 { 906 EFI_PARTITION_MODULE_NAME, 907 0, 908 efi_gpt_std_ops 909 }, 910 "gpt", // short_name 911 EFI_PARTITION_NAME, // pretty_name 912 0 // flags 913 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 914 | B_DISK_SYSTEM_SUPPORTS_MOVING 915 | B_DISK_SYSTEM_SUPPORTS_RESIZING 916 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 917 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 918 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 919 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 920 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 921 | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 922 | B_DISK_SYSTEM_SUPPORTS_NAME 923 , 924 925 // scanning 926 efi_gpt_identify_partition, 927 efi_gpt_scan_partition, 928 efi_gpt_free_identify_partition_cookie, 929 NULL, // free_partition_cookie 930 efi_gpt_free_partition_content_cookie, 931 932 #ifndef _BOOT_MODE 933 // querying 934 efi_gpt_get_supported_operations, 935 efi_gpt_get_supported_child_operations, 936 NULL, // supports_initializing_child 937 efi_gpt_is_sub_system_for, 938 939 efi_gpt_validate_resize, 940 efi_gpt_validate_resize_child, 941 efi_gpt_validate_move, 942 efi_gpt_validate_move_child, 943 efi_gpt_validate_set_name, 944 NULL, // validate_set_content_name 945 efi_gpt_validate_set_type, 946 NULL, // validate_set_parameters 947 NULL, // validate_set_content_parameters 948 efi_gpt_validate_initialize, 949 efi_gpt_validate_create_child, 950 efi_gpt_get_partitionable_spaces, 951 efi_gpt_get_next_supported_type, 952 NULL, // get_type_for_content_type 953 954 // shadow partition modification 955 efi_gpt_shadow_changed, 956 957 // writing 958 efi_gpt_repair, 959 efi_gpt_resize, 960 efi_gpt_resize_child, 961 efi_gpt_move, 962 efi_gpt_move_child, 963 efi_gpt_set_name, 964 NULL, // set_content_name 965 efi_gpt_set_type, 966 NULL, // set_parameters 967 NULL, // set_content_parameters 968 efi_gpt_initialize, 969 efi_gpt_uninitialize, 970 efi_gpt_create_child, 971 efi_gpt_delete_child 972 #else 973 NULL 974 #endif // _BOOT_MODE 975 }; 976 977 #ifndef _BOOT_MODE 978 partition_module_info* modules[] = { 979 &sEFIPartitionModule, 980 NULL 981 }; 982 #endif 983