1 /* 2 libparted - a library for manipulating disk partitions 3 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2007 4 Free Software Foundation, Inc. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 /** \file disk.c */ 21 22 /** 23 * \addtogroup PedDisk 24 * 25 * \brief Disk label access. 26 * 27 * Most programs will need to use ped_disk_new() or ped_disk_new_fresh() to get 28 * anything done. A PedDisk is always associated with a device and has a 29 * partition table. There are different types of partition tables (or disk 30 * labels). These are represented by the PedDiskType enumeration. 31 * 32 * @{ 33 */ 34 35 #include <config.h> 36 37 #include <parted/parted.h> 38 #include <parted/debug.h> 39 40 #if ENABLE_NLS 41 # include <libintl.h> 42 # define _(String) dgettext (PACKAGE, String) 43 # define N_(String) (String) 44 #else 45 # define _(String) (String) 46 # define N_(String) (String) 47 #endif /* ENABLE_NLS */ 48 49 /* UPDATE MODE functions */ 50 #ifdef DEBUG 51 static int _disk_check_sanity (PedDisk* disk); 52 #endif 53 static void _disk_push_update_mode (PedDisk* disk); 54 static void _disk_pop_update_mode (PedDisk* disk); 55 static int _disk_raw_insert_before (PedDisk* disk, PedPartition* loc, 56 PedPartition* part); 57 static int _disk_raw_insert_after (PedDisk* disk, PedPartition* loc, 58 PedPartition* part); 59 static int _disk_raw_remove (PedDisk* disk, PedPartition* part); 60 static int _disk_raw_add (PedDisk* disk, PedPartition* part); 61 62 static PedDiskType* disk_types = NULL; 63 64 void 65 ped_disk_type_register (PedDiskType* disk_type) 66 { 67 PED_ASSERT (disk_type != NULL, return); 68 PED_ASSERT (disk_type->ops != NULL, return); 69 PED_ASSERT (disk_type->name != NULL, return); 70 71 /* pretend that "next" isn't part of the struct :-) */ 72 ((struct _PedDiskType*) disk_type)->next = disk_types; 73 disk_types = (struct _PedDiskType*) disk_type; 74 } 75 76 void 77 ped_disk_type_unregister (PedDiskType* disk_type) 78 { 79 PedDiskType* walk; 80 PedDiskType* last = NULL; 81 82 PED_ASSERT (disk_types != NULL, return); 83 PED_ASSERT (disk_type != NULL, return); 84 85 for (walk = disk_types; walk && walk != disk_type; 86 last = walk, walk = walk->next); 87 88 PED_ASSERT (walk != NULL, return); 89 if (last) 90 ((struct _PedDiskType*) last)->next = disk_type->next; 91 else 92 disk_types = disk_type->next; 93 } 94 95 /** 96 * Deprecated: use ped_disk_type_regiser. 97 */ 98 void 99 ped_register_disk_type (PedDiskType* disk_type) 100 { 101 ped_disk_type_register (disk_type); 102 } 103 104 /** 105 * Deprecated: use ped_disk_type_unregiser. 106 */ 107 void 108 ped_unregister_disk_type (PedDiskType* disk_type) 109 { 110 ped_disk_type_unregister (disk_type); 111 } 112 113 /** 114 * Return the next disk type registers, after "type". If "type" is 115 * NULL, returns the first disk type. 116 * 117 * \return Next disk; NULL if "type" is the last registered disk type. 118 */ 119 PedDiskType* 120 ped_disk_type_get_next (PedDiskType* type) 121 { 122 if (type) 123 return type->next; 124 else 125 return disk_types; 126 } 127 128 /** 129 * Return the disk type with a name of "name". 130 * 131 * \return Disk type; NULL if no match. 132 */ 133 PedDiskType* 134 ped_disk_type_get (const char* name) 135 { 136 PedDiskType* walk = NULL; 137 138 PED_ASSERT (name != NULL, return NULL); 139 140 for (walk = ped_disk_type_get_next (NULL); walk; 141 walk = ped_disk_type_get_next (walk)) 142 if (strcasecmp (walk->name, name) == 0) 143 break; 144 145 return walk; 146 } 147 148 /** 149 * Return the type of partition table detected on "dev". 150 * 151 * \return Type; NULL if none was detected. 152 */ 153 PedDiskType* 154 ped_disk_probe (PedDevice* dev) 155 { 156 PedDiskType *walk = NULL; 157 158 PED_ASSERT (dev != NULL, return NULL); 159 160 if (!ped_device_open (dev)) 161 return NULL; 162 163 ped_exception_fetch_all (); 164 for (walk = ped_disk_type_get_next (NULL); walk; 165 walk = ped_disk_type_get_next (walk)) { 166 if (walk->ops->probe (dev)) 167 break; 168 } 169 170 if (ped_exception) 171 ped_exception_catch (); 172 ped_exception_leave_all (); 173 174 ped_device_close (dev); 175 return walk; 176 } 177 178 /** 179 * Read the partition table off a device (if one is found). 180 * 181 * \warning May modify \p dev->cylinders, \p dev->heads and \p dev->sectors 182 * if the partition table indicates that the existing values 183 * are incorrect. 184 * 185 * \return A new \link _PedDisk PedDisk \endlink object; 186 * NULL on failure (e.g. partition table not detected). 187 */ 188 PedDisk* 189 ped_disk_new (PedDevice* dev) 190 { 191 PedDiskType* type; 192 PedDisk* disk; 193 194 PED_ASSERT (dev != NULL, return NULL); 195 196 if (!ped_device_open (dev)) 197 goto error; 198 199 type = ped_disk_probe (dev); 200 if (!type) { 201 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 202 _("%s: unrecognised disk label"), 203 dev->path); 204 goto error_close_dev; 205 } 206 disk = ped_disk_new_fresh (dev, type); 207 if (!disk) 208 goto error_close_dev; 209 if (!type->ops->read (disk)) 210 goto error_destroy_disk; 211 disk->needs_clobber = 0; 212 ped_device_close (dev); 213 return disk; 214 215 error_destroy_disk: 216 ped_disk_destroy (disk); 217 error_close_dev: 218 ped_device_close (dev); 219 error: 220 return NULL; 221 } 222 223 static int 224 _add_duplicate_part (PedDisk* disk, PedPartition* old_part) 225 { 226 PedPartition* new_part; 227 PedConstraint* constraint_exact; 228 229 new_part = disk->type->ops->partition_duplicate (old_part); 230 if (!new_part) 231 goto error; 232 new_part->disk = disk; 233 234 constraint_exact = ped_constraint_exact (&new_part->geom); 235 if (!constraint_exact) 236 goto error_destroy_new_part; 237 if (!ped_disk_add_partition (disk, new_part, constraint_exact)) 238 goto error_destroy_constraint_exact; 239 ped_constraint_destroy (constraint_exact); 240 return 1; 241 242 error_destroy_constraint_exact: 243 ped_constraint_destroy (constraint_exact); 244 error_destroy_new_part: 245 ped_partition_destroy (new_part); 246 error: 247 return 0; 248 } 249 250 /** 251 * Clone a \link _PedDisk PedDisk \endlink object. 252 * 253 * \return Deep copy of \p old_disk, NULL on failure. 254 */ 255 PedDisk* 256 ped_disk_duplicate (const PedDisk* old_disk) 257 { 258 PedDisk* new_disk; 259 PedPartition* old_part; 260 261 PED_ASSERT (old_disk != NULL, return NULL); 262 PED_ASSERT (!old_disk->update_mode, return NULL); 263 PED_ASSERT (old_disk->type->ops->duplicate != NULL, return NULL); 264 PED_ASSERT (old_disk->type->ops->partition_duplicate != NULL, 265 return NULL); 266 267 new_disk = old_disk->type->ops->duplicate (old_disk); 268 if (!new_disk) 269 goto error; 270 271 _disk_push_update_mode (new_disk); 272 for (old_part = ped_disk_next_partition (old_disk, NULL); old_part; 273 old_part = ped_disk_next_partition (old_disk, old_part)) { 274 if (ped_partition_is_active (old_part)) { 275 if (!_add_duplicate_part (new_disk, old_part)) 276 goto error_destroy_new_disk; 277 } 278 } 279 _disk_pop_update_mode (new_disk); 280 return new_disk; 281 282 error_destroy_new_disk: 283 ped_disk_destroy (new_disk); 284 error: 285 return NULL; 286 } 287 288 /** 289 * Remove all identifying signatures of a partition table, 290 * except for partition tables of a given type. 291 * 292 * \return 0 on error, 1 otherwise. 293 * 294 * \sa ped_disk_clobber() 295 */ 296 int 297 ped_disk_clobber_exclude (PedDevice* dev, const PedDiskType* exclude) 298 { 299 PedDiskType* walk; 300 301 PED_ASSERT (dev != NULL, goto error); 302 303 if (!ped_device_open (dev)) 304 goto error; 305 306 for (walk = ped_disk_type_get_next (NULL); walk; 307 walk = ped_disk_type_get_next (walk)) { 308 int probed; 309 310 if (walk == exclude) 311 continue; 312 313 ped_exception_fetch_all (); 314 probed = walk->ops->probe (dev); 315 if (!probed) 316 ped_exception_catch (); 317 ped_exception_leave_all (); 318 319 if (probed && walk->ops->clobber) { 320 if (!walk->ops->clobber (dev)) 321 goto error_close_dev; 322 } 323 } 324 ped_device_close (dev); 325 return 1; 326 327 error_close_dev: 328 ped_device_close (dev); 329 error: 330 return 0; 331 } 332 333 /** 334 * Remove all identifying signatures of a partition table, 335 * 336 * \return 0 on error, 1 otherwise. 337 * 338 * \sa ped_disk_clobber_exclude() 339 */ 340 int 341 ped_disk_clobber (PedDevice* dev) 342 { 343 return ped_disk_clobber_exclude (dev, NULL); 344 } 345 346 /** 347 * Create a new partition table on \p dev. 348 * 349 * This new partition table is only created in-memory, and nothing is written 350 * to disk until ped_disk_commit_to_dev() is called. 351 * 352 * \return The newly constructed \link _PedDisk PedDisk \endlink, 353 * NULL on failure. 354 */ 355 PedDisk* 356 ped_disk_new_fresh (PedDevice* dev, const PedDiskType* type) 357 { 358 PedDisk* disk; 359 360 PED_ASSERT (dev != NULL, return NULL); 361 PED_ASSERT (type != NULL, return NULL); 362 PED_ASSERT (type->ops->alloc != NULL, return NULL); 363 364 disk = type->ops->alloc (dev); 365 if (!disk) 366 goto error; 367 _disk_pop_update_mode (disk); 368 PED_ASSERT (disk->update_mode == 0, goto error_destroy_disk); 369 370 disk->needs_clobber = 1; 371 return disk; 372 373 error_destroy_disk: 374 ped_disk_destroy (disk); 375 error: 376 return NULL; 377 } 378 379 PedDisk* 380 _ped_disk_alloc (const PedDevice* dev, const PedDiskType* disk_type) 381 { 382 PedDisk* disk; 383 384 disk = (PedDisk*) ped_malloc (sizeof (PedDisk)); 385 if (!disk) 386 goto error; 387 388 disk->dev = (PedDevice*)dev; 389 disk->type = disk_type; 390 disk->update_mode = 1; 391 disk->part_list = NULL; 392 return disk; 393 394 ped_free (disk); 395 error: 396 return NULL; 397 } 398 399 void 400 _ped_disk_free (PedDisk* disk) 401 { 402 _disk_push_update_mode (disk); 403 ped_disk_delete_all (disk); 404 ped_free (disk); 405 } 406 407 /** 408 * Close \p disk. 409 * 410 * What this function does depends on the PedDiskType of \p disk, 411 * but you can generally assume that outstanding writes are flushed 412 * (this mainly means that _ped_disk_free is called). 413 */ 414 void 415 ped_disk_destroy (PedDisk* disk) 416 { 417 PED_ASSERT (disk != NULL, return); 418 PED_ASSERT (!disk->update_mode, return); 419 420 disk->type->ops->free (disk); 421 } 422 423 /** 424 * Tell the operating system kernel about the partition table layout 425 * of \p disk. 426 * 427 * This is rather loosely defined: for example, on old versions of Linux, 428 * it simply calls the BLKRRPART ioctl, which tells the kernel to 429 * reread the partition table. On newer versions (2.4.x), it will 430 * use the new blkpg interface to tell Linux where each partition 431 * starts/ends, etc. In this case, Linux does not need to have support for 432 * a specific type of partition table. 433 * 434 * \return 0 on failure, 1 otherwise. 435 */ 436 int 437 ped_disk_commit_to_os (PedDisk* disk) 438 { 439 PED_ASSERT (disk != NULL, return 0); 440 441 if (!ped_device_open (disk->dev)) 442 goto error; 443 if (!ped_architecture->disk_ops->disk_commit (disk)) 444 goto error_close_dev; 445 ped_device_close (disk->dev); 446 return 1; 447 448 error_close_dev: 449 ped_device_close (disk->dev); 450 error: 451 return 0; 452 } 453 454 /** 455 * Write the changes made to the in-memory description 456 * of a partition table to the device. 457 * 458 * \return 0 on failure, 1 otherwise. 459 */ 460 int 461 ped_disk_commit_to_dev (PedDisk* disk) 462 { 463 PED_ASSERT (disk != NULL, goto error); 464 PED_ASSERT (!disk->update_mode, goto error); 465 466 if (!disk->type->ops->write) { 467 ped_exception_throw ( 468 PED_EXCEPTION_ERROR, 469 PED_EXCEPTION_CANCEL, 470 _("This libparted doesn't have write support for " 471 "%s. Perhaps it was compiled read-only."), 472 disk->type->name); 473 goto error; 474 } 475 476 if (!ped_device_open (disk->dev)) 477 goto error; 478 479 if (disk->needs_clobber) { 480 if (!ped_disk_clobber_exclude (disk->dev, disk->type)) 481 goto error_close_dev; 482 disk->needs_clobber = 0; 483 } 484 if (!disk->type->ops->write (disk)) 485 goto error_close_dev; 486 ped_device_close (disk->dev); 487 return 1; 488 489 error_close_dev: 490 ped_device_close (disk->dev); 491 error: 492 return 0; 493 } 494 495 /* 496 * This function writes the in-memory changes to a partition table to 497 * disk and informs the operating system of the changes. 498 * 499 * \note Equivalent to calling first ped_disk_commit_to_dev(), then 500 * ped_disk_commit_to_os(). 501 * 502 * \return 0 on failure, 1 otherwise. 503 */ 504 int 505 ped_disk_commit (PedDisk* disk) 506 { 507 if (!ped_disk_commit_to_dev (disk)) 508 return 0; 509 return ped_disk_commit_to_os (disk); 510 } 511 512 /** 513 * \addtogroup PedPartition 514 * 515 * @{ 516 */ 517 518 /** 519 * Check whether a partition is mounted or busy in some 520 * other way. 521 * 522 * \note An extended partition is busy if any logical partitions are mounted. 523 * 524 * \return \c 1 if busy. 525 */ 526 int 527 ped_partition_is_busy (const PedPartition* part) 528 { 529 PED_ASSERT (part != NULL, return 1); 530 531 return ped_architecture->disk_ops->partition_is_busy (part); 532 } 533 534 /** 535 * Return a path that can be used to address the partition in the 536 * operating system. 537 */ 538 char* 539 ped_partition_get_path (const PedPartition* part) 540 { 541 PED_ASSERT (part != NULL, return NULL); 542 543 return ped_architecture->disk_ops->partition_get_path (part); 544 } 545 546 /** @} */ 547 548 /** 549 * \addtogroup PedDisk 550 * 551 * @{ 552 */ 553 554 /** 555 * Perform a sanity check on a partition table. 556 * 557 * \note The check performed is generic (i.e. it does not depends on the label 558 * type of the disk. 559 * 560 * \throws PED_EXCEPTION_WARNING if a partition type ID does not match the file 561 * system on it. 562 * 563 * \return 0 if the check fails, 1 otherwise. 564 */ 565 int 566 ped_disk_check (const PedDisk* disk) 567 { 568 PedPartition* walk; 569 570 PED_ASSERT (disk != NULL, return 0); 571 572 for (walk = disk->part_list; walk; 573 walk = ped_disk_next_partition (disk, walk)) { 574 const PedFileSystemType* fs_type = walk->fs_type; 575 PedGeometry* geom; 576 PedSector length_error; 577 PedSector max_length_error; 578 579 if (!ped_partition_is_active (walk) || !fs_type) 580 continue; 581 582 geom = ped_file_system_probe_specific (fs_type, &walk->geom); 583 if (!geom) 584 continue; 585 586 length_error = abs (walk->geom.length - geom->length); 587 max_length_error = PED_MAX (4096, walk->geom.length / 100); 588 if (!ped_geometry_test_inside (&walk->geom, geom) 589 || length_error > max_length_error) { 590 char* part_size = ped_unit_format (disk->dev, walk->geom.length); 591 char* fs_size = ped_unit_format (disk->dev, geom->length); 592 PedExceptionOption choice; 593 594 choice = ped_exception_throw ( 595 PED_EXCEPTION_WARNING, 596 PED_EXCEPTION_IGNORE_CANCEL, 597 _("Partition %d is %s, but the file system is " 598 "%s."), 599 walk->num, part_size, fs_size); 600 601 ped_free (part_size); 602 ped_free (fs_size); 603 604 if (choice != PED_EXCEPTION_IGNORE) 605 return 0; 606 } 607 } 608 609 return 1; 610 } 611 612 /** 613 * This function checks if a particular type of partition table supports 614 * a feature. 615 * 616 * \return 1 if \p disk_type supports \p feature, 0 otherwise. 617 */ 618 int 619 ped_disk_type_check_feature (const PedDiskType* disk_type, 620 PedDiskTypeFeature feature) 621 { 622 return (disk_type->features & feature) != 0; 623 } 624 625 /** 626 * Get the number of primary partitions. 627 */ 628 int 629 ped_disk_get_primary_partition_count (const PedDisk* disk) 630 { 631 PedPartition* walk; 632 int count = 0; 633 634 PED_ASSERT (disk != NULL, return 0); 635 636 for (walk = disk->part_list; walk; 637 walk = ped_disk_next_partition (disk, walk)) { 638 if (ped_partition_is_active (walk) 639 && ! (walk->type & PED_PARTITION_LOGICAL)) 640 count++; 641 } 642 643 return count; 644 } 645 646 /** 647 * Get the highest partition number on \p disk. 648 */ 649 int 650 ped_disk_get_last_partition_num (const PedDisk* disk) 651 { 652 PedPartition* walk; 653 int highest = -1; 654 655 PED_ASSERT (disk != NULL, return 0); 656 657 for (walk = disk->part_list; walk; 658 walk = ped_disk_next_partition (disk, walk)) { 659 if (walk->num > highest) 660 highest = walk->num; 661 } 662 663 return highest; 664 } 665 666 /** 667 * Get the maximum number of (primary) partitions the disk label supports. 668 * 669 * For example, MacIntosh partition maps can have different sizes, 670 * and accordingly support a different number of partitions. 671 */ 672 int 673 ped_disk_get_max_primary_partition_count (const PedDisk* disk) 674 { 675 PED_ASSERT (disk->type != NULL, return 0); 676 PED_ASSERT (disk->type->ops->get_max_primary_partition_count != NULL, 677 return 0); 678 679 return disk->type->ops->get_max_primary_partition_count (disk); 680 } 681 682 /** 683 * \internal We turned a really nasty bureaucracy problem into an elegant maths 684 * problem :-) Basically, there are some constraints to a partition's 685 * geometry: 686 * 687 * (1) it must start and end on a "disk" block, determined by the disk label 688 * (not the hardware). (constraint represented by a PedAlignment) 689 * 690 * (2) if we're resizing a partition, we MIGHT need to keep each block aligned. 691 * Eg: if an ext2 file system has 4k blocks, then we can only move the start 692 * by a multiple of 4k. (constraint represented by a PedAlignment) 693 * 694 * (3) we need to keep the start and end within the device's physical 695 * boundaries. (constraint represented by a PedGeometry) 696 * 697 * Satisfying (1) and (2) simultaneously required a bit of fancy maths ;-) See 698 * ped_alignment_intersect() 699 * 700 * The application of these constraints is in disk_*.c's *_partition_align() 701 * function. 702 */ 703 static int 704 _partition_align (PedPartition* part, const PedConstraint* constraint) 705 { 706 const PedDiskType* disk_type; 707 708 PED_ASSERT (part != NULL, return 0); 709 PED_ASSERT (part->num != -1, return 0); 710 PED_ASSERT (part->disk != NULL, return 0); 711 disk_type = part->disk->type; 712 PED_ASSERT (disk_type != NULL, return 0); 713 PED_ASSERT (disk_type->ops->partition_align != NULL, return 0); 714 PED_ASSERT (part->disk->update_mode, return 0); 715 716 return disk_type->ops->partition_align (part, constraint); 717 } 718 719 static int 720 _partition_enumerate (PedPartition* part) 721 { 722 const PedDiskType* disk_type; 723 724 PED_ASSERT (part != NULL, return 0); 725 PED_ASSERT (part->disk != NULL, return 0); 726 disk_type = part->disk->type; 727 PED_ASSERT (disk_type != NULL, return 0); 728 PED_ASSERT (disk_type->ops->partition_enumerate != NULL, return 0); 729 730 return disk_type->ops->partition_enumerate (part); 731 } 732 733 /** 734 * Gives all the (active) partitions a number. It should preserve the numbers 735 * and orders as much as possible. 736 */ 737 static int 738 ped_disk_enumerate_partitions (PedDisk* disk) 739 { 740 PedPartition* walk; 741 int i; 742 int end; 743 744 PED_ASSERT (disk != NULL, return 0); 745 746 /* first "sort" already-numbered partitions. (e.g. if a logical partition 747 * is removed, then all logical partitions that were number higher MUST be 748 * renumbered) 749 */ 750 end = ped_disk_get_last_partition_num (disk); 751 for (i=1; i<=end; i++) { 752 walk = ped_disk_get_partition (disk, i); 753 if (walk) { 754 if (!_partition_enumerate (walk)) 755 return 0; 756 } 757 } 758 759 /* now, number un-numbered partitions */ 760 for (walk = disk->part_list; walk; 761 walk = ped_disk_next_partition (disk, walk)) { 762 if (ped_partition_is_active (walk) && walk->num == -1) { 763 if (!_partition_enumerate (walk)) 764 return 0; 765 } 766 } 767 768 return 1; 769 } 770 771 static int 772 _disk_remove_metadata (PedDisk* disk) 773 { 774 PedPartition* walk = NULL; 775 PedPartition* next; 776 777 PED_ASSERT (disk != NULL, return 0); 778 779 next = ped_disk_next_partition (disk, walk); 780 781 while (next) { 782 walk = next; 783 while (1) { 784 next = ped_disk_next_partition (disk, next); 785 if (!next || next->type & PED_PARTITION_METADATA) 786 break; 787 } 788 if (walk->type & PED_PARTITION_METADATA) 789 ped_disk_delete_partition (disk, walk); 790 } 791 return 1; 792 } 793 794 static int 795 _disk_alloc_metadata (PedDisk* disk) 796 { 797 PED_ASSERT (disk != NULL, return 0); 798 799 if (!disk->update_mode) 800 _disk_remove_metadata (disk); 801 802 return disk->type->ops->alloc_metadata (disk); 803 } 804 805 static int 806 _disk_remove_freespace (PedDisk* disk) 807 { 808 PedPartition* walk; 809 PedPartition* next; 810 811 walk = ped_disk_next_partition (disk, NULL); 812 for (; walk; walk = next) { 813 next = ped_disk_next_partition (disk, walk); 814 815 if (walk->type & PED_PARTITION_FREESPACE) { 816 _disk_raw_remove (disk, walk); 817 ped_partition_destroy (walk); 818 } 819 } 820 821 return 1; 822 } 823 824 static int 825 _alloc_extended_freespace (PedDisk* disk) 826 { 827 PedSector last_end; 828 PedPartition* walk; 829 PedPartition* last; 830 PedPartition* free_space; 831 PedPartition* extended_part; 832 833 extended_part = ped_disk_extended_partition (disk); 834 if (!extended_part) 835 return 1; 836 837 last_end = extended_part->geom.start; 838 last = NULL; 839 840 for (walk = extended_part->part_list; walk; walk = walk->next) { 841 if (walk->geom.start > last_end + 1) { 842 free_space = ped_partition_new ( 843 disk, 844 PED_PARTITION_FREESPACE 845 | PED_PARTITION_LOGICAL, 846 NULL, 847 last_end + 1, walk->geom.start - 1); 848 _disk_raw_insert_before (disk, walk, free_space); 849 } 850 851 last = walk; 852 last_end = last->geom.end; 853 } 854 855 if (last_end < extended_part->geom.end) { 856 free_space = ped_partition_new ( 857 disk, 858 PED_PARTITION_FREESPACE | PED_PARTITION_LOGICAL, 859 NULL, 860 last_end + 1, extended_part->geom.end); 861 862 if (last) 863 return _disk_raw_insert_after (disk, last, free_space); 864 else 865 extended_part->part_list = free_space; 866 } 867 868 return 1; 869 } 870 871 static int 872 _disk_alloc_freespace (PedDisk* disk) 873 { 874 PedSector last_end; 875 PedPartition* walk; 876 PedPartition* last; 877 PedPartition* free_space; 878 879 if (!_disk_remove_freespace (disk)) 880 return 0; 881 if (!_alloc_extended_freespace (disk)) 882 return 0; 883 884 last = NULL; 885 last_end = -1; 886 887 for (walk = disk->part_list; walk; walk = walk->next) { 888 if (walk->geom.start > last_end + 1) { 889 free_space = ped_partition_new (disk, 890 PED_PARTITION_FREESPACE, NULL, 891 last_end + 1, walk->geom.start - 1); 892 _disk_raw_insert_before (disk, walk, free_space); 893 } 894 895 last = walk; 896 last_end = last->geom.end; 897 } 898 899 if (last_end < disk->dev->length - 1) { 900 free_space = ped_partition_new (disk, 901 PED_PARTITION_FREESPACE, NULL, 902 last_end + 1, disk->dev->length - 1); 903 if (last) 904 return _disk_raw_insert_after (disk, last, free_space); 905 else 906 disk->part_list = free_space; 907 } 908 909 return 1; 910 } 911 912 /** 913 * Update mode: used when updating the internal representation of the partition 914 * table. In update mode, the metadata and freespace placeholder/virtual 915 * partitions are removed, making it much easier for various manipulation 916 * routines... 917 */ 918 static void 919 _disk_push_update_mode (PedDisk* disk) 920 { 921 if (!disk->update_mode) { 922 #ifdef DEBUG 923 _disk_check_sanity (disk); 924 #endif 925 926 _disk_remove_freespace (disk); 927 disk->update_mode++; 928 _disk_remove_metadata (disk); 929 930 #ifdef DEBUG 931 _disk_check_sanity (disk); 932 #endif 933 } else { 934 disk->update_mode++; 935 } 936 } 937 938 static void 939 _disk_pop_update_mode (PedDisk* disk) 940 { 941 PED_ASSERT (disk->update_mode, return); 942 943 if (disk->update_mode == 1) { 944 /* re-allocate metadata BEFORE leaving update mode, to prevent infinite 945 * recursion (metadata allocation requires update mode) 946 */ 947 #ifdef DEBUG 948 _disk_check_sanity (disk); 949 #endif 950 951 _disk_alloc_metadata (disk); 952 disk->update_mode--; 953 _disk_alloc_freespace (disk); 954 955 #ifdef DEBUG 956 _disk_check_sanity (disk); 957 #endif 958 } else { 959 disk->update_mode--; 960 } 961 } 962 963 /** @} */ 964 965 /** 966 * \addtogroup PedPartition 967 * 968 * \brief Partition access. 969 * 970 * @{ 971 */ 972 973 PedPartition* 974 _ped_partition_alloc (const PedDisk* disk, PedPartitionType type, 975 const PedFileSystemType* fs_type, 976 PedSector start, PedSector end) 977 { 978 PedPartition* part; 979 980 PED_ASSERT (disk != NULL, return 0); 981 982 part = (PedPartition*) ped_malloc (sizeof (PedPartition)); 983 if (!part) 984 goto error; 985 986 part->prev = NULL; 987 part->next = NULL; 988 989 part->disk = (PedDisk*) disk; 990 if (!ped_geometry_init (&part->geom, disk->dev, start, end - start + 1)) 991 goto error_free_part; 992 993 part->num = -1; 994 part->type = type; 995 part->part_list = NULL; 996 part->fs_type = fs_type; 997 998 return part; 999 1000 error_free_part: 1001 ped_free (part); 1002 error: 1003 return NULL; 1004 } 1005 1006 void 1007 _ped_partition_free (PedPartition* part) 1008 { 1009 ped_free (part); 1010 } 1011 1012 int 1013 _ped_partition_attempt_align (PedPartition* part, 1014 const PedConstraint* external, 1015 PedConstraint* internal) 1016 { 1017 PedConstraint* intersection; 1018 PedGeometry* solution; 1019 1020 intersection = ped_constraint_intersect (external, internal); 1021 ped_constraint_destroy (internal); 1022 if (!intersection) 1023 goto fail; 1024 1025 solution = ped_constraint_solve_nearest (intersection, &part->geom); 1026 if (!solution) 1027 goto fail_free_intersection; 1028 ped_geometry_set (&part->geom, solution->start, solution->length); 1029 ped_geometry_destroy (solution); 1030 ped_constraint_destroy (intersection); 1031 return 1; 1032 1033 fail_free_intersection: 1034 ped_constraint_destroy (intersection); 1035 fail: 1036 return 0; 1037 } 1038 1039 /** 1040 * Create a new \link _PedPartition PedPartition \endlink on \p disk. 1041 * 1042 * \param type One of \p PED_PARTITION_NORMAL, \p PED_PARTITION_EXTENDED, 1043 * \p PED_PARTITION_LOGICAL. 1044 * 1045 * \note The constructed partition is not added to <tt>disk</tt>'s 1046 * partition table. Use ped_disk_add_partition() to do this. 1047 * 1048 * \return A new \link _PedPartition PedPartition \endlink object, 1049 * NULL on failure. 1050 * 1051 * \throws PED_EXCEPTION_ERROR if \p type is \p EXTENDED or \p LOGICAL but the 1052 * label does not support this concept. 1053 */ 1054 PedPartition* 1055 ped_partition_new (const PedDisk* disk, PedPartitionType type, 1056 const PedFileSystemType* fs_type, PedSector start, 1057 PedSector end) 1058 { 1059 int supports_extended; 1060 PedPartition* part; 1061 1062 PED_ASSERT (disk != NULL, return NULL); 1063 PED_ASSERT (disk->type->ops->partition_new != NULL, return NULL); 1064 1065 supports_extended = ped_disk_type_check_feature (disk->type, 1066 PED_DISK_TYPE_EXTENDED); 1067 1068 if (!supports_extended 1069 && (type == PED_PARTITION_EXTENDED 1070 || type == PED_PARTITION_LOGICAL)) { 1071 ped_exception_throw ( 1072 PED_EXCEPTION_ERROR, 1073 PED_EXCEPTION_CANCEL, 1074 _("%s disk labels do not support extended " 1075 "partitions."), 1076 disk->type->name); 1077 goto error; 1078 } 1079 1080 part = disk->type->ops->partition_new (disk, type, fs_type, start, end); 1081 if (!part) 1082 goto error; 1083 1084 if (fs_type || part->type == PED_PARTITION_EXTENDED) { 1085 if (!ped_partition_set_system (part, fs_type)) 1086 goto error_destroy_part; 1087 } 1088 return part; 1089 1090 error_destroy_part: 1091 ped_partition_destroy (part); 1092 error: 1093 return NULL; 1094 } 1095 1096 /** 1097 * Destroy a \link _PedPartition PedPartition \endlink object. 1098 * 1099 * \note Should not be called on a partition that is in a partition table. 1100 * Use ped_disk_delete_partition() instead. 1101 */ 1102 void 1103 ped_partition_destroy (PedPartition* part) 1104 { 1105 PED_ASSERT (part != NULL, return); 1106 PED_ASSERT (part->disk != NULL, return); 1107 PED_ASSERT (part->disk->type->ops->partition_new != NULL, return); 1108 1109 part->disk->type->ops->partition_destroy (part); 1110 } 1111 1112 1113 /** 1114 * Return whether or not the partition is "active". 1115 * 1116 * A partition is active if \p part->type is neither \p PED_PARTITION_METADATA 1117 * nor \p PED_PARTITION_FREE. 1118 */ 1119 int 1120 ped_partition_is_active (const PedPartition* part) 1121 { 1122 PED_ASSERT (part != NULL, return 0); 1123 1124 return !(part->type & PED_PARTITION_FREESPACE 1125 || part->type & PED_PARTITION_METADATA); 1126 } 1127 1128 /** 1129 * Set the state (\c 1 or \c 0) of a flag on a partition. 1130 * 1131 * Flags are disk label specific, although they have a global 1132 * "namespace": the flag PED_PARTITION_BOOT, for example, roughly means 1133 * "this" partition is bootable". But this means different things on different 1134 * disk labels (and may not be defined on some disk labels). For example, 1135 * on MS-DOS disk labels, there can only be one boot partition, and this 1136 * refers to the partition that will be booted from on startup. On PC98 1137 * disk labels, the user can choose from any bootable partition on startup. 1138 * 1139 * \note It is an error to call this on an unavailable flag -- use 1140 * ped_partition_is_flag_available() to determine which flags are available 1141 * for a given disk label. 1142 * 1143 * \throws PED_EXCEPTION_ERROR if the requested flag is not available for this 1144 * label. 1145 */ 1146 int 1147 ped_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state) 1148 { 1149 PedDiskOps* ops; 1150 1151 PED_ASSERT (part != NULL, return 0); 1152 PED_ASSERT (part->disk != NULL, return 0); 1153 PED_ASSERT (ped_partition_is_active (part), return 0); 1154 1155 ops = part->disk->type->ops; 1156 PED_ASSERT (ops->partition_set_flag != NULL, return 0); 1157 PED_ASSERT (ops->partition_is_flag_available != NULL, return 0); 1158 1159 if (!ops->partition_is_flag_available (part, flag)) { 1160 ped_exception_throw ( 1161 PED_EXCEPTION_ERROR, 1162 PED_EXCEPTION_CANCEL, 1163 "The flag '%s' is not available for %s disk labels.", 1164 ped_partition_flag_get_name (flag), 1165 part->disk->type->name); 1166 return 0; 1167 } 1168 1169 return ops->partition_set_flag (part, flag, state); 1170 } 1171 1172 /** 1173 * Get the state (\c 1 or \c 0) of a flag on a partition. 1174 * 1175 * See ped_partition_set_flag() for conditions that must hold. 1176 * 1177 * \todo Where's the check for flag availability? 1178 */ 1179 int 1180 ped_partition_get_flag (const PedPartition* part, PedPartitionFlag flag) 1181 { 1182 PED_ASSERT (part != NULL, return 0); 1183 PED_ASSERT (part->disk != NULL, return 0); 1184 PED_ASSERT (part->disk->type->ops->partition_get_flag != NULL, 1185 return 0); 1186 PED_ASSERT (ped_partition_is_active (part), return 0); 1187 1188 return part->disk->type->ops->partition_get_flag (part, flag); 1189 } 1190 1191 /** 1192 * Check whether a given flag is available on a partition. 1193 * 1194 * \return \c 1 if the flag is available. 1195 */ 1196 int 1197 ped_partition_is_flag_available (const PedPartition* part, 1198 PedPartitionFlag flag) 1199 { 1200 PED_ASSERT (part != NULL, return 0); 1201 PED_ASSERT (part->disk != NULL, return 0); 1202 PED_ASSERT (part->disk->type->ops->partition_is_flag_available != NULL, 1203 return 0); 1204 PED_ASSERT (ped_partition_is_active (part), return 0); 1205 1206 return part->disk->type->ops->partition_is_flag_available (part, flag); 1207 } 1208 1209 /** 1210 * Sets the system type on the partition to \p fs_type. 1211 * 1212 * \note The file system may be opened, to get more information about the 1213 * file system, e.g. to determine if it's FAT16 or FAT32. 1214 * 1215 * \return \c 0 on failure. 1216 */ 1217 int 1218 ped_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type) 1219 { 1220 const PedDiskType* disk_type; 1221 1222 PED_ASSERT (part != NULL, return 0); 1223 PED_ASSERT (ped_partition_is_active (part), return 0); 1224 PED_ASSERT (part->disk != NULL, return 0); 1225 disk_type = part->disk->type; 1226 PED_ASSERT (disk_type != NULL, return 0); 1227 PED_ASSERT (disk_type->ops != NULL, return 0); 1228 PED_ASSERT (disk_type->ops->partition_set_system != NULL, return 0); 1229 1230 return disk_type->ops->partition_set_system (part, fs_type); 1231 } 1232 1233 static int 1234 _assert_partition_name_feature (const PedDiskType* disk_type) 1235 { 1236 if (!ped_disk_type_check_feature ( 1237 disk_type, PED_DISK_TYPE_PARTITION_NAME)) { 1238 ped_exception_throw ( 1239 PED_EXCEPTION_ERROR, 1240 PED_EXCEPTION_CANCEL, 1241 "%s disk labels do not support partition names.", 1242 disk_type->name); 1243 return 0; 1244 } 1245 return 1; 1246 } 1247 1248 /** 1249 * Sets the name of a partition. 1250 * 1251 * \note This will only work if the disk label supports it. 1252 * You can use 1253 * \code 1254 * ped_disk_type_check_feature (part->disk->type, PED_DISK_TYPE_PARTITION_NAME); 1255 * \endcode 1256 * to check whether this feature is enabled for a label. 1257 * 1258 * \note \p name will not be modified by libparted. It can be freed 1259 * by the caller immediately after ped_partition_set_name() is called. 1260 * 1261 * \return \c 1 on success, \c 0 otherwise. 1262 */ 1263 int 1264 ped_partition_set_name (PedPartition* part, const char* name) 1265 { 1266 PED_ASSERT (part != NULL, return 0); 1267 PED_ASSERT (part->disk != NULL, return 0); 1268 PED_ASSERT (ped_partition_is_active (part), return 0); 1269 PED_ASSERT (name != NULL, return 0); 1270 1271 if (!_assert_partition_name_feature (part->disk->type)) 1272 return 0; 1273 1274 PED_ASSERT (part->disk->type->ops->partition_set_name != NULL, 1275 return 0); 1276 part->disk->type->ops->partition_set_name (part, name); 1277 return 1; 1278 } 1279 1280 /** 1281 * Returns the name of a partition \p part. This will only work if the disk 1282 * label supports it. 1283 * 1284 * \note The returned string should not be modified. It should 1285 * not be referenced after the partition is destroyed. 1286 */ 1287 const char* 1288 ped_partition_get_name (const PedPartition* part) 1289 { 1290 PED_ASSERT (part != NULL, return NULL); 1291 PED_ASSERT (part->disk != NULL, return 0); 1292 PED_ASSERT (ped_partition_is_active (part), return 0); 1293 1294 if (!_assert_partition_name_feature (part->disk->type)) 1295 return NULL; 1296 1297 PED_ASSERT (part->disk->type->ops->partition_get_name != NULL, 1298 return NULL); 1299 return part->disk->type->ops->partition_get_name (part); 1300 } 1301 1302 /** @} */ 1303 1304 /** 1305 * \addtogroup PedDisk 1306 * 1307 * @{ 1308 */ 1309 1310 PedPartition* 1311 ped_disk_extended_partition (const PedDisk* disk) 1312 { 1313 PedPartition* walk; 1314 1315 PED_ASSERT (disk != NULL, return 0); 1316 1317 for (walk = disk->part_list; walk; walk = walk->next) { 1318 if (walk->type == PED_PARTITION_EXTENDED) 1319 break; 1320 } 1321 return walk; 1322 } 1323 1324 /** 1325 * Return the next partition after \p part on \p disk. If \p part is \c NULL, 1326 * return the first partition. If \p part is the last partition, returns 1327 * \c NULL. If \p part is an extended partition, returns the first logical 1328 * partition. If this is called repeatedly passing the return value as \p part, 1329 * a depth-first traversal is executed. 1330 * 1331 * \return The next partition, \c NULL if no more partitions left. 1332 */ 1333 PedPartition* 1334 ped_disk_next_partition (const PedDisk* disk, const PedPartition* part) 1335 { 1336 PED_ASSERT (disk != NULL, return 0); 1337 1338 if (!part) 1339 return disk->part_list; 1340 if (part->type == PED_PARTITION_EXTENDED) 1341 return part->part_list ? part->part_list : part->next; 1342 if (part->next) 1343 return part->next; 1344 if (part->type & PED_PARTITION_LOGICAL) 1345 return ped_disk_extended_partition (disk)->next; 1346 return NULL; 1347 } 1348 1349 /** @} */ 1350 1351 #ifdef DEBUG 1352 static int 1353 _disk_check_sanity (PedDisk* disk) 1354 { 1355 PedPartition* walk; 1356 1357 PED_ASSERT (disk != NULL, return 0); 1358 1359 for (walk = disk->part_list; walk; walk = walk->next) { 1360 PED_ASSERT (!(walk->type & PED_PARTITION_LOGICAL), return 0); 1361 PED_ASSERT (!walk->prev || walk->prev->next == walk, return 0); 1362 } 1363 1364 if (!ped_disk_extended_partition (disk)) 1365 return 1; 1366 1367 for (walk = ped_disk_extended_partition (disk)->part_list; walk; 1368 walk = walk->next) { 1369 PED_ASSERT (walk->type & PED_PARTITION_LOGICAL, return 0); 1370 if (walk->prev) 1371 PED_ASSERT (walk->prev->next == walk, return 0); 1372 } 1373 return 1; 1374 } 1375 #endif 1376 1377 /** 1378 * Returns the partition numbered \p num. 1379 * 1380 * \return \c NULL if the specified partition does not exist. 1381 */ 1382 PedPartition* 1383 ped_disk_get_partition (const PedDisk* disk, int num) 1384 { 1385 PedPartition* walk; 1386 1387 PED_ASSERT (disk != NULL, return 0); 1388 1389 for (walk = disk->part_list; walk; 1390 walk = ped_disk_next_partition (disk, walk)) { 1391 if (walk->num == num && !(walk->type & PED_PARTITION_FREESPACE)) 1392 return walk; 1393 } 1394 1395 return NULL; 1396 } 1397 1398 /** 1399 * Returns the partition that contains sect. If sect lies within a logical 1400 * partition, then the logical partition is returned (not the extended 1401 * partition). 1402 */ 1403 PedPartition* 1404 ped_disk_get_partition_by_sector (const PedDisk* disk, PedSector sect) 1405 { 1406 PedPartition* walk; 1407 1408 PED_ASSERT (disk != NULL, return 0); 1409 1410 for (walk = disk->part_list; walk; 1411 walk = ped_disk_next_partition (disk, walk)) { 1412 if (ped_geometry_test_sector_inside (&walk->geom, sect) 1413 && walk->type != PED_PARTITION_EXTENDED) 1414 return walk; 1415 } 1416 1417 /* should never get here, unless sect is outside of disk's useable 1418 * part, or we're in "update mode", and the free space place-holders 1419 * have been removed with _disk_remove_freespace() 1420 */ 1421 return NULL; 1422 } 1423 1424 /* I'm beginning to agree with Sedgewick :-/ */ 1425 static int 1426 _disk_raw_insert_before (PedDisk* disk, PedPartition* loc, PedPartition* part) 1427 { 1428 PED_ASSERT (disk != NULL, return 0); 1429 PED_ASSERT (loc != NULL, return 0); 1430 PED_ASSERT (part != NULL, return 0); 1431 1432 part->prev = loc->prev; 1433 part->next = loc; 1434 if (part->prev) { 1435 part->prev->next = part; 1436 } else { 1437 if (loc->type & PED_PARTITION_LOGICAL) 1438 ped_disk_extended_partition (disk)->part_list = part; 1439 else 1440 disk->part_list = part; 1441 } 1442 loc->prev = part; 1443 1444 return 1; 1445 } 1446 1447 static int 1448 _disk_raw_insert_after (PedDisk* disk, PedPartition* loc, PedPartition* part) 1449 { 1450 PED_ASSERT (disk != NULL, return 0); 1451 PED_ASSERT (loc != NULL, return 0); 1452 PED_ASSERT (part != NULL, return 0); 1453 1454 part->prev = loc; 1455 part->next = loc->next; 1456 if (loc->next) 1457 loc->next->prev = part; 1458 loc->next = part; 1459 1460 return 1; 1461 } 1462 1463 static int 1464 _disk_raw_remove (PedDisk* disk, PedPartition* part) 1465 { 1466 PED_ASSERT (disk != NULL, return 0); 1467 PED_ASSERT (part != NULL, return 0); 1468 1469 if (part->prev) { 1470 part->prev->next = part->next; 1471 if (part->next) 1472 part->next->prev = part->prev; 1473 } else { 1474 if (part->type & PED_PARTITION_LOGICAL) { 1475 ped_disk_extended_partition (disk)->part_list 1476 = part->next; 1477 } else { 1478 disk->part_list = part->next; 1479 } 1480 if (part->next) 1481 part->next->prev = NULL; 1482 } 1483 1484 return 1; 1485 } 1486 1487 /* 1488 *UPDATE MODE ONLY 1489 */ 1490 static int 1491 _disk_raw_add (PedDisk* disk, PedPartition* part) 1492 { 1493 PedPartition* walk; 1494 PedPartition* last; 1495 PedPartition* ext_part; 1496 1497 PED_ASSERT (disk->update_mode, return 0); 1498 1499 ext_part = ped_disk_extended_partition (disk); 1500 1501 last = NULL; 1502 walk = (part->type & PED_PARTITION_LOGICAL) ? 1503 ext_part->part_list : disk->part_list; 1504 1505 for (; walk; last = walk, walk = walk->next) { 1506 if (walk->geom.start > part->geom.end) 1507 break; 1508 } 1509 1510 if (walk) { 1511 return _disk_raw_insert_before (disk, walk, part); 1512 } else { 1513 if (last) { 1514 return _disk_raw_insert_after (disk, last, part); 1515 } else { 1516 if (part->type & PED_PARTITION_LOGICAL) 1517 ext_part->part_list = part; 1518 else 1519 disk->part_list = part; 1520 } 1521 } 1522 1523 return 1; 1524 } 1525 1526 static PedConstraint* 1527 _partition_get_overlap_constraint (PedPartition* part, PedGeometry* geom) 1528 { 1529 PedSector min_start; 1530 PedSector max_end; 1531 PedPartition* walk; 1532 PedGeometry free_space; 1533 1534 PED_ASSERT (part->disk->update_mode, return NULL); 1535 PED_ASSERT (part->geom.dev == geom->dev, return NULL); 1536 1537 if (part->type & PED_PARTITION_LOGICAL) { 1538 PedPartition* ext_part; 1539 1540 ext_part = ped_disk_extended_partition (part->disk); 1541 PED_ASSERT (ext_part != NULL, return NULL); 1542 1543 min_start = ext_part->geom.start; 1544 max_end = ext_part->geom.end; 1545 walk = ext_part->part_list; 1546 } else { 1547 min_start = 0; 1548 max_end = part->disk->dev->length - 1; 1549 walk = part->disk->part_list; 1550 } 1551 1552 while (walk != NULL 1553 && (walk->geom.start < geom->start 1554 || min_start >= walk->geom.start)) { 1555 if (walk != part) 1556 min_start = walk->geom.end + 1; 1557 walk = walk->next; 1558 } 1559 1560 if (walk == part) 1561 walk = walk->next; 1562 1563 if (walk) 1564 max_end = walk->geom.start - 1; 1565 1566 if (min_start >= max_end) 1567 return NULL; 1568 1569 ped_geometry_init (&free_space, part->disk->dev, 1570 min_start, max_end - min_start + 1); 1571 return ped_constraint_new_from_max (&free_space); 1572 } 1573 1574 /* 1575 * Returns \c 0 if the partition, \p part overlaps with any partitions on the 1576 * \p disk. The geometry of \p part is taken to be \p geom, NOT \p part->geom 1577 * (the idea here is to check if \p geom is valid, before changing \p part). 1578 * 1579 * This is useful for seeing if a resized partitions new geometry is going to 1580 * fit, without the existing geomtry getting in the way. 1581 * 1582 * Note: overlap with an extended partition is also allowed, provided that 1583 * \p geom lies completely inside the extended partition. 1584 */ 1585 static int 1586 _disk_check_part_overlaps (PedDisk* disk, PedPartition* part) 1587 { 1588 PedPartition* walk; 1589 1590 PED_ASSERT (disk != NULL, return 0); 1591 PED_ASSERT (part != NULL, return 0); 1592 1593 for (walk = ped_disk_next_partition (disk, NULL); walk; 1594 walk = ped_disk_next_partition (disk, walk)) { 1595 if (walk->type & PED_PARTITION_FREESPACE) 1596 continue; 1597 if (walk == part) 1598 continue; 1599 if (part->type & PED_PARTITION_EXTENDED 1600 && walk->type & PED_PARTITION_LOGICAL) 1601 continue; 1602 1603 if (ped_geometry_test_overlap (&walk->geom, &part->geom)) { 1604 if (walk->type & PED_PARTITION_EXTENDED 1605 && part->type & PED_PARTITION_LOGICAL 1606 && ped_geometry_test_inside (&walk->geom, 1607 &part->geom)) 1608 continue; 1609 return 0; 1610 } 1611 } 1612 1613 return 1; 1614 } 1615 1616 static int 1617 _partition_check_basic_sanity (PedDisk* disk, PedPartition* part) 1618 { 1619 PedPartition* ext_part = ped_disk_extended_partition (disk); 1620 1621 PED_ASSERT (part->disk == disk, return 0); 1622 1623 PED_ASSERT (part->geom.start >= 0, return 0); 1624 PED_ASSERT (part->geom.end < disk->dev->length, return 0); 1625 PED_ASSERT (part->geom.start <= part->geom.end, return 0); 1626 1627 if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED) 1628 && (part->type == PED_PARTITION_EXTENDED 1629 || part->type == PED_PARTITION_LOGICAL)) { 1630 ped_exception_throw ( 1631 PED_EXCEPTION_ERROR, 1632 PED_EXCEPTION_CANCEL, 1633 _("%s disk labels don't support logical or extended " 1634 "partitions."), 1635 disk->type->name); 1636 return 0; 1637 } 1638 1639 if (ped_partition_is_active (part) 1640 && ! (part->type & PED_PARTITION_LOGICAL)) { 1641 if (ped_disk_get_primary_partition_count (disk) + 1 1642 > ped_disk_get_max_primary_partition_count (disk)) { 1643 ped_exception_throw ( 1644 PED_EXCEPTION_ERROR, 1645 PED_EXCEPTION_CANCEL, 1646 _("Too many primary partitions.")); 1647 return 0; 1648 } 1649 } 1650 1651 if ((part->type & PED_PARTITION_LOGICAL) && !ext_part) { 1652 ped_exception_throw ( 1653 PED_EXCEPTION_ERROR, 1654 PED_EXCEPTION_CANCEL, 1655 _("Can't add a logical partition to %s, because " 1656 "there is no extended partition."), 1657 disk->dev->path); 1658 return 0; 1659 } 1660 1661 return 1; 1662 } 1663 1664 static int 1665 _check_extended_partition (PedDisk* disk, PedPartition* part) 1666 { 1667 PedPartition* walk; 1668 PedPartition* ext_part; 1669 1670 PED_ASSERT (disk != NULL, return 0); 1671 ext_part = ped_disk_extended_partition (disk); 1672 if (!ext_part) ext_part = part; 1673 PED_ASSERT (ext_part != NULL, return 0); 1674 1675 if (part != ext_part) { 1676 ped_exception_throw ( 1677 PED_EXCEPTION_ERROR, 1678 PED_EXCEPTION_CANCEL, 1679 _("Can't have more than one extended partition on %s."), 1680 disk->dev->path); 1681 return 0; 1682 } 1683 1684 for (walk = ext_part->part_list; walk; walk = walk->next) { 1685 if (!ped_geometry_test_inside (&ext_part->geom, &walk->geom)) { 1686 ped_exception_throw ( 1687 PED_EXCEPTION_ERROR, 1688 PED_EXCEPTION_CANCEL, 1689 _("Can't have logical partitions outside of " 1690 "the extended partition.")); 1691 return 0; 1692 } 1693 } 1694 return 1; 1695 } 1696 1697 static int 1698 _check_partition (PedDisk* disk, PedPartition* part) 1699 { 1700 PedPartition* ext_part = ped_disk_extended_partition (disk); 1701 1702 PED_ASSERT (part->geom.start <= part->geom.end, return 0); 1703 1704 if (part->type == PED_PARTITION_EXTENDED) { 1705 if (!_check_extended_partition (disk, part)) 1706 return 0; 1707 } 1708 1709 if (part->type & PED_PARTITION_LOGICAL 1710 && !ped_geometry_test_inside (&ext_part->geom, &part->geom)) { 1711 ped_exception_throw ( 1712 PED_EXCEPTION_ERROR, 1713 PED_EXCEPTION_CANCEL, 1714 _("Can't have a logical partition outside of the " 1715 "extended partition on %s."), 1716 disk->dev->path); 1717 return 0; 1718 } 1719 1720 if (!_disk_check_part_overlaps (disk, part)) { 1721 ped_exception_throw ( 1722 PED_EXCEPTION_ERROR, 1723 PED_EXCEPTION_CANCEL, 1724 _("Can't have overlapping partitions.")); 1725 return 0; 1726 } 1727 1728 if (! (part->type & PED_PARTITION_LOGICAL) 1729 && ext_part && ext_part != part 1730 && ped_geometry_test_inside (&ext_part->geom, &part->geom)) { 1731 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, 1732 _("Can't have a primary partition inside an extended " 1733 "partition.")); 1734 return 0; 1735 } 1736 1737 return 1; 1738 } 1739 1740 /** 1741 * Adds PedPartition \p part to PedPartition \p disk. 1742 * 1743 * \warning The partition's geometry may be changed, subject to \p constraint. 1744 * You could set \p constraint to <tt>ped_constraint_exact(&part->geom)</tt>, 1745 * but many partition table schemes have special requirements on the start 1746 * and end of partitions. Therefore, having an overly strict constraint 1747 * will probably mean that this function will fail (in which 1748 * case \p part will be left unmodified) 1749 * \p part is assigned a number (\p part->num) in this process. 1750 * 1751 * \return \c 0 on failure. 1752 */ 1753 int 1754 ped_disk_add_partition (PedDisk* disk, PedPartition* part, 1755 const PedConstraint* constraint) 1756 { 1757 PedConstraint* overlap_constraint = NULL; 1758 PedConstraint* constraints = NULL; 1759 1760 PED_ASSERT (disk != NULL, return 0); 1761 PED_ASSERT (part != NULL, return 0); 1762 1763 if (!_partition_check_basic_sanity (disk, part)) 1764 return 0; 1765 1766 _disk_push_update_mode (disk); 1767 1768 if (ped_partition_is_active (part)) { 1769 overlap_constraint 1770 = _partition_get_overlap_constraint (part, &part->geom); 1771 constraints = ped_constraint_intersect (overlap_constraint, 1772 constraint); 1773 1774 if (!constraints && constraint) { 1775 ped_exception_throw ( 1776 PED_EXCEPTION_ERROR, 1777 PED_EXCEPTION_CANCEL, 1778 _("Can't have overlapping partitions.")); 1779 goto error; 1780 } 1781 1782 if (!_partition_enumerate (part)) 1783 goto error; 1784 if (!_partition_align (part, constraints)) 1785 goto error; 1786 } 1787 if (!_check_partition (disk, part)) 1788 goto error; 1789 if (!_disk_raw_add (disk, part)) 1790 goto error; 1791 1792 ped_constraint_destroy (overlap_constraint); 1793 ped_constraint_destroy (constraints); 1794 _disk_pop_update_mode (disk); 1795 #ifdef DEBUG 1796 if (!_disk_check_sanity (disk)) 1797 return 0; 1798 #endif 1799 return 1; 1800 1801 error: 1802 ped_constraint_destroy (overlap_constraint); 1803 ped_constraint_destroy (constraints); 1804 _disk_pop_update_mode (disk); 1805 return 0; 1806 } 1807 1808 /** 1809 * Removes PedPartition \p part from PedDisk \p disk. 1810 * 1811 * If \p part is an extended partition, it must not contain any logical 1812 * partitions. \p part is *NOT* destroyed. The caller must call 1813 * ped_partition_destroy(), or use ped_disk_delete_partition() instead. 1814 * 1815 * \return \c 0 on error. 1816 */ 1817 int 1818 ped_disk_remove_partition (PedDisk* disk, PedPartition* part) 1819 { 1820 PED_ASSERT (disk != NULL, return 0); 1821 PED_ASSERT (part != NULL, return 0); 1822 1823 _disk_push_update_mode (disk); 1824 PED_ASSERT (part->part_list == NULL, goto error); 1825 _disk_raw_remove (disk, part); 1826 _disk_pop_update_mode (disk); 1827 ped_disk_enumerate_partitions (disk); 1828 return 1; 1829 1830 error: 1831 _disk_pop_update_mode (disk); 1832 return 0; 1833 } 1834 1835 static int 1836 ped_disk_delete_all_logical (PedDisk* disk); 1837 1838 /** 1839 * Removes \p part from \p disk, and destroys \p part. 1840 * 1841 * \return \c 0 on failure. 1842 */ 1843 int 1844 ped_disk_delete_partition (PedDisk* disk, PedPartition* part) 1845 { 1846 PED_ASSERT (disk != NULL, return 0); 1847 PED_ASSERT (part != NULL, return 0); 1848 1849 _disk_push_update_mode (disk); 1850 if (part->type == PED_PARTITION_EXTENDED) 1851 ped_disk_delete_all_logical (disk); 1852 ped_disk_remove_partition (disk, part); 1853 ped_partition_destroy (part); 1854 _disk_pop_update_mode (disk); 1855 1856 return 1; 1857 } 1858 1859 static int 1860 ped_disk_delete_all_logical (PedDisk* disk) 1861 { 1862 PedPartition* walk; 1863 PedPartition* next; 1864 PedPartition* ext_part; 1865 1866 PED_ASSERT (disk != NULL, return 0); 1867 ext_part = ped_disk_extended_partition (disk); 1868 PED_ASSERT (ext_part != NULL, return 0); 1869 1870 for (walk = ext_part->part_list; walk; walk = next) { 1871 next = walk->next; 1872 1873 if (!ped_disk_delete_partition (disk, walk)) 1874 return 0; 1875 } 1876 return 1; 1877 } 1878 1879 /** 1880 * Removes and destroys all partitions on \p disk. 1881 * 1882 * \return \c 0 on failure. 1883 */ 1884 int 1885 ped_disk_delete_all (PedDisk* disk) 1886 { 1887 PedPartition* walk; 1888 PedPartition* next; 1889 1890 PED_ASSERT (disk != NULL, return 0); 1891 1892 _disk_push_update_mode (disk); 1893 1894 for (walk = disk->part_list; walk; walk = next) { 1895 next = walk->next; 1896 1897 if (!ped_disk_delete_partition (disk, walk)) 1898 return 0; 1899 } 1900 1901 _disk_pop_update_mode (disk); 1902 1903 return 1; 1904 } 1905 1906 /** 1907 * Sets the geometry of \p part (i.e. change a partitions location). This can 1908 * fail for many reasons, e.g. can't overlap with other partitions. If it 1909 * does fail, \p part will remain unchanged. Returns \c 0 on failure. \p part's 1910 * geometry may be set to something different from \p start and \p end subject 1911 * to \p constraint. 1912 * 1913 * \warning The constraint warning from ped_disk_add_partition() applies. 1914 * 1915 * \note this function does not modify the contents of the partition. You need 1916 * to call ped_file_system_resize() separately. 1917 */ 1918 int 1919 ped_disk_set_partition_geom (PedDisk* disk, PedPartition* part, 1920 const PedConstraint* constraint, 1921 PedSector start, PedSector end) 1922 { 1923 PedConstraint* overlap_constraint = NULL; 1924 PedConstraint* constraints = NULL; 1925 PedGeometry old_geom; 1926 PedGeometry new_geom; 1927 1928 PED_ASSERT (disk != NULL, return 0); 1929 PED_ASSERT (part != NULL, return 0); 1930 PED_ASSERT (part->disk == disk, return 0); 1931 1932 old_geom = part->geom; 1933 ped_geometry_init (&new_geom, part->geom.dev, start, end - start + 1); 1934 1935 _disk_push_update_mode (disk); 1936 1937 overlap_constraint 1938 = _partition_get_overlap_constraint (part, &new_geom); 1939 constraints = ped_constraint_intersect (overlap_constraint, constraint); 1940 if (!constraints && constraint) { 1941 ped_exception_throw ( 1942 PED_EXCEPTION_ERROR, 1943 PED_EXCEPTION_CANCEL, 1944 _("Can't have overlapping partitions.")); 1945 goto error_pop_update_mode; 1946 } 1947 1948 part->geom = new_geom; 1949 if (!_partition_align (part, constraints)) 1950 goto error_pop_update_mode; 1951 if (!_check_partition (disk, part)) 1952 goto error_pop_update_mode; 1953 1954 /* remove and add, to ensure the ordering gets updated if necessary */ 1955 _disk_raw_remove (disk, part); 1956 _disk_raw_add (disk, part); 1957 1958 _disk_pop_update_mode (disk); 1959 1960 ped_constraint_destroy (overlap_constraint); 1961 ped_constraint_destroy (constraints); 1962 return 1; 1963 1964 error_pop_update_mode: 1965 _disk_pop_update_mode (disk); 1966 ped_constraint_destroy (overlap_constraint); 1967 ped_constraint_destroy (constraints); 1968 part->geom = old_geom; 1969 return 0; 1970 } 1971 1972 /** 1973 * Grow PedPartition \p part geometry to the maximum possible subject to 1974 * \p constraint. The new geometry will be a superset of the old geometry. 1975 * 1976 * \return 0 on failure 1977 */ 1978 int 1979 ped_disk_maximize_partition (PedDisk* disk, PedPartition* part, 1980 const PedConstraint* constraint) 1981 { 1982 PedGeometry old_geom; 1983 PedSector global_min_start; 1984 PedSector global_max_end; 1985 PedSector new_start; 1986 PedSector new_end; 1987 PedPartition* ext_part = ped_disk_extended_partition (disk); 1988 PedConstraint* constraint_any; 1989 1990 PED_ASSERT (disk != NULL, return 0); 1991 PED_ASSERT (part != NULL, return 0); 1992 1993 if (part->type & PED_PARTITION_LOGICAL) { 1994 PED_ASSERT (ext_part != NULL, return 0); 1995 global_min_start = ext_part->geom.start; 1996 global_max_end = ext_part->geom.end; 1997 } else { 1998 global_min_start = 0; 1999 global_max_end = disk->dev->length - 1; 2000 } 2001 2002 old_geom = part->geom; 2003 2004 _disk_push_update_mode (disk); 2005 2006 if (part->prev) 2007 new_start = part->prev->geom.end + 1; 2008 else 2009 new_start = global_min_start; 2010 2011 if (part->next) 2012 new_end = part->next->geom.start - 1; 2013 else 2014 new_end = global_max_end; 2015 2016 if (!ped_disk_set_partition_geom (disk, part, constraint, new_start, 2017 new_end)) 2018 goto error; 2019 2020 _disk_pop_update_mode (disk); 2021 return 1; 2022 2023 error: 2024 constraint_any = ped_constraint_any (disk->dev); 2025 ped_disk_set_partition_geom (disk, part, constraint_any, 2026 old_geom.start, old_geom.end); 2027 ped_constraint_destroy (constraint_any); 2028 _disk_pop_update_mode (disk); 2029 return 0; 2030 } 2031 2032 /** 2033 * Get the maximum geometry \p part can be grown to, subject to 2034 * \p constraint. 2035 * 2036 * \return \c NULL on failure. 2037 */ 2038 PedGeometry* 2039 ped_disk_get_max_partition_geometry (PedDisk* disk, PedPartition* part, 2040 const PedConstraint* constraint) 2041 { 2042 PedGeometry old_geom; 2043 PedGeometry* max_geom; 2044 PedConstraint* constraint_exact; 2045 2046 PED_ASSERT(disk != NULL, return NULL); 2047 PED_ASSERT(part != NULL, return NULL); 2048 PED_ASSERT(ped_partition_is_active (part), return NULL); 2049 2050 old_geom = part->geom; 2051 if (!ped_disk_maximize_partition (disk, part, constraint)) 2052 return NULL; 2053 max_geom = ped_geometry_duplicate (&part->geom); 2054 2055 constraint_exact = ped_constraint_exact (&old_geom); 2056 ped_disk_set_partition_geom (disk, part, constraint_exact, 2057 old_geom.start, old_geom.end); 2058 ped_constraint_destroy (constraint_exact); 2059 2060 /* this assertion should never fail, because the old 2061 * geometry was valid 2062 */ 2063 PED_ASSERT (ped_geometry_test_equal (&part->geom, &old_geom), 2064 return NULL); 2065 2066 return max_geom; 2067 } 2068 2069 /** 2070 * Reduce the size of the extended partition to a minimum while still wrapping 2071 * its logical partitions. If there are no logical partitions, remove the 2072 * extended partition. 2073 * 2074 * \return 0 on failure. 2075 */ 2076 int 2077 ped_disk_minimize_extended_partition (PedDisk* disk) 2078 { 2079 PedPartition* first_logical; 2080 PedPartition* last_logical; 2081 PedPartition* walk; 2082 PedPartition* ext_part; 2083 PedConstraint* constraint; 2084 int status; 2085 2086 PED_ASSERT (disk != NULL, return 0); 2087 2088 ext_part = ped_disk_extended_partition (disk); 2089 if (!ext_part) 2090 return 1; 2091 2092 _disk_push_update_mode (disk); 2093 2094 first_logical = ext_part->part_list; 2095 if (!first_logical) { 2096 _disk_pop_update_mode (disk); 2097 return ped_disk_delete_partition (disk, ext_part); 2098 } 2099 2100 for (walk = first_logical; walk->next; walk = walk->next); 2101 last_logical = walk; 2102 2103 constraint = ped_constraint_any (disk->dev); 2104 status = ped_disk_set_partition_geom (disk, ext_part, constraint, 2105 first_logical->geom.start, 2106 last_logical->geom.end); 2107 ped_constraint_destroy (constraint); 2108 2109 _disk_pop_update_mode (disk); 2110 return status; 2111 } 2112 2113 /** 2114 * @} 2115 */ 2116 2117 /** 2118 * \addtogroup PedPartition 2119 * 2120 * @{ 2121 */ 2122 2123 /** 2124 * Returns a name that seems mildly appropriate for a partition type \p type. 2125 * 2126 * Eg, if you pass (PED_PARTITION_LOGICAL & PED_PARTITION_FREESPACE), it 2127 * will return "free". This isn't to be taken too seriously - it's just 2128 * useful for user interfaces, so you can show the user something ;-) 2129 * 2130 * \note The returned string will be in English. However, 2131 * translations are provided, so the caller can call 2132 * dgettext("parted", RESULT) on the result. 2133 * 2134 */ 2135 const char* 2136 ped_partition_type_get_name (PedPartitionType type) 2137 { 2138 if (type & PED_PARTITION_METADATA) 2139 return N_("metadata"); 2140 else if (type & PED_PARTITION_FREESPACE) 2141 return N_("free"); 2142 else if (type & PED_PARTITION_EXTENDED) 2143 return N_("extended"); 2144 else if (type & PED_PARTITION_LOGICAL) 2145 return N_("logical"); 2146 else 2147 return N_("primary"); 2148 } 2149 2150 2151 /** 2152 * Returns a name for a \p flag, e.g. PED_PARTITION_BOOT will return "boot". 2153 * 2154 * \note The returned string will be in English. However, 2155 * translations are provided, so the caller can call 2156 * dgettext("parted", RESULT) on the result. 2157 */ 2158 const char* 2159 ped_partition_flag_get_name (PedPartitionFlag flag) 2160 { 2161 switch (flag) { 2162 case PED_PARTITION_BOOT: 2163 return N_("boot"); 2164 case PED_PARTITION_ROOT: 2165 return N_("root"); 2166 case PED_PARTITION_SWAP: 2167 return N_("swap"); 2168 case PED_PARTITION_HIDDEN: 2169 return N_("hidden"); 2170 case PED_PARTITION_RAID: 2171 return N_("raid"); 2172 case PED_PARTITION_LVM: 2173 return N_("lvm"); 2174 case PED_PARTITION_LBA: 2175 return N_("lba"); 2176 case PED_PARTITION_HPSERVICE: 2177 return N_("hp-service"); 2178 case PED_PARTITION_PALO: 2179 return N_("palo"); 2180 case PED_PARTITION_PREP: 2181 return N_("prep"); 2182 case PED_PARTITION_MSFT_RESERVED: 2183 return N_("msftres"); 2184 2185 default: 2186 ped_exception_throw ( 2187 PED_EXCEPTION_BUG, 2188 PED_EXCEPTION_CANCEL, 2189 _("Unknown partition flag, %d."), 2190 flag); 2191 return NULL; 2192 } 2193 } 2194 2195 /** 2196 * Iterates through all flags. 2197 * 2198 * ped_partition_flag_next(0) returns the first flag 2199 * 2200 * \return the next flag, or 0 if there are no more flags 2201 */ 2202 PedPartitionFlag 2203 ped_partition_flag_next (PedPartitionFlag flag) 2204 { 2205 return (flag + 1) % (PED_PARTITION_LAST_FLAG + 1); 2206 } 2207 2208 /** 2209 * Returns the flag associated with \p name. 2210 * 2211 * \p name can be the English 2212 * string, or the translation for the native language. 2213 */ 2214 PedPartitionFlag 2215 ped_partition_flag_get_by_name (const char* name) 2216 { 2217 PedPartitionFlag flag; 2218 const char* flag_name; 2219 2220 for (flag = ped_partition_flag_next (0); flag; 2221 flag = ped_partition_flag_next (flag)) { 2222 flag_name = ped_partition_flag_get_name (flag); 2223 if (strcasecmp (name, flag_name) == 0 2224 || strcasecmp (name, _(flag_name)) == 0) 2225 return flag; 2226 } 2227 2228 return 0; 2229 } 2230 2231 static void 2232 ped_partition_print (const PedPartition* part) 2233 { 2234 PED_ASSERT (part != NULL, return); 2235 2236 printf (" %-10s %02d (%d->%d)\n", 2237 ped_partition_type_get_name (part->type), 2238 part->num, 2239 (int) part->geom.start, (int) part->geom.end); 2240 } 2241 2242 /** @} */ 2243 2244 /** 2245 * \addtogroup PedDisk 2246 * 2247 * @{ 2248 */ 2249 2250 /** 2251 * Prints a summary of disk's partitions. Useful for debugging. 2252 */ 2253 void 2254 ped_disk_print (const PedDisk* disk) 2255 { 2256 PedPartition* part; 2257 2258 PED_ASSERT (disk != NULL, return); 2259 2260 for (part = disk->part_list; part; 2261 part = ped_disk_next_partition (disk, part)) 2262 ped_partition_print (part); 2263 } 2264 2265 /** @} */