Logo Search packages:      
Sourcecode: parted version File versions

disk_dvh.c

/*
    libparted - a library for manipulating disk partitions
    Copyright (C) 2001, 2002 Free Software Foundation, Inc.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <string.h>

#include <parted/parted.h>
#include <parted/debug.h>
#include <parted/endian.h>

#include "dvh.h"

#if ENABLE_NLS
#  include <libintl.h>
#  define _(String) dgettext (PACKAGE, String)
#else
#  define _(String) (String)
#endif /* ENABLE_NLS */

/* Default size for volhdr part, same val as IRIX's fx uses */
#define PTYPE_VOLHDR_DFLTSZ 4096

/* Partition numbers that seem to be strongly held convention */
#define PNUM_VOLHDR 8
#define PNUM_VOLUME 10

/* Other notes of interest:
 *  PED_PARTITION_EXTENDED is used for volume headers
 *  PED_PARTITION_LOGICAL  is used for bootfiles
 *  PED_PARTITION_NORMAL   is used for all else
 */

typedef struct _DVHDiskData {
      struct device_parameters      dev_params;
      int                     swap; /* part num of swap, 0=none */
      int                     root; /* part num of root, 0=none */
      int                     boot; /* part num of boot, 0=none */
} DVHDiskData;

typedef struct _DVHPartData {
      int   type;
      char  name[VDNAMESIZE + 1];   /* boot volumes only */
      int   real_file_size;         /* boot volumes only */
} DVHPartData;

static PedDiskType dvh_disk_type;

static int
dvh_probe (PedDevice *dev)
{
      struct volume_header    vh;

      if (!ped_device_read (dev, &vh, 0, 1))
            return 0;

      return PED_BE32_TO_CPU (vh.vh_magic) == VHMAGIC;
}

#ifndef DISCOVER_ONLY
static int
dvh_clobber (PedDevice* dev)
{
      char  zeros[512];

      memset (zeros, 0, 512);
      return ped_device_write (dev, zeros, 0, 1);
}
#endif /* !DISCOVER_ONLY */

static PedDisk*
dvh_alloc (PedDevice* dev)
{
      PedDisk*    disk;
      DVHDiskData*      dvh_disk_data;
      PedPartition*     volume_part;
      PedConstraint*    constraint_any;

      disk = _ped_disk_alloc (dev, &dvh_disk_type);
      if (!disk)
            goto error;

      disk->disk_specific = dvh_disk_data
            = ped_malloc (sizeof (DVHDiskData));
      if (!dvh_disk_data)
            goto error_free_disk;

      memset (&dvh_disk_data->dev_params, 0,
            sizeof (struct device_parameters));
      dvh_disk_data->swap = 0;
      dvh_disk_data->root = 0;
      dvh_disk_data->boot = 0;

      volume_part = ped_partition_new (disk, PED_PARTITION_EXTENDED, NULL,
                               1, PTYPE_VOLHDR_DFLTSZ - 1);
      if (!volume_part)
            goto error_free_disk_specific;
      volume_part->num = PNUM_VOLHDR + 1;
      constraint_any = ped_constraint_any (dev);
      if (!ped_disk_add_partition (disk, volume_part, constraint_any))
            goto error_destroy_constraint_any;
      ped_constraint_destroy (constraint_any);
      return disk;

error_destroy_constraint_any:
      ped_constraint_destroy (constraint_any);
error_destroy_volume_part:
      ped_partition_destroy (volume_part);
error_free_disk_specific:
      ped_free (disk->disk_specific);
error_free_disk:
      ped_free (disk);
error:
      return NULL;
}

static PedDisk*
dvh_duplicate (const PedDisk* disk)
{
      PedDisk*    new_disk;
      DVHDiskData*      new_dvh_disk_data;
      DVHDiskData*      old_dvh_disk_data = disk->disk_specific;

      PED_ASSERT (old_dvh_disk_data != NULL, goto error);

      new_disk = _ped_disk_alloc (disk->dev, &dvh_disk_type);
      if (!new_disk)
            goto error;

      new_disk->disk_specific = new_dvh_disk_data
            = ped_malloc (sizeof (DVHDiskData));
      if (!new_dvh_disk_data)
            goto error_free_new_disk;

      new_dvh_disk_data->dev_params = old_dvh_disk_data->dev_params;
      return new_disk;

error_free_new_disk:
      ped_free (new_disk);
error:
      return NULL;
}

