| /* |
| libparted - a library for manipulating disk partitions |
| Copyright (C) 2001, 2002, 2005, 2007 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <config.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 (const PedDevice *dev) |
| { |
| struct volume_header vh; |
| |
| if (dev->sector_size != 512) |
| return 0; |
| |
| 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 (const 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, |
| 0, 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); |
| 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; |
| PedConstraint* constraint; |
| |
| switch (ped_exception_throw ( |
| PED_EXCEPTION_WARNING, |
| PED_EXCEPTION_FIX + PED_EXCEPTION_CANCEL, |
| _("%s has no extended partition (volume header partition)."), |
| disk->dev->path)) { |
| case PED_EXCEPTION_UNHANDLED: |
| case PED_EXCEPTION_FIX: |
| default: |
| part = ped_partition_new ( |
| disk, PED_PARTITION_EXTENDED, NULL, |
| 0, PTYPE_VOLHDR_DFLTSZ - 1); |
| if (!part) |
| goto error; |
| part->num = PNUM_VOLHDR + 1; |
| constraint = ped_constraint_any (part->disk->dev); |
| if (!constraint) |
| goto error_destroy_part; |
| if (!ped_disk_add_partition (disk, part, constraint)) |
| goto error_destroy_constraint; |
| ped_constraint_destroy (constraint); |
| ret = PED_EXCEPTION_FIX; |
| break; |
| |
| case PED_EXCEPTION_CANCEL: |
| goto error; |
| } |
| return ret; |
| |
| error_destroy_constraint: |
| ped_constraint_destroy (constraint); |
| 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); |
| |
| 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 (const 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 (const 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; |
| break; |
| default: |
| break; |
| } |
| #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); |
| 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); |
| |
| 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 (const 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) |
| { |
| 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; |
| } |
| |
| /* The constraint for the volume header partition is different, because it must |
| * contain the first sector of the disk. |
| */ |
| static PedConstraint* |
| _get_extended_constraint (PedDisk* disk) |
| { |
| PedGeometry min_geom; |
| if (!ped_geometry_init (&min_geom, disk->dev, 0, 1)) |
| return NULL; |
| return ped_constraint_new_from_min (&min_geom); |
| } |
| |
| static PedConstraint* |
| _get_primary_constraint (PedDisk* disk) |
| { |
| PedGeometry max_geom; |
| if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1)) |
| return NULL; |
| return ped_constraint_new_from_max (&max_geom); |
| } |
| |
| static int |
| dvh_partition_align (PedPartition* part, const PedConstraint* constraint) |
| { |
| PED_ASSERT (part != NULL, return 0); |
| |
| if (_ped_partition_attempt_align ( |
| part, constraint, |
| (part->type == PED_PARTITION_EXTENDED) |
| ? _get_extended_constraint (part->disk) |
| : _get_primary_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; |
| PedPartition* extended_part; |
| PedConstraint* constraint_exact; |
| PedPartitionType metadata_type; |
| PED_ASSERT(disk != NULL, return 0); |
| |
| /* We don't need to "protect" the start of the disk from the volume |
| * header. |
| */ |
| extended_part = ped_disk_extended_partition (disk); |
| if (extended_part && extended_part->geom.start == 0) |
| metadata_type = PED_PARTITION_METADATA | PED_PARTITION_LOGICAL; |
| else |
| metadata_type = PED_PARTITION_METADATA; |
| |
| part = ped_partition_new (disk, metadata_type, 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; |
| |
| 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_disk_type_register (&dvh_disk_type); |
| } |
| |
| void |
| ped_disk_dvh_done () |
| { |
| ped_disk_type_unregister (&dvh_disk_type); |
| } |