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