static void
dvh_free (PedDisk* disk)
{
      ped_free (disk->disk_specific);
      _ped_disk_free (disk);
}

/* two's complement 32-bit checksum */
static uint32_t
_checksum (const uint32_t* base, size_t size)
{
      uint32_t    sum = 0;
      size_t            i;

      for (i = 0; i < size / sizeof (uint32_t); i++)
            sum = sum - PED_BE32_TO_CPU (base[i]);

      return sum;
}

/* try to make a reasonable volume header partition... */
static PedExceptionOption
_handle_no_volume_header (PedDisk* disk)
{
      PedExceptionOption      ret;
      PedPartition*           part;
      PedPartition*           first_free_space;
      PedConstraint*          constraint_exact;

      for (first_free_space = disk->part_list; first_free_space;
           first_free_space = first_free_space->next) {
            if (first_free_space->type == PED_PARTITION_FREESPACE
                && first_free_space->geom.length > 5)
                  break;
      }
      /* weird!  Can this happen? */
      PED_ASSERT (first_free_space != NULL, goto error);

      switch (ped_exception_throw (
            PED_EXCEPTION_WARNING,
            PED_EXCEPTION_FIX + PED_EXCEPTION_IGNORE_CANCEL,
            _("%s has no extended partition (volume header "
              "partition).  If you ignore, then any boot volumes "
              "will be deleted."),
            disk->dev->path)) {
      case PED_EXCEPTION_UNHANDLED:
      case PED_EXCEPTION_FIX:
      default:
            part = ped_partition_new (
                  disk, PED_PARTITION_EXTENDED,
                  NULL,
                  first_free_space->geom.start,
                  first_free_space->geom.start + PTYPE_VOLHDR_DFLTSZ - 1);
            if (!part)
                  goto error;
            part->num = PNUM_VOLHDR + 1;
            constraint_exact = ped_constraint_exact (&part->geom);
            if (!constraint_exact)
                  goto error_destroy_part;
            if (!ped_disk_add_partition (disk, part, constraint_exact))
                  goto error_destroy_constraint_exact;
            ped_constraint_destroy (constraint_exact);
            ret = PED_EXCEPTION_FIX;
            break;

      case PED_EXCEPTION_IGNORE:
            ret = PED_EXCEPTION_IGNORE;
            break;

      case PED_EXCEPTION_CANCEL:
            goto error;
      }
      return ret;

error_destroy_constraint_exact:
      ped_constraint_destroy (constraint_exact);
error_destroy_part:
      ped_partition_destroy (part);
error:
      return PED_EXCEPTION_CANCEL;
}

static PedPartition*
_parse_partition (PedDisk* disk, struct partition_table* pt)
{
      PedPartition*     part;
      DVHPartData*      dvh_part_data;
      PedSector   start = PED_BE32_TO_CPU (pt->pt_firstlbn);
      PedSector   length = PED_BE32_TO_CPU (pt->pt_nblks);

      /* the boot/extended's start is often set to 0 */
      if (start == 0) {
            start++;
            length--;
      }

      part = ped_partition_new (disk,
                            pt->pt_type ? 0 : PED_PARTITION_EXTENDED,
                          NULL,
                          start, start + length - 1);
      if (!part)
            return NULL;

      dvh_part_data = part->disk_specific;
      dvh_part_data->type = PED_BE32_TO_CPU (pt->pt_type);
      strcpy (dvh_part_data->name, "");

      return part;
}

static PedPartition*
_parse_boot_file (PedDisk* disk, struct volume_directory* vd)
{
      PedPartition*     part;
      DVHPartData*      dvh_part_data;
      PedSector   start = PED_BE32_TO_CPU (vd->vd_lbn);
      int         length = PED_BE32_TO_CPU (vd->vd_nbytes);

      part = ped_partition_new (disk, PED_PARTITION_LOGICAL, NULL,
                          start, start + length/512 - 1);
      if (!part)
            return NULL;

      dvh_part_data = part->disk_specific;
      dvh_part_data->real_file_size = length;

      strncpy (dvh_part_data->name, vd->vd_name, VDNAMESIZE);
      dvh_part_data->name[VDNAMESIZE] = 0;
      return part;
}

