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 47static off_t 48block_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 64static status_t 65efi_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 77static float 78efi_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 102static status_t 103efi_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 157static void 158efi_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 164static void 165efi_gpt_free_partition_content_cookie(partition_data* partition) 166{ 167 delete (EFI::Header*)partition->content_cookie; 168} 169 170 171#ifndef _BOOT_MODE 172static uint32 173efi_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 187static uint32 188efi_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 198static bool 199efi_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 206static bool 207efi_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 241static bool 242efi_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 280static bool 281efi_gpt_validate_move(partition_data* partition, off_t* start) 282{ 283 // nothing to do 284 return true; 285} 286 287 288static bool 289efi_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 331static bool 332efi_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 342static bool 343efi_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 350static bool 351efi_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 366static bool 367efi_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 427static status_t 428efi_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 436static status_t 437efi_gpt_get_next_supported_type(partition_data* partition, int32* cookie, 438 char* type) 439{ 440 // TODO: implement 441 return B_ERROR; 442} 443 444 445static status_t 446efi_gpt_shadow_changed(partition_data* partition, partition_data* child, 447 uint32 operation) 448{ 449 // TODO: implement 450 return B_ERROR; 451} 452 453 454static status_t 455efi_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 462static status_t 463efi_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 491static status_t 492efi_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 544static status_t 545efi_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 552static status_t 553efi_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 613static status_t 614efi_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 659static status_t 660efi_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 707static status_t 708efi_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 740static status_t 741efi_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 779static status_t 780efi_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 853static status_t 854efi_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 901static partition_module_info sEFIPartitionModule = { 902#else 903partition_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 978partition_module_info* modules[] = { 979 &sEFIPartitionModule, 980 NULL 981}; 982#endif 983