dvh.c revision 9663:ace9a2ac3683
1/* 2 libparted - a library for manipulating disk partitions 3 Copyright (C) 2001, 2002, 2005, 2007 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17*/ 18 19#include <config.h> 20#include <parted/parted.h> 21#include <parted/debug.h> 22#include <parted/endian.h> 23 24#include "dvh.h" 25 26#if ENABLE_NLS 27# include <libintl.h> 28# define _(String) dgettext (PACKAGE, String) 29#else 30# define _(String) (String) 31#endif /* ENABLE_NLS */ 32 33/* Default size for volhdr part, same val as IRIX's fx uses */ 34#define PTYPE_VOLHDR_DFLTSZ 4096 35 36/* Partition numbers that seem to be strongly held convention */ 37#define PNUM_VOLHDR 8 38#define PNUM_VOLUME 10 39 40/* Other notes of interest: 41 * PED_PARTITION_EXTENDED is used for volume headers 42 * PED_PARTITION_LOGICAL is used for bootfiles 43 * PED_PARTITION_NORMAL is used for all else 44 */ 45 46typedef struct _DVHDiskData { 47 struct device_parameters dev_params; 48 int swap; /* part num of swap, 0=none */ 49 int root; /* part num of root, 0=none */ 50 int boot; /* part num of boot, 0=none */ 51} DVHDiskData; 52 53typedef struct _DVHPartData { 54 int type; 55 char name[VDNAMESIZE + 1]; /* boot volumes only */ 56 int real_file_size; /* boot volumes only */ 57} DVHPartData; 58 59static PedDiskType dvh_disk_type; 60 61static int 62dvh_probe (const PedDevice *dev) 63{ 64 struct volume_header vh; 65 66 if (dev->sector_size != 512) 67 return 0; 68 69 if (!ped_device_read (dev, &vh, 0, 1)) 70 return 0; 71 72 return PED_BE32_TO_CPU (vh.vh_magic) == VHMAGIC; 73} 74 75#ifndef DISCOVER_ONLY 76static int 77dvh_clobber (PedDevice* dev) 78{ 79 char zeros[512]; 80 81 memset (zeros, 0, 512); 82 return ped_device_write (dev, zeros, 0, 1); 83} 84#endif /* !DISCOVER_ONLY */ 85 86static PedDisk* 87dvh_alloc (const PedDevice* dev) 88{ 89 PedDisk* disk; 90 DVHDiskData* dvh_disk_data; 91 PedPartition* volume_part; 92 PedConstraint* constraint_any; 93 94 disk = _ped_disk_alloc (dev, &dvh_disk_type); 95 if (!disk) 96 goto error; 97 98 disk->disk_specific = dvh_disk_data 99 = ped_malloc (sizeof (DVHDiskData)); 100 if (!dvh_disk_data) 101 goto error_free_disk; 102 103 memset (&dvh_disk_data->dev_params, 0, 104 sizeof (struct device_parameters)); 105 dvh_disk_data->swap = 0; 106 dvh_disk_data->root = 0; 107 dvh_disk_data->boot = 0; 108 109 volume_part = ped_partition_new (disk, PED_PARTITION_EXTENDED, NULL, 110 0, PTYPE_VOLHDR_DFLTSZ - 1); 111 if (!volume_part) 112 goto error_free_disk_specific; 113 volume_part->num = PNUM_VOLHDR + 1; 114 constraint_any = ped_constraint_any (dev); 115 if (!ped_disk_add_partition (disk, volume_part, constraint_any)) 116 goto error_destroy_constraint_any; 117 ped_constraint_destroy (constraint_any); 118 return disk; 119 120error_destroy_constraint_any: 121 ped_constraint_destroy (constraint_any); 122 ped_partition_destroy (volume_part); 123error_free_disk_specific: 124 ped_free (disk->disk_specific); 125error_free_disk: 126 ped_free (disk); 127error: 128 return NULL; 129} 130 131static PedDisk* 132dvh_duplicate (const PedDisk* disk) 133{ 134 PedDisk* new_disk; 135 DVHDiskData* new_dvh_disk_data; 136 DVHDiskData* old_dvh_disk_data = disk->disk_specific; 137 138 PED_ASSERT (old_dvh_disk_data != NULL, goto error); 139 140 new_disk = _ped_disk_alloc (disk->dev, &dvh_disk_type); 141 if (!new_disk) 142 goto error; 143 144 new_disk->disk_specific = new_dvh_disk_data 145 = ped_malloc (sizeof (DVHDiskData)); 146 if (!new_dvh_disk_data) 147 goto error_free_new_disk; 148 149 new_dvh_disk_data->dev_params = old_dvh_disk_data->dev_params; 150 return new_disk; 151 152error_free_new_disk: 153 ped_free (new_disk); 154error: 155 return NULL; 156} 157 158static void 159dvh_free (PedDisk* disk) 160{ 161 ped_free (disk->disk_specific); 162 _ped_disk_free (disk); 163} 164 165/* two's complement 32-bit checksum */ 166static uint32_t 167_checksum (const uint32_t* base, size_t size) 168{ 169 uint32_t sum = 0; 170 size_t i; 171 172 for (i = 0; i < size / sizeof (uint32_t); i++) 173 sum = sum - PED_BE32_TO_CPU (base[i]); 174 175 return sum; 176} 177 178/* try to make a reasonable volume header partition... */ 179static PedExceptionOption 180_handle_no_volume_header (PedDisk* disk) 181{ 182 PedExceptionOption ret; 183 PedPartition* part; 184 PedConstraint* constraint; 185 186 switch (ped_exception_throw ( 187 PED_EXCEPTION_WARNING, 188 PED_EXCEPTION_FIX + PED_EXCEPTION_CANCEL, 189 _("%s has no extended partition (volume header partition)."), 190 disk->dev->path)) { 191 case PED_EXCEPTION_UNHANDLED: 192 case PED_EXCEPTION_FIX: 193 default: 194 part = ped_partition_new ( 195 disk, PED_PARTITION_EXTENDED, NULL, 196 0, PTYPE_VOLHDR_DFLTSZ - 1); 197 if (!part) 198 goto error; 199 part->num = PNUM_VOLHDR + 1; 200 constraint = ped_constraint_any (part->disk->dev); 201 if (!constraint) 202 goto error_destroy_part; 203 if (!ped_disk_add_partition (disk, part, constraint)) 204 goto error_destroy_constraint; 205 ped_constraint_destroy (constraint); 206 ret = PED_EXCEPTION_FIX; 207 break; 208 209 case PED_EXCEPTION_CANCEL: 210 goto error; 211 } 212 return ret; 213 214error_destroy_constraint: 215 ped_constraint_destroy (constraint); 216error_destroy_part: 217 ped_partition_destroy (part); 218error: 219 return PED_EXCEPTION_CANCEL; 220} 221 222static PedPartition* 223_parse_partition (PedDisk* disk, struct partition_table* pt) 224{ 225 PedPartition* part; 226 DVHPartData* dvh_part_data; 227 PedSector start = PED_BE32_TO_CPU (pt->pt_firstlbn); 228 PedSector length = PED_BE32_TO_CPU (pt->pt_nblks); 229 230 part = ped_partition_new (disk, 231 pt->pt_type ? 0 : PED_PARTITION_EXTENDED, 232 NULL, 233 start, start + length - 1); 234 if (!part) 235 return NULL; 236 237 dvh_part_data = part->disk_specific; 238 dvh_part_data->type = PED_BE32_TO_CPU (pt->pt_type); 239 strcpy (dvh_part_data->name, ""); 240 241 return part; 242} 243 244static PedPartition* 245_parse_boot_file (PedDisk* disk, struct volume_directory* vd) 246{ 247 PedPartition* part; 248 DVHPartData* dvh_part_data; 249 PedSector start = PED_BE32_TO_CPU (vd->vd_lbn); 250 int length = PED_BE32_TO_CPU (vd->vd_nbytes); 251 252 part = ped_partition_new (disk, PED_PARTITION_LOGICAL, NULL, 253 start, start + length/512 - 1); 254 if (!part) 255 return NULL; 256 257 dvh_part_data = part->disk_specific; 258 dvh_part_data->real_file_size = length; 259 260 strncpy (dvh_part_data->name, vd->vd_name, VDNAMESIZE); 261 dvh_part_data->name[VDNAMESIZE] = 0; 262 return part; 263} 264 265static int dvh_write (const PedDisk* disk); 266 267/* YUCK 268 * 269 * If you remove a boot/root/swap partition, the disk->disk_specific 270 * thing isn't updated. (Probably reflects a design bug somewhere...) 271 * Anyway, the workaround is: flush stale flags whenever we allocate 272 * new partition numbers, and before we write to disk. 273 */ 274static void 275_flush_stale_flags (const PedDisk* disk) 276{ 277 DVHDiskData* dvh_disk_data = disk->disk_specific; 278 279 if (dvh_disk_data->root 280 && !ped_disk_get_partition (disk, dvh_disk_data->root)) 281 dvh_disk_data->root = 0; 282 if (dvh_disk_data->swap 283 && !ped_disk_get_partition (disk, dvh_disk_data->swap)) 284 dvh_disk_data->swap = 0; 285 if (dvh_disk_data->boot 286 && !ped_disk_get_partition (disk, dvh_disk_data->boot)) 287 dvh_disk_data->boot = 0; 288} 289 290static int 291dvh_read (PedDisk* disk) 292{ 293 DVHDiskData* dvh_disk_data = disk->disk_specific; 294 int i; 295 struct volume_header vh; 296 char boot_name [BFNAMESIZE + 1]; 297#ifndef DISCOVER_ONLY 298 int write_back = 0; 299#endif 300 301 PED_ASSERT (dvh_disk_data != NULL, return 0); 302 303 ped_disk_delete_all (disk); 304 305 if (!ped_device_read (disk->dev, &vh, 0, 1)) 306 return 0; 307 308 if (_checksum ((uint32_t*) &vh, sizeof (struct volume_header))) { 309 if (ped_exception_throw ( 310 PED_EXCEPTION_ERROR, 311 PED_EXCEPTION_IGNORE_CANCEL, 312 _("Checksum is wrong, indicating the partition " 313 "table is corrupt.")) 314 == PED_EXCEPTION_CANCEL) 315 return 0; 316 } 317 318 PED_ASSERT (PED_BE32_TO_CPU (vh.vh_magic) == VHMAGIC, return 0); 319 320 dvh_disk_data->dev_params = vh.vh_dp; 321 strncpy (boot_name, vh.vh_bootfile, BFNAMESIZE); 322 boot_name[BFNAMESIZE] = 0; 323 324 /* normal partitions */ 325 for (i = 0; i < NPARTAB; i++) { 326 PedPartition* part; 327 PedConstraint* constraint_exact; 328 329 if (!vh.vh_pt[i].pt_nblks) 330 continue; 331 /* Skip the whole-disk partition, parted disklikes overlap */ 332 if (PED_BE32_TO_CPU (vh.vh_pt[i].pt_type) == PTYPE_VOLUME) 333 continue; 334 335 part = _parse_partition (disk, &vh.vh_pt[i]); 336 if (!part) 337 goto error_delete_all; 338 339 part->fs_type = ped_file_system_probe (&part->geom); 340 part->num = i + 1; 341 342 if (PED_BE16_TO_CPU (vh.vh_rootpt) == i) 343 ped_partition_set_flag (part, PED_PARTITION_ROOT, 1); 344 if (PED_BE16_TO_CPU (vh.vh_swappt) == i) 345 ped_partition_set_flag (part, PED_PARTITION_SWAP, 1); 346 347 constraint_exact = ped_constraint_exact (&part->geom); 348 if (!ped_disk_add_partition(disk, part, constraint_exact)) { 349 ped_partition_destroy (part); 350 goto error_delete_all; 351 } 352 ped_constraint_destroy (constraint_exact); 353 } 354 355 if (!ped_disk_extended_partition (disk)) { 356#ifdef DISCOVER_ONLY 357 return 1; 358#else 359 switch (_handle_no_volume_header (disk)) { 360 case PED_EXCEPTION_CANCEL: 361 return 0; 362 case PED_EXCEPTION_IGNORE: 363 return 1; 364 case PED_EXCEPTION_FIX: 365 write_back = 1; 366 break; 367 default: 368 break; 369 } 370#endif 371 } 372 373 /* boot partitions */ 374 for (i = 0; i < NVDIR; i++) { 375 PedPartition* part; 376 PedConstraint* constraint_exact; 377 378 if (!vh.vh_vd[i].vd_nbytes) 379 continue; 380 381 part = _parse_boot_file (disk, &vh.vh_vd[i]); 382 if (!part) 383 goto error_delete_all; 384 385 part->fs_type = ped_file_system_probe (&part->geom); 386 part->num = NPARTAB + i + 1; 387 388 if (!strcmp (boot_name, ped_partition_get_name (part))) 389 ped_partition_set_flag (part, PED_PARTITION_BOOT, 1); 390 391 constraint_exact = ped_constraint_exact (&part->geom); 392 if (!ped_disk_add_partition(disk, part, constraint_exact)) { 393 ped_partition_destroy (part); 394 goto error_delete_all; 395 } 396 ped_constraint_destroy (constraint_exact); 397 } 398#ifndef DISCOVER_ONLY 399 if (write_back) 400 dvh_write (disk); 401#endif 402 return 1; 403 404error_delete_all: 405 ped_disk_delete_all (disk); 406 return 0; 407} 408 409#ifndef DISCOVER_ONLY 410static void 411_generate_partition (PedPartition* part, struct partition_table* pt) 412{ 413 DVHPartData* dvh_part_data = part->disk_specific; 414 415 /* Assert not a bootfile */ 416 PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) == 0, return); 417 418 pt->pt_nblks = PED_CPU_TO_BE32 (part->geom.length); 419 pt->pt_firstlbn = PED_CPU_TO_BE32 (part->geom.start); 420 pt->pt_type = PED_CPU_TO_BE32 (dvh_part_data->type); 421} 422 423static void 424_generate_boot_file (PedPartition* part, struct volume_directory* vd) 425{ 426 DVHPartData* dvh_part_data = part->disk_specific; 427 428 /* Assert it's a bootfile */ 429 PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) != 0, return); 430 431 vd->vd_nbytes = PED_CPU_TO_BE32 (dvh_part_data->real_file_size); 432 vd->vd_lbn = PED_CPU_TO_BE32 (part->geom.start); 433 434 memset (vd->vd_name, 0, VDNAMESIZE); 435 strncpy (vd->vd_name, dvh_part_data->name, VDNAMESIZE); 436} 437 438static int 439dvh_write (const PedDisk* disk) 440{ 441 DVHDiskData* dvh_disk_data = disk->disk_specific; 442 struct volume_header vh; 443 int i; 444 445 PED_ASSERT (dvh_disk_data != NULL, return 0); 446 447 _flush_stale_flags (disk); 448 449 memset (&vh, 0, sizeof (struct volume_header)); 450 451 vh.vh_magic = PED_CPU_TO_BE32 (VHMAGIC); 452 vh.vh_rootpt = PED_CPU_TO_BE16 (dvh_disk_data->root - 1); 453 vh.vh_swappt = PED_CPU_TO_BE16 (dvh_disk_data->swap - 1); 454 455 if (dvh_disk_data->boot) { 456 PedPartition* boot_part; 457 boot_part = ped_disk_get_partition (disk, dvh_disk_data->boot); 458 strcpy (vh.vh_bootfile, ped_partition_get_name (boot_part)); 459 } 460 461 vh.vh_dp = dvh_disk_data->dev_params; 462 /* Set up rudimentary device geometry */ 463 vh.vh_dp.dp_cyls 464 = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.cylinders); 465 vh.vh_dp.dp_trks0 = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.heads); 466 vh.vh_dp.dp_secs 467 = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.sectors); 468 vh.vh_dp.dp_secbytes = PED_CPU_TO_BE16 ((short)disk->dev->sector_size); 469 470 for (i = 0; i < NPARTAB; i++) { 471 PedPartition* part = ped_disk_get_partition (disk, i + 1); 472 if (part) 473 _generate_partition (part, &vh.vh_pt[i]); 474 } 475 476 /* whole disk partition 477 * This is only ever written here, and never modified 478 * (or even shown) as it must contain the entire disk, 479 * and parted does not like overlapping partitions 480 */ 481 vh.vh_pt[PNUM_VOLUME].pt_nblks = PED_CPU_TO_BE32 (disk->dev->length); 482 vh.vh_pt[PNUM_VOLUME].pt_firstlbn = PED_CPU_TO_BE32 (0); 483 vh.vh_pt[PNUM_VOLUME].pt_type = PED_CPU_TO_BE32 (PTYPE_VOLUME); 484 485 for (i = 0; i < NVDIR; i++) { 486 PedPartition* part = ped_disk_get_partition (disk, 487 i + 1 + NPARTAB); 488 if (part) 489 _generate_boot_file (part, &vh.vh_vd[i]); 490 } 491 492 vh.vh_csum = 0; 493 vh.vh_csum = PED_CPU_TO_BE32 (_checksum ((uint32_t*) &vh, 494 sizeof (struct volume_header))); 495 496 return ped_device_write (disk->dev, &vh, 0, 1) 497 && ped_device_sync (disk->dev); 498} 499#endif /* !DISCOVER_ONLY */ 500 501static PedPartition* 502dvh_partition_new (const PedDisk* disk, PedPartitionType part_type, 503 const PedFileSystemType* fs_type, 504 PedSector start, PedSector end) 505{ 506 PedPartition* part; 507 DVHPartData* dvh_part_data; 508 509 part = _ped_partition_alloc (disk, part_type, fs_type, start, end); 510 if (!part) 511 goto error; 512 513 if (!ped_partition_is_active (part)) { 514 part->disk_specific = NULL; 515 return part; 516 } 517 518 dvh_part_data = part->disk_specific = 519 ped_malloc (sizeof (DVHPartData)); 520 if (!dvh_part_data) 521 goto error_free_part; 522 523 dvh_part_data->type = (part_type == PED_PARTITION_EXTENDED) 524 ? PTYPE_VOLHDR 525 : PTYPE_RAW; 526 strcpy (dvh_part_data->name, ""); 527 dvh_part_data->real_file_size = part->geom.length * 512; 528 return part; 529 530error_free_part: 531 _ped_partition_free (part); 532error: 533 return NULL; 534} 535 536static PedPartition* 537dvh_partition_duplicate (const PedPartition* part) 538{ 539 PedPartition* result; 540 DVHPartData* part_data = part->disk_specific; 541 DVHPartData* result_data; 542 543 result = _ped_partition_alloc (part->disk, part->type, part->fs_type, 544 part->geom.start, part->geom.end); 545 if (!result) 546 goto error; 547 result->num = part->num; 548 549 if (!ped_partition_is_active (part)) { 550 result->disk_specific = NULL; 551 return result; 552 } 553 554 result_data = result->disk_specific = 555 ped_malloc (sizeof (DVHPartData)); 556 if (!result_data) 557 goto error_free_part; 558 559 result_data->type = part_data->type; 560 strcpy (result_data->name, part_data->name); 561 result_data->real_file_size = part_data->real_file_size; 562 return result; 563 564error_free_part: 565 _ped_partition_free (result); 566error: 567 return NULL; 568} 569 570static void 571dvh_partition_destroy (PedPartition* part) 572{ 573 if (ped_partition_is_active (part)) { 574 PED_ASSERT (part->disk_specific != NULL, return); 575 ped_free (part->disk_specific); 576 } 577 _ped_partition_free (part); 578} 579 580static int 581dvh_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type) 582{ 583 DVHPartData* dvh_part_data = part->disk_specific; 584 585 part->fs_type = fs_type; 586 587 if (part->type == PED_PARTITION_EXTENDED) { 588 dvh_part_data->type = PTYPE_VOLHDR; 589 return 1; 590 } 591 592 /* Is this a bootfile? */ 593 if (part->type == PED_PARTITION_LOGICAL) 594 return 1; 595 596 if (fs_type && !strcmp (fs_type->name, "xfs")) 597 dvh_part_data->type = PTYPE_XFS; 598 else 599 dvh_part_data->type = PTYPE_RAW; 600 return 1; 601} 602 603static int 604dvh_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state) 605{ 606 DVHDiskData* dvh_disk_data = part->disk->disk_specific; 607 608 switch (flag) { 609 case PED_PARTITION_ROOT: 610 if (part->type != 0 && state) { 611#ifndef DISCOVER_ONLY 612 ped_exception_throw ( 613 PED_EXCEPTION_ERROR, 614 PED_EXCEPTION_CANCEL, 615 _("Only primary partitions can be root " 616 "partitions.")); 617#endif 618 return 0; 619 } 620 dvh_disk_data->root = state ? part->num : 0; 621 break; 622 623 case PED_PARTITION_SWAP: 624 if (part->type != 0 && state) { 625#ifndef DISCOVER_ONLY 626 ped_exception_throw ( 627 PED_EXCEPTION_ERROR, 628 PED_EXCEPTION_CANCEL, 629 _("Only primary partitions can be swap " 630 "partitions.")); 631 return 0; 632#endif 633 } 634 dvh_disk_data->swap = state ? part->num : 0; 635 break; 636 637 case PED_PARTITION_BOOT: 638 if (part->type != PED_PARTITION_LOGICAL && state) { 639#ifndef DISCOVER_ONLY 640 ped_exception_throw ( 641 PED_EXCEPTION_ERROR, 642 PED_EXCEPTION_CANCEL, 643 _("Only logical partitions can be a boot " 644 "file.")); 645#endif 646 return 0; 647 } 648 dvh_disk_data->boot = state ? part->num : 0; 649 break; 650 651 case PED_PARTITION_LVM: 652 case PED_PARTITION_LBA: 653 case PED_PARTITION_HIDDEN: 654 case PED_PARTITION_RAID: 655 default: 656 return 0; 657 } 658 return 1; 659} 660 661static int 662dvh_partition_get_flag (const PedPartition* part, PedPartitionFlag flag) 663{ 664 DVHDiskData* dvh_disk_data = part->disk->disk_specific; 665 666 switch (flag) { 667 case PED_PARTITION_ROOT: 668 return dvh_disk_data->root == part->num; 669 670 case PED_PARTITION_SWAP: 671 return dvh_disk_data->swap == part->num; 672 673 case PED_PARTITION_BOOT: 674 return dvh_disk_data->boot == part->num; 675 676 case PED_PARTITION_LVM: 677 case PED_PARTITION_LBA: 678 case PED_PARTITION_HIDDEN: 679 case PED_PARTITION_RAID: 680 default: 681 return 0; 682 } 683 return 1; 684} 685 686static int 687dvh_partition_is_flag_available (const PedPartition* part, 688 PedPartitionFlag flag) 689{ 690 switch (flag) { 691 case PED_PARTITION_ROOT: 692 case PED_PARTITION_SWAP: 693 case PED_PARTITION_BOOT: 694 return 1; 695 696 case PED_PARTITION_LVM: 697 case PED_PARTITION_LBA: 698 case PED_PARTITION_HIDDEN: 699 case PED_PARTITION_RAID: 700 default: 701 return 0; 702 } 703 return 1; 704} 705 706static void 707dvh_partition_set_name (PedPartition* part, const char* name) 708{ 709 DVHPartData* dvh_part_data = part->disk_specific; 710 711 if (part->type == PED_PARTITION_LOGICAL) { 712 /* Bootfile */ 713 strncpy (dvh_part_data->name, name, VDNAMESIZE); 714 dvh_part_data->name[VDNAMESIZE] = 0; 715 } else { 716#ifndef DISCOVER_ONLY 717 ped_exception_throw ( 718 PED_EXCEPTION_ERROR, 719 PED_EXCEPTION_CANCEL, 720 _("Only logical partitions (boot files) have a name.")); 721#endif 722 } 723} 724 725static const char* 726dvh_partition_get_name (const PedPartition* part) 727{ 728 DVHPartData* dvh_part_data = part->disk_specific; 729 return dvh_part_data->name; 730} 731 732/* The constraint for the volume header partition is different, because it must 733 * contain the first sector of the disk. 734 */ 735static PedConstraint* 736_get_extended_constraint (PedDisk* disk) 737{ 738 PedGeometry min_geom; 739 if (!ped_geometry_init (&min_geom, disk->dev, 0, 1)) 740 return NULL; 741 return ped_constraint_new_from_min (&min_geom); 742} 743 744static PedConstraint* 745_get_primary_constraint (PedDisk* disk) 746{ 747 PedGeometry max_geom; 748 if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1)) 749 return NULL; 750 return ped_constraint_new_from_max (&max_geom); 751} 752 753static int 754dvh_partition_align (PedPartition* part, const PedConstraint* constraint) 755{ 756 PED_ASSERT (part != NULL, return 0); 757 758 if (_ped_partition_attempt_align ( 759 part, constraint, 760 (part->type == PED_PARTITION_EXTENDED) 761 ? _get_extended_constraint (part->disk) 762 : _get_primary_constraint (part->disk))) 763 return 1; 764 765#ifndef DISCOVER_ONLY 766 ped_exception_throw ( 767 PED_EXCEPTION_ERROR, 768 PED_EXCEPTION_CANCEL, 769 _("Unable to satisfy all constraints on the partition.")); 770#endif 771 return 0; 772} 773 774static int 775dvh_partition_enumerate (PedPartition* part) 776{ 777 int i; 778 779 /* never change the partition numbers */ 780 if (part->num != -1) 781 return 1; 782 783 _flush_stale_flags (part->disk); 784 785 if (part->type & PED_PARTITION_LOGICAL) { 786 /* Bootfile */ 787 for (i = 1 + NPARTAB; i <= NPARTAB + NVDIR; i++) { 788 if (!ped_disk_get_partition (part->disk, i)) { 789 part->num = i; 790 return 1; 791 } 792 } 793 PED_ASSERT (0, return 0); 794 } else if (part->type & PED_PARTITION_EXTENDED) { 795 /* Volheader */ 796 part->num = PNUM_VOLHDR + 1; 797 } else { 798 for (i = 1; i <= NPARTAB; i++) { 799 /* reserved for full volume partition */ 800 if (i == PNUM_VOLUME + 1) 801 continue; 802 803 if (!ped_disk_get_partition (part->disk, i)) { 804 part->num = i; 805 return 1; 806 } 807 } 808 ped_exception_throw ( 809 PED_EXCEPTION_ERROR, 810 PED_EXCEPTION_CANCEL, 811 _("Too many primary partitions")); 812 } 813 814 return 0; 815} 816 817static int 818dvh_get_max_primary_partition_count (const PedDisk* disk) 819{ 820 return NPARTAB; 821} 822 823static int 824dvh_alloc_metadata (PedDisk* disk) 825{ 826 PedPartition* part; 827 PedPartition* extended_part; 828 PedConstraint* constraint_exact; 829 PedPartitionType metadata_type; 830 PED_ASSERT(disk != NULL, return 0); 831 832 /* We don't need to "protect" the start of the disk from the volume 833 * header. 834 */ 835 extended_part = ped_disk_extended_partition (disk); 836 if (extended_part && extended_part->geom.start == 0) 837 metadata_type = PED_PARTITION_METADATA | PED_PARTITION_LOGICAL; 838 else 839 metadata_type = PED_PARTITION_METADATA; 840 841 part = ped_partition_new (disk, metadata_type, NULL, 0, 0); 842 if (!part) 843 goto error; 844 845 constraint_exact = ped_constraint_exact (&part->geom); 846 if (!ped_disk_add_partition (disk, part, constraint_exact)) 847 goto error_destroy_part; 848 ped_constraint_destroy (constraint_exact); 849 return 1; 850 851 ped_constraint_destroy (constraint_exact); 852error_destroy_part: 853 ped_partition_destroy (part); 854error: 855 return 0; 856} 857 858static PedDiskOps dvh_disk_ops = { 859 .probe = dvh_probe, 860#ifndef DISCOVER_ONLY 861 .clobber = dvh_clobber, 862#else 863 .clobber = NULL, 864#endif 865 .alloc = dvh_alloc, 866 .duplicate = dvh_duplicate, 867 .free = dvh_free, 868 .read = dvh_read, 869#ifndef DISCOVER_ONLY 870 .write = dvh_write, 871#else 872 .write = NULL, 873#endif 874 875 .partition_new = dvh_partition_new, 876 .partition_duplicate = dvh_partition_duplicate, 877 .partition_destroy = dvh_partition_destroy, 878 .partition_set_system = dvh_partition_set_system, 879 .partition_set_flag = dvh_partition_set_flag, 880 .partition_get_flag = dvh_partition_get_flag, 881 .partition_is_flag_available = dvh_partition_is_flag_available, 882 .partition_set_name = dvh_partition_set_name, 883 .partition_get_name = dvh_partition_get_name, 884 .partition_align = dvh_partition_align, 885 .partition_enumerate = dvh_partition_enumerate, 886 887 .alloc_metadata = dvh_alloc_metadata, 888 .get_max_primary_partition_count = 889 dvh_get_max_primary_partition_count 890}; 891 892static PedDiskType dvh_disk_type = { 893 .next = NULL, 894 .name = "dvh", 895 .ops = &dvh_disk_ops, 896 .features = PED_DISK_TYPE_PARTITION_NAME | PED_DISK_TYPE_EXTENDED 897}; 898 899void 900ped_disk_dvh_init () 901{ 902 PED_ASSERT (sizeof (struct volume_header) == 512, return); 903 904 ped_disk_type_register (&dvh_disk_type); 905} 906 907void 908ped_disk_dvh_done () 909{ 910 ped_disk_type_unregister (&dvh_disk_type); 911} 912