static int dvh_write (PedDisk* disk);

/* YUCK
 *
 *  If you remove a boot/root/swap partition, the disk->disk_specific
 * thing isn't updated.  (Probably reflects a design bug somewhere...)
 * Anyway, the workaround is: flush stale flags whenever we allocate
 * new partition numbers, and before we write to disk.
 */
static void
_flush_stale_flags (PedDisk* disk)
{
      DVHDiskData*            dvh_disk_data = disk->disk_specific;

      if (dvh_disk_data->root
                   && !ped_disk_get_partition (disk, dvh_disk_data->root))
            dvh_disk_data->root = 0;
      if (dvh_disk_data->swap
                   && !ped_disk_get_partition (disk, dvh_disk_data->swap))
            dvh_disk_data->swap = 0;
      if (dvh_disk_data->boot
                   && !ped_disk_get_partition (disk, dvh_disk_data->boot))
            dvh_disk_data->boot = 0;
}

static int
dvh_read (PedDisk* disk)
{
      DVHDiskData*            dvh_disk_data = disk->disk_specific;
      int               i;
      struct volume_header    vh;
      char              boot_name [BFNAMESIZE + 1];
#ifndef DISCOVER_ONLY
      int               write_back = 0;
#endif

      PED_ASSERT (dvh_disk_data != NULL, return 0);

      ped_disk_delete_all (disk);

      if (!ped_device_read (disk->dev, &vh, 0, 1))
            return 0;

      if (_checksum ((uint32_t*) &vh, sizeof (struct volume_header))) {
            if (ped_exception_throw (
                  PED_EXCEPTION_ERROR,
                  PED_EXCEPTION_IGNORE_CANCEL,
                  _("Checksum is wrong, indicating the partition "
                    "table is corrupt."))
                        == PED_EXCEPTION_CANCEL)
                  return 0;
      }

      PED_ASSERT (PED_BE32_TO_CPU (vh.vh_magic) == VHMAGIC, return 0);

      dvh_disk_data->dev_params = vh.vh_dp;
      strncpy (boot_name, vh.vh_bootfile, BFNAMESIZE);
      boot_name[BFNAMESIZE] = 0;

      /* normal partitions */
      for (i = 0; i < NPARTAB; i++) {
            PedPartition* part;
            PedConstraint* constraint_exact;

            if (!vh.vh_pt[i].pt_nblks)
                  continue;
            /* Skip the whole-disk partition, parted disklikes overlap */
            if (PED_BE32_TO_CPU (vh.vh_pt[i].pt_type) == PTYPE_VOLUME)
                  continue;

            part = _parse_partition (disk, &vh.vh_pt[i]);
            if (!part)
                  goto error_delete_all;

            part->fs_type = ped_file_system_probe (&part->geom);
            part->num = i + 1;

            if (PED_BE16_TO_CPU (vh.vh_rootpt) == i)
                  ped_partition_set_flag (part, PED_PARTITION_ROOT, 1);
            if (PED_BE16_TO_CPU (vh.vh_swappt) == i)
                  ped_partition_set_flag (part, PED_PARTITION_SWAP, 1);

            constraint_exact = ped_constraint_exact (&part->geom);
            if (!ped_disk_add_partition(disk, part, constraint_exact)) {
                  ped_partition_destroy (part);
                  goto error_delete_all;
            }
            ped_constraint_destroy (constraint_exact);
      }

      if (!ped_disk_extended_partition (disk)) {
#ifdef DISCOVER_ONLY
            return 1;
#else
            switch (_handle_no_volume_header (disk)) {
                  case PED_EXCEPTION_CANCEL:
                        return 0;
                  case PED_EXCEPTION_IGNORE:
                        return 1;
                  case PED_EXCEPTION_FIX:
                        write_back = 1;
            }
#endif
      }

      /* boot partitions */
      for (i = 0; i < NVDIR; i++) {
            PedPartition* part;
            PedConstraint* constraint_exact;

            if (!vh.vh_vd[i].vd_nbytes)
                  continue;

            part = _parse_boot_file (disk, &vh.vh_vd[i]);
            if (!part)
                  goto error_delete_all;

            part->fs_type = ped_file_system_probe (&part->geom);
            part->num = NPARTAB + i + 1;

            if (!strcmp (boot_name, ped_partition_get_name (part)))
                  ped_partition_set_flag (part, PED_PARTITION_BOOT, 1);

            constraint_exact = ped_constraint_exact (&part->geom);
            if (!ped_disk_add_partition(disk, part, constraint_exact)) {
                  ped_partition_destroy (part);
                  goto error_delete_all;
            }
            ped_constraint_destroy (constraint_exact);
      }
#ifndef DISCOVER_ONLY
      if (write_back)
            dvh_write (disk);
#endif
      return 1;

error_delete_all:
      ped_disk_delete_all (disk);
error:
      return 0;
}

