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 
  46 typedef 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 
  53 typedef struct _DVHPartData {
  54         int     type;
  55         char    name[VDNAMESIZE + 1];   /* boot volumes only */
  56         int     real_file_size;         /* boot volumes only */
  57 } DVHPartData;
  58 
  59 static PedDiskType dvh_disk_type;
  60 
  61 static int
  62 dvh_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
  76 static int
  77 dvh_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 
  86 static PedDisk*
  87 dvh_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 
 120 error_destroy_constraint_any:
 121         ped_constraint_destroy (constraint_any);
 122         ped_partition_destroy (volume_part);
 123 error_free_disk_specific:
 124         ped_free (disk->disk_specific);
 125 error_free_disk:
 126         ped_free (disk);
 127 error:
 128         return NULL;
 129 }
 130 
 131 static PedDisk*
 132 dvh_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 
 152 error_free_new_disk:
 153         ped_free (new_disk);
 154 error:
 155         return NULL;
 156 }
 157 
 158 static void
 159 dvh_free (PedDisk* disk)
 160 {
 161         ped_free (disk->disk_specific);
 162         _ped_disk_free (disk);
 163 }
 164 
 165 /* two's complement 32-bit checksum */
 166 static 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... */
 179 static 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 
 214 error_destroy_constraint:
 215         ped_constraint_destroy (constraint);
 216 error_destroy_part:
 217         ped_partition_destroy (part);
 218 error:
 219         return PED_EXCEPTION_CANCEL;
 220 }
 221 
 222 static 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 
 244 static 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 
 265 static 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  */
 274 static 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 
 290 static int
 291 dvh_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 
 404 error_delete_all:
 405         ped_disk_delete_all (disk);
 406         return 0;
 407 }
 408 
 409 #ifndef DISCOVER_ONLY
 410 static 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 
 423 static 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 
 438 static int
 439 dvh_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 
 501 static PedPartition*
 502 dvh_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 
 530 error_free_part:
 531         _ped_partition_free (part);
 532 error:
 533         return NULL;
 534 }
 535 
 536 static PedPartition*
 537 dvh_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 
 564 error_free_part:
 565         _ped_partition_free (result);
 566 error:
 567         return NULL;
 568 }
 569 
 570 static void
 571 dvh_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 
 580 static int
 581 dvh_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 
 603 static int
 604 dvh_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 
 661 static int
 662 dvh_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 
 686 static int
 687 dvh_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 
 706 static void
 707 dvh_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 
 725 static const char*
 726 dvh_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  */
 735 static 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 
 744 static 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 
 753 static int
 754 dvh_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 
 774 static int
 775 dvh_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 
 817 static int
 818 dvh_get_max_primary_partition_count (const PedDisk* disk)
 819 {
 820         return NPARTAB;
 821 }
 822 
 823 static int
 824 dvh_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);
 852 error_destroy_part:
 853         ped_partition_destroy (part);
 854 error:
 855         return 0;
 856 }
 857 
 858 static 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 
 892 static 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 
 899 void
 900 ped_disk_dvh_init ()
 901 {
 902         PED_ASSERT (sizeof (struct volume_header) == 512, return);
 903 
 904         ped_disk_type_register (&dvh_disk_type);
 905 }
 906 
 907 void
 908 ped_disk_dvh_done ()
 909 {
 910         ped_disk_type_unregister (&dvh_disk_type);
 911 }