#ifndef DISCOVER_ONLY
static void
_generate_partition (PedPartition* part, struct partition_table* pt)
{
      DVHPartData*      dvh_part_data = part->disk_specific;

      /* Assert not a bootfile */
      PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) == 0, return);

      if (part->geom.start == 1) {
            /* before, we adjusted the volume header so as not to
             * overlap with metadata.  Now, we adjust back...
             */
            pt->pt_nblks = PED_CPU_TO_BE32 (part->geom.length + 1);
            pt->pt_firstlbn = 0;
      } else {
            pt->pt_nblks = PED_CPU_TO_BE32 (part->geom.length);
            pt->pt_firstlbn = PED_CPU_TO_BE32 (part->geom.start);
      }

      pt->pt_type = PED_CPU_TO_BE32 (dvh_part_data->type);
}

static void
_generate_boot_file (PedPartition* part, struct volume_directory* vd)
{
      DVHPartData*      dvh_part_data = part->disk_specific;

      /* Assert it's a bootfile */
      PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) != 0, return);

      vd->vd_nbytes = PED_CPU_TO_BE32 (dvh_part_data->real_file_size);
      vd->vd_lbn = PED_CPU_TO_BE32 (part->geom.start);

      memset (vd->vd_name, 0, VDNAMESIZE);
      strncpy (vd->vd_name, dvh_part_data->name, VDNAMESIZE);
}

static int
dvh_write (PedDisk* disk)
{
      DVHDiskData*            dvh_disk_data = disk->disk_specific;
      struct volume_header    vh;
      int               i;

      PED_ASSERT (dvh_disk_data != NULL, return 0);

      _flush_stale_flags (disk);

      memset (&vh, 0, sizeof (struct volume_header));

      vh.vh_magic = PED_CPU_TO_BE32 (VHMAGIC);
      vh.vh_rootpt = PED_CPU_TO_BE16 (dvh_disk_data->root - 1);
      vh.vh_swappt = PED_CPU_TO_BE16 (dvh_disk_data->swap - 1);

      if (dvh_disk_data->boot) {
            PedPartition* boot_part;
            boot_part = ped_disk_get_partition (disk, dvh_disk_data->boot);
            strcpy (vh.vh_bootfile, ped_partition_get_name (boot_part));
      }

      vh.vh_dp = dvh_disk_data->dev_params;
      /* Set up rudimentary device geometry */
      vh.vh_dp.dp_cyls
            = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.cylinders);
      vh.vh_dp.dp_trks0 = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.heads);
      vh.vh_dp.dp_secs
            = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.sectors);
      vh.vh_dp.dp_secbytes = PED_CPU_TO_BE16 ((short)disk->dev->sector_size);

      for (i = 0; i < NPARTAB; i++) {
            PedPartition* part = ped_disk_get_partition (disk, i + 1);
            if (part)
                  _generate_partition (part, &vh.vh_pt[i]);
      }

      /* whole disk partition
       * This is only ever written here, and never modified 
       * (or even shown) as it must contain the entire disk, 
       * and parted does not like overlapping partitions
       */
      vh.vh_pt[PNUM_VOLUME].pt_nblks = PED_CPU_TO_BE32 (disk->dev->length);
      vh.vh_pt[PNUM_VOLUME].pt_firstlbn = PED_CPU_TO_BE32 (0);
      vh.vh_pt[PNUM_VOLUME].pt_type = PED_CPU_TO_BE32 (PTYPE_VOLUME);

      for (i = 0; i < NVDIR; i++) {
            PedPartition* part = ped_disk_get_partition (disk,
                                               i + 1 + NPARTAB);
            if (part)
                  _generate_boot_file (part, &vh.vh_vd[i]);
      }

      vh.vh_csum = 0;
      vh.vh_csum = PED_CPU_TO_BE32 (_checksum ((uint32_t*) &vh,
                                    sizeof (struct volume_header)));

      return ped_device_write (disk->dev, &vh, 0, 1)
             && ped_device_sync (disk->dev);
}
#endif /* !DISCOVER_ONLY */

static PedPartition*
dvh_partition_new (const PedDisk* disk, PedPartitionType part_type,
                const PedFileSystemType* fs_type,
                PedSector start, PedSector end)
{
      PedPartition* part;
      DVHPartData* dvh_part_data;

      part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
      if (!part)
            goto error;

      if (!ped_partition_is_active (part)) {
            part->disk_specific = NULL;
            return part;
      }

      dvh_part_data = part->disk_specific =
            ped_malloc (sizeof (DVHPartData));
      if (!dvh_part_data)
            goto error_free_part;

      dvh_part_data->type = (part_type == PED_PARTITION_EXTENDED)
                              ? PTYPE_VOLHDR
                              : PTYPE_RAW;
      strcpy (dvh_part_data->name, "");
      dvh_part_data->real_file_size = part->geom.length * 512;
      return part;

error_free_part:
      _ped_partition_free (part);
error:
      return NULL;
}

static PedPartition*
dvh_partition_duplicate (const PedPartition* part)
{
      PedPartition* result;
      DVHPartData* part_data = part->disk_specific;
      DVHPartData* result_data;

      result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
                               part->geom.start, part->geom.end);
      if (!result)
            goto error;
      result->num = part->num;

      if (!ped_partition_is_active (part)) {
            result->disk_specific = NULL;
            return result;
      }

      result_data = result->disk_specific =
            ped_malloc (sizeof (DVHPartData));
      if (!result_data)
            goto error_free_part;

      result_data->type = part_data->type;
      strcpy (result_data->name, part_data->name);
      result_data->real_file_size = part_data->real_file_size;
      return result;

error_free_part:
      _ped_partition_free (result);
error:
      return NULL;
}

static void
dvh_partition_destroy (PedPartition* part)
{
      if (ped_partition_is_active (part)) {
            PED_ASSERT (part->disk_specific != NULL, return);
            ped_free (part->disk_specific);
      }
      _ped_partition_free (part);
}

static int
dvh_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
{
      DVHPartData* dvh_part_data = part->disk_specific;

      part->fs_type = fs_type;

      if (part->type == PED_PARTITION_EXTENDED) {
            dvh_part_data->type = PTYPE_VOLHDR;
            return 1;
      }

      /* Is this a bootfile? */
      if (part->type == PED_PARTITION_LOGICAL)
            return 1;

      if (fs_type && !strcmp (fs_type->name, "xfs"))
            dvh_part_data->type = PTYPE_XFS;
      else
            dvh_part_data->type = PTYPE_RAW;
      return 1;
}

static int
dvh_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
{
      DVHDiskData* dvh_disk_data = part->disk->disk_specific;

      switch (flag) {
      case PED_PARTITION_ROOT:
            if (part->type != 0 && state) {
#ifndef DISCOVER_ONLY
                  ped_exception_throw (
                        PED_EXCEPTION_ERROR,
                        PED_EXCEPTION_CANCEL,
                        _("Only primary partitions can be root "
                          "partitions."));
#endif
                  return 0;
            }
            dvh_disk_data->root = state ? part->num : 0;
            break;

      case PED_PARTITION_SWAP:
            if (part->type != 0 && state) {
#ifndef DISCOVER_ONLY
                  ped_exception_throw (
                        PED_EXCEPTION_ERROR,
                        PED_EXCEPTION_CANCEL,
                        _("Only primary partitions can be swap "
                          "partitions."));
                  return 0;
#endif
            }
            dvh_disk_data->swap = state ? part->num : 0;
            break;

      case PED_PARTITION_BOOT:
            if (part->type != PED_PARTITION_LOGICAL && state) {
#ifndef DISCOVER_ONLY
                  ped_exception_throw (
                        PED_EXCEPTION_ERROR,
                        PED_EXCEPTION_CANCEL,
                        _("Only logical partitions can be a boot "
                          "file."));
#endif
                  return 0;
            }
            dvh_disk_data->boot = state ? part->num : 0;
            break;

      case PED_PARTITION_LVM:
      case PED_PARTITION_LBA:
      case PED_PARTITION_HIDDEN:
      case PED_PARTITION_RAID:
      default:
            return 0;
      }
      return 1;
}

static int
dvh_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
{
      DVHDiskData* dvh_disk_data = part->disk->disk_specific;

      switch (flag) {
      case PED_PARTITION_ROOT:
            return dvh_disk_data->root == part->num;

      case PED_PARTITION_SWAP:
            return dvh_disk_data->swap == part->num;

      case PED_PARTITION_BOOT:
            return dvh_disk_data->boot == part->num;

      case PED_PARTITION_LVM:
      case PED_PARTITION_LBA:
      case PED_PARTITION_HIDDEN:
      case PED_PARTITION_RAID:
      default:
            return 0;
      }
      return 1;
}

static int
dvh_partition_is_flag_available (const PedPartition* part,
                          PedPartitionFlag flag)
{
      DVHDiskData* dvh_disk_data = part->disk->disk_specific;

      switch (flag) {
      case PED_PARTITION_ROOT:
      case PED_PARTITION_SWAP:
      case PED_PARTITION_BOOT:
            return 1;

      case PED_PARTITION_LVM:
      case PED_PARTITION_LBA:
      case PED_PARTITION_HIDDEN:
      case PED_PARTITION_RAID:
      default:
            return 0;
      }
      return 1;
}

static void
dvh_partition_set_name (PedPartition* part, const char* name)
{
      DVHPartData* dvh_part_data = part->disk_specific;

      if (part->type == PED_PARTITION_LOGICAL) {
            /* Bootfile */
            strncpy (dvh_part_data->name, name, VDNAMESIZE);
            dvh_part_data->name[VDNAMESIZE] = 0;
      } else {
#ifndef DISCOVER_ONLY
            ped_exception_throw (
                  PED_EXCEPTION_ERROR,
                  PED_EXCEPTION_CANCEL,
                  _("Only logical partitions (boot files) have a name."));
#endif
      }
}

static const char*
dvh_partition_get_name (const PedPartition* part)
{
      DVHPartData* dvh_part_data = part->disk_specific;
      return dvh_part_data->name;
}

static PedConstraint*
_get_strict_primary_constraint (PedDisk* disk)
{
      PedDevice*  dev = disk->dev;
        PedAlignment    start_align;
        PedAlignment    end_align;
        PedGeometry     max_geom;
      PedSector   block = dev->bios_geom.sectors * dev->bios_geom.heads;
      PedSector   start_lower_bound;
      PedPartition*     extended_partition = ped_disk_extended_partition (disk);

      if (extended_partition)
            start_lower_bound = extended_partition->geom.end + 1;
      else
            start_lower_bound = 1;

        if (!ped_alignment_init (&start_align, 0, block))
                return NULL;
        if (!ped_alignment_init (&end_align, -1, block))
                return NULL;
      if (!ped_geometry_init (&max_geom, dev, start_lower_bound,
                              disk->dev->length - 1 - start_lower_bound))
            return NULL;

        return ped_constraint_new (&start_align, &end_align, &max_geom,
                                   &max_geom, 1, dev->length);
}

static PedConstraint*
_get_lax_constraint (PedDisk* disk)
{
      PedDevice*  dev = disk->dev;
        PedGeometry     max_geom;

      if (!ped_geometry_init (&max_geom, dev, 1, dev->length - 1))
            return NULL;

        return ped_constraint_new (ped_alignment_any, ped_alignment_any,
                           &max_geom, &max_geom, 1, dev->length);
}

static int
dvh_partition_align (PedPartition* part, const PedConstraint* constraint)
{
        PED_ASSERT (part != NULL, return 0);

      if (part->type == 0) {
            if (_ped_partition_attempt_align (
                        part, constraint,
                        _get_strict_primary_constraint (part->disk)))
                  return 1;
      }
      if (_ped_partition_attempt_align (part, constraint,
                                _get_lax_constraint (part->disk)))
            return 1;

#ifndef DISCOVER_ONLY
      ped_exception_throw (
            PED_EXCEPTION_ERROR,
            PED_EXCEPTION_CANCEL,
            _("Unable to satisfy all constraints on the partition."));
#endif
      return 0;
}

static int
dvh_partition_enumerate (PedPartition* part)
{
      int i;

      /* never change the partition numbers */
      if (part->num != -1)
            return 1;

      _flush_stale_flags (part->disk);

      if (part->type & PED_PARTITION_LOGICAL) {
            /* Bootfile */
            for (i = 1 + NPARTAB; i <= NPARTAB + NVDIR; i++) {
                  if (!ped_disk_get_partition (part->disk, i)) {
                        part->num = i;
                        return 1;
                  }
            }
            PED_ASSERT (0, return 0);
      } else if (part->type & PED_PARTITION_EXTENDED) {
            /* Volheader */
            part->num = PNUM_VOLHDR + 1;
      } else {
            for (i = 1; i <= NPARTAB; i++) {
                  /* reserved for full volume partition */
                  if (i == PNUM_VOLUME + 1)
                        continue;

                  if (!ped_disk_get_partition (part->disk, i)) {
                        part->num = i;
                        return 1;
                  }
            }
            ped_exception_throw (
                  PED_EXCEPTION_ERROR,
                  PED_EXCEPTION_CANCEL,
                  _("Too many primary partitions"));
      }

      return 0;
}

static int
dvh_get_max_primary_partition_count (const PedDisk* disk)
{
      return NPARTAB;
}

static int
dvh_alloc_metadata (PedDisk* disk)
{
      PedPartition* part;
      PedConstraint* constraint_exact;
      PED_ASSERT(disk != NULL, return 0);

      part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, 0, 0);
      if (!part)
            goto error;

      constraint_exact = ped_constraint_exact (&part->geom);
      if (!ped_disk_add_partition (disk, part, constraint_exact))
            goto error_destroy_part;
      ped_constraint_destroy (constraint_exact);
      return 1;

error_destroy_constraint:
      ped_constraint_destroy (constraint_exact);
error_destroy_part:
      ped_partition_destroy (part);
error:
      return 0;
}

static PedDiskOps dvh_disk_ops = {
      probe:                  dvh_probe,
#ifndef DISCOVER_ONLY
      clobber:          dvh_clobber,
#else
      clobber:          NULL,
#endif
      alloc:                  dvh_alloc,
      duplicate:        dvh_duplicate,
      free:             dvh_free,
      read:             dvh_read,
#ifndef DISCOVER_ONLY
      write:                  dvh_write,
#else
      write:                  NULL,
#endif

      partition_new:          dvh_partition_new,
      partition_duplicate:    dvh_partition_duplicate,
      partition_destroy:      dvh_partition_destroy,
      partition_set_system:   dvh_partition_set_system,
      partition_set_flag:     dvh_partition_set_flag,
      partition_get_flag:     dvh_partition_get_flag,
      partition_is_flag_available:  dvh_partition_is_flag_available,
      partition_set_name:     dvh_partition_set_name,
      partition_get_name:     dvh_partition_get_name,
      partition_align:  dvh_partition_align,
      partition_enumerate:    dvh_partition_enumerate,

      alloc_metadata:         dvh_alloc_metadata,
      get_max_primary_partition_count:
                        dvh_get_max_primary_partition_count
};

static PedDiskType dvh_disk_type = {
      next:       NULL,
      name:       "dvh",
      ops:        &dvh_disk_ops,
      features:   PED_DISK_TYPE_PARTITION_NAME | PED_DISK_TYPE_EXTENDED
};

void
ped_disk_dvh_init ()
{
      PED_ASSERT (sizeof (struct volume_header) == 512, return);

      ped_register_disk_type (&dvh_disk_type);
}

void
ped_disk_dvh_done ()
{
      ped_unregister_disk_type (&dvh_disk_type);
}


Generated by  Doxygen 1.6.0   Back to index