2
libparted - a library for manipulating disk partitions
3
Copyright (C) 2001-2002, 2005, 2007-2012 Free Software Foundation, Inc.
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.
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.
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/>.
20
#include <parted/parted.h>
21
#include <parted/debug.h>
22
#include <parted/endian.h>
30
# define _(String) dgettext (PACKAGE, String)
32
# define _(String) (String)
33
#endif /* ENABLE_NLS */
35
/* Default size for volhdr part, same val as IRIX's fx uses */
36
#define PTYPE_VOLHDR_DFLTSZ 4096
38
/* Partition numbers that seem to be strongly held convention */
40
#define PNUM_VOLUME 10
42
/* Other notes of interest:
43
* PED_PARTITION_EXTENDED is used for volume headers
44
* PED_PARTITION_LOGICAL is used for bootfiles
45
* PED_PARTITION_NORMAL is used for all else
48
typedef struct _DVHDiskData {
49
struct device_parameters dev_params;
50
int swap; /* part num of swap, 0=none */
51
int root; /* part num of root, 0=none */
52
int boot; /* part num of boot, 0=none */
55
typedef struct _DVHPartData {
57
char name[VDNAMESIZE + 1]; /* boot volumes only */
58
int real_file_size; /* boot volumes only */
61
static PedDiskType dvh_disk_type;
64
dvh_probe (const PedDevice *dev)
66
struct volume_header *vh;
69
if (!ptt_read_sector (dev, 0, &label))
72
vh = (struct volume_header *) label;
74
bool found = PED_BE32_TO_CPU (vh->vh_magic) == VHMAGIC;
80
dvh_alloc (const PedDevice* dev)
83
DVHDiskData* dvh_disk_data;
84
PedPartition* volume_part;
85
PedConstraint* constraint_any;
87
disk = _ped_disk_alloc (dev, &dvh_disk_type);
91
disk->disk_specific = dvh_disk_data
92
= ped_malloc (sizeof (DVHDiskData));
96
memset (&dvh_disk_data->dev_params, 0,
97
sizeof (struct device_parameters));
98
dvh_disk_data->swap = 0;
99
dvh_disk_data->root = 0;
100
dvh_disk_data->boot = 0;
102
volume_part = ped_partition_new (disk, PED_PARTITION_EXTENDED, NULL,
103
0, PTYPE_VOLHDR_DFLTSZ - 1);
105
goto error_free_disk_specific;
106
volume_part->num = PNUM_VOLHDR + 1;
107
constraint_any = ped_constraint_any (dev);
108
if (!ped_disk_add_partition (disk, volume_part, constraint_any))
109
goto error_destroy_constraint_any;
110
ped_constraint_destroy (constraint_any);
113
error_destroy_constraint_any:
114
ped_constraint_destroy (constraint_any);
115
ped_partition_destroy (volume_part);
116
error_free_disk_specific:
117
free (disk->disk_specific);
125
dvh_duplicate (const PedDisk* disk)
128
DVHDiskData* new_dvh_disk_data;
129
DVHDiskData* old_dvh_disk_data = disk->disk_specific;
131
PED_ASSERT (old_dvh_disk_data != NULL);
133
new_disk = ped_disk_new_fresh (disk->dev, &dvh_disk_type);
137
new_disk->disk_specific = new_dvh_disk_data
138
= ped_malloc (sizeof (DVHDiskData));
139
if (!new_dvh_disk_data)
140
goto error_free_new_disk;
142
new_dvh_disk_data->dev_params = old_dvh_disk_data->dev_params;
152
dvh_free (PedDisk* disk)
154
free (disk->disk_specific);
155
_ped_disk_free (disk);
158
/* two's complement 32-bit checksum */
159
static uint32_t _GL_ATTRIBUTE_PURE
160
_checksum (const uint32_t* base, size_t size)
165
for (i = 0; i < size / sizeof (uint32_t); i++)
166
sum = sum - PED_BE32_TO_CPU (base[i]);
171
/* try to make a reasonable volume header partition... */
172
static PedExceptionOption
173
_handle_no_volume_header (PedDisk* disk)
175
PedExceptionOption ret;
177
PedConstraint* constraint;
179
switch (ped_exception_throw (
180
PED_EXCEPTION_WARNING,
181
PED_EXCEPTION_FIX + PED_EXCEPTION_CANCEL,
182
_("%s has no extended partition (volume header partition)."),
184
case PED_EXCEPTION_UNHANDLED:
185
case PED_EXCEPTION_FIX:
187
part = ped_partition_new (
188
disk, PED_PARTITION_EXTENDED, NULL,
189
0, PTYPE_VOLHDR_DFLTSZ - 1);
192
part->num = PNUM_VOLHDR + 1;
193
constraint = ped_constraint_any (part->disk->dev);
195
goto error_destroy_part;
196
if (!ped_disk_add_partition (disk, part, constraint))
197
goto error_destroy_constraint;
198
ped_constraint_destroy (constraint);
199
ret = PED_EXCEPTION_FIX;
202
case PED_EXCEPTION_CANCEL:
207
error_destroy_constraint:
208
ped_constraint_destroy (constraint);
210
ped_partition_destroy (part);
212
return PED_EXCEPTION_CANCEL;
216
_parse_partition (PedDisk* disk, struct partition_table* pt)
219
DVHPartData* dvh_part_data;
220
PedSector start = PED_BE32_TO_CPU (pt->pt_firstlbn);
221
PedSector length = PED_BE32_TO_CPU (pt->pt_nblks);
223
part = ped_partition_new (disk,
224
pt->pt_type ? 0 : PED_PARTITION_EXTENDED,
226
start, start + length - 1);
230
dvh_part_data = part->disk_specific;
231
dvh_part_data->type = PED_BE32_TO_CPU (pt->pt_type);
232
strcpy (dvh_part_data->name, "");
238
_parse_boot_file (PedDisk* disk, struct volume_directory* vd)
241
DVHPartData* dvh_part_data;
242
PedSector start = PED_BE32_TO_CPU (vd->vd_lbn);
243
int length = PED_BE32_TO_CPU (vd->vd_nbytes);
245
part = ped_partition_new (disk, PED_PARTITION_LOGICAL, NULL,
246
start, start + length/512 - 1);
250
dvh_part_data = part->disk_specific;
251
dvh_part_data->real_file_size = length;
253
strncpy (dvh_part_data->name, vd->vd_name, VDNAMESIZE);
254
dvh_part_data->name[VDNAMESIZE] = 0;
258
static int dvh_write (const PedDisk* disk);
262
* If you remove a boot/root/swap partition, the disk->disk_specific
263
* thing isn't updated. (Probably reflects a design bug somewhere...)
264
* Anyway, the workaround is: flush stale flags whenever we allocate
265
* new partition numbers, and before we write to disk.
268
_flush_stale_flags (const PedDisk* disk)
270
DVHDiskData* dvh_disk_data = disk->disk_specific;
272
if (dvh_disk_data->root
273
&& !ped_disk_get_partition (disk, dvh_disk_data->root))
274
dvh_disk_data->root = 0;
275
if (dvh_disk_data->swap
276
&& !ped_disk_get_partition (disk, dvh_disk_data->swap))
277
dvh_disk_data->swap = 0;
278
if (dvh_disk_data->boot
279
&& !ped_disk_get_partition (disk, dvh_disk_data->boot))
280
dvh_disk_data->boot = 0;
284
dvh_read (PedDisk* disk)
286
DVHDiskData* dvh_disk_data = disk->disk_specific;
288
struct volume_header vh;
289
char boot_name [BFNAMESIZE + 1];
290
#ifndef DISCOVER_ONLY
294
PED_ASSERT (dvh_disk_data != NULL);
296
ped_disk_delete_all (disk);
299
if (!ptt_read_sector (disk->dev, 0, &s0))
301
memcpy (&vh, s0, sizeof vh);
304
if (_checksum ((uint32_t*) &vh, sizeof (struct volume_header))) {
305
if (ped_exception_throw (
307
PED_EXCEPTION_IGNORE_CANCEL,
308
_("Checksum is wrong, indicating the partition "
309
"table is corrupt."))
310
== PED_EXCEPTION_CANCEL)
314
PED_ASSERT (PED_BE32_TO_CPU (vh.vh_magic) == VHMAGIC);
316
dvh_disk_data->dev_params = vh.vh_dp;
317
strncpy (boot_name, vh.vh_bootfile, BFNAMESIZE);
318
boot_name[BFNAMESIZE] = 0;
320
/* normal partitions */
321
for (i = 0; i < NPARTAB; i++) {
324
if (!vh.vh_pt[i].pt_nblks)
326
/* Skip the whole-disk partition, parted disklikes overlap */
327
if (PED_BE32_TO_CPU (vh.vh_pt[i].pt_type) == PTYPE_VOLUME)
330
part = _parse_partition (disk, &vh.vh_pt[i]);
332
goto error_delete_all;
334
part->fs_type = ped_file_system_probe (&part->geom);
337
if (PED_BE16_TO_CPU (vh.vh_rootpt) == i)
338
ped_partition_set_flag (part, PED_PARTITION_ROOT, 1);
339
if (PED_BE16_TO_CPU (vh.vh_swappt) == i)
340
ped_partition_set_flag (part, PED_PARTITION_SWAP, 1);
342
PedConstraint *constraint_exact
343
= ped_constraint_exact (&part->geom);
344
bool ok = ped_disk_add_partition (disk, part, constraint_exact);
345
ped_constraint_destroy (constraint_exact);
347
ped_partition_destroy (part);
348
goto error_delete_all;
352
if (!ped_disk_extended_partition (disk)) {
356
switch (_handle_no_volume_header (disk)) {
357
case PED_EXCEPTION_CANCEL:
359
case PED_EXCEPTION_IGNORE:
361
case PED_EXCEPTION_FIX:
370
/* boot partitions */
371
for (i = 0; i < NVDIR; i++) {
374
if (!vh.vh_vd[i].vd_nbytes)
377
part = _parse_boot_file (disk, &vh.vh_vd[i]);
379
goto error_delete_all;
381
part->fs_type = ped_file_system_probe (&part->geom);
382
part->num = NPARTAB + i + 1;
384
if (!strcmp (boot_name, ped_partition_get_name (part)))
385
ped_partition_set_flag (part, PED_PARTITION_BOOT, 1);
387
PedConstraint *constraint_exact
388
= ped_constraint_exact (&part->geom);
389
bool ok = ped_disk_add_partition (disk, part, constraint_exact);
390
ped_constraint_destroy (constraint_exact);
392
ped_partition_destroy (part);
393
goto error_delete_all;
396
#ifndef DISCOVER_ONLY
403
ped_disk_delete_all (disk);
407
#ifndef DISCOVER_ONLY
409
_generate_partition (PedPartition* part, struct partition_table* pt)
411
DVHPartData* dvh_part_data = part->disk_specific;
413
/* Assert not a bootfile */
414
PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) == 0);
416
pt->pt_nblks = PED_CPU_TO_BE32 (part->geom.length);
417
pt->pt_firstlbn = PED_CPU_TO_BE32 (part->geom.start);
418
pt->pt_type = PED_CPU_TO_BE32 (dvh_part_data->type);
422
_generate_boot_file (PedPartition* part, struct volume_directory* vd)
424
DVHPartData* dvh_part_data = part->disk_specific;
426
/* Assert it's a bootfile */
427
PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) != 0);
429
vd->vd_nbytes = PED_CPU_TO_BE32 (dvh_part_data->real_file_size);
430
vd->vd_lbn = PED_CPU_TO_BE32 (part->geom.start);
432
memset (vd->vd_name, 0, VDNAMESIZE);
433
strncpy (vd->vd_name, dvh_part_data->name, VDNAMESIZE);
437
dvh_write (const PedDisk* disk)
439
DVHDiskData* dvh_disk_data = disk->disk_specific;
440
struct volume_header vh;
443
PED_ASSERT (dvh_disk_data != NULL);
445
_flush_stale_flags (disk);
447
memset (&vh, 0, sizeof (struct volume_header));
449
vh.vh_magic = PED_CPU_TO_BE32 (VHMAGIC);
450
vh.vh_rootpt = PED_CPU_TO_BE16 (dvh_disk_data->root - 1);
451
vh.vh_swappt = PED_CPU_TO_BE16 (dvh_disk_data->swap - 1);
453
if (dvh_disk_data->boot) {
454
PedPartition* boot_part;
455
boot_part = ped_disk_get_partition (disk, dvh_disk_data->boot);
456
strcpy (vh.vh_bootfile, ped_partition_get_name (boot_part));
459
vh.vh_dp = dvh_disk_data->dev_params;
460
/* Set up rudimentary device geometry */
462
= PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.cylinders);
463
vh.vh_dp.dp_trks0 = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.heads);
465
= PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.sectors);
466
vh.vh_dp.dp_secbytes = PED_CPU_TO_BE16 ((short)disk->dev->sector_size);
468
for (i = 0; i < NPARTAB; i++) {
469
PedPartition* part = ped_disk_get_partition (disk, i + 1);
471
_generate_partition (part, &vh.vh_pt[i]);
474
/* whole disk partition
475
* This is only ever written here, and never modified
476
* (or even shown) as it must contain the entire disk,
477
* and parted does not like overlapping partitions
479
vh.vh_pt[PNUM_VOLUME].pt_nblks = PED_CPU_TO_BE32 (disk->dev->length);
480
vh.vh_pt[PNUM_VOLUME].pt_firstlbn = PED_CPU_TO_BE32 (0);
481
vh.vh_pt[PNUM_VOLUME].pt_type = PED_CPU_TO_BE32 (PTYPE_VOLUME);
483
for (i = 0; i < NVDIR; i++) {
484
PedPartition* part = ped_disk_get_partition (disk,
487
_generate_boot_file (part, &vh.vh_vd[i]);
491
vh.vh_csum = PED_CPU_TO_BE32 (_checksum ((uint32_t*) &vh,
492
sizeof (struct volume_header)));
494
return (ptt_write_sector (disk, &vh, sizeof vh)
495
&& ped_device_sync (disk->dev));
497
#endif /* !DISCOVER_ONLY */
500
dvh_partition_new (const PedDisk* disk, PedPartitionType part_type,
501
const PedFileSystemType* fs_type,
502
PedSector start, PedSector end)
505
DVHPartData* dvh_part_data;
507
part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
511
if (!ped_partition_is_active (part)) {
512
part->disk_specific = NULL;
516
dvh_part_data = part->disk_specific =
517
ped_malloc (sizeof (DVHPartData));
519
goto error_free_part;
521
dvh_part_data->type = (part_type == PED_PARTITION_EXTENDED)
524
strcpy (dvh_part_data->name, "");
525
dvh_part_data->real_file_size = part->geom.length * 512;
529
_ped_partition_free (part);
535
dvh_partition_duplicate (const PedPartition* part)
537
PedPartition* result;
538
DVHPartData* part_data = part->disk_specific;
539
DVHPartData* result_data;
541
result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
542
part->geom.start, part->geom.end);
545
result->num = part->num;
547
if (!ped_partition_is_active (part)) {
548
result->disk_specific = NULL;
552
result_data = result->disk_specific =
553
ped_malloc (sizeof (DVHPartData));
555
goto error_free_part;
557
result_data->type = part_data->type;
558
strcpy (result_data->name, part_data->name);
559
result_data->real_file_size = part_data->real_file_size;
563
_ped_partition_free (result);
569
dvh_partition_destroy (PedPartition* part)
571
if (ped_partition_is_active (part)) {
572
PED_ASSERT (part->disk_specific != NULL);
573
free (part->disk_specific);
575
_ped_partition_free (part);
579
dvh_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
581
DVHPartData* dvh_part_data = part->disk_specific;
583
part->fs_type = fs_type;
585
if (part->type == PED_PARTITION_EXTENDED) {
586
dvh_part_data->type = PTYPE_VOLHDR;
590
/* Is this a bootfile? */
591
if (part->type == PED_PARTITION_LOGICAL)
594
if (fs_type && !strcmp (fs_type->name, "xfs"))
595
dvh_part_data->type = PTYPE_XFS;
597
dvh_part_data->type = PTYPE_RAW;
602
dvh_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
604
DVHDiskData* dvh_disk_data = part->disk->disk_specific;
607
case PED_PARTITION_ROOT:
608
if (part->type != 0 && state) {
609
#ifndef DISCOVER_ONLY
610
ped_exception_throw (
612
PED_EXCEPTION_CANCEL,
613
_("Only primary partitions can be root "
618
dvh_disk_data->root = state ? part->num : 0;
621
case PED_PARTITION_SWAP:
622
if (part->type != 0 && state) {
623
#ifndef DISCOVER_ONLY
624
ped_exception_throw (
626
PED_EXCEPTION_CANCEL,
627
_("Only primary partitions can be swap "
632
dvh_disk_data->swap = state ? part->num : 0;
635
case PED_PARTITION_BOOT:
636
if (part->type != PED_PARTITION_LOGICAL && state) {
637
#ifndef DISCOVER_ONLY
638
ped_exception_throw (
640
PED_EXCEPTION_CANCEL,
641
_("Only logical partitions can be a boot "
646
dvh_disk_data->boot = state ? part->num : 0;
649
case PED_PARTITION_LVM:
650
case PED_PARTITION_LBA:
651
case PED_PARTITION_HIDDEN:
652
case PED_PARTITION_RAID:
659
static int _GL_ATTRIBUTE_PURE
660
dvh_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
662
DVHDiskData* dvh_disk_data = part->disk->disk_specific;
665
case PED_PARTITION_ROOT:
666
return dvh_disk_data->root == part->num;
668
case PED_PARTITION_SWAP:
669
return dvh_disk_data->swap == part->num;
671
case PED_PARTITION_BOOT:
672
return dvh_disk_data->boot == part->num;
674
case PED_PARTITION_LVM:
675
case PED_PARTITION_LBA:
676
case PED_PARTITION_HIDDEN:
677
case PED_PARTITION_RAID:
685
dvh_partition_is_flag_available (const PedPartition* part,
686
PedPartitionFlag flag)
689
case PED_PARTITION_ROOT:
690
case PED_PARTITION_SWAP:
691
case PED_PARTITION_BOOT:
694
case PED_PARTITION_LVM:
695
case PED_PARTITION_LBA:
696
case PED_PARTITION_HIDDEN:
697
case PED_PARTITION_RAID:
705
dvh_partition_set_name (PedPartition* part, const char* name)
707
DVHPartData* dvh_part_data = part->disk_specific;
709
if (part->type == PED_PARTITION_LOGICAL) {
711
strncpy (dvh_part_data->name, name, VDNAMESIZE);
712
dvh_part_data->name[VDNAMESIZE] = 0;
714
#ifndef DISCOVER_ONLY
715
ped_exception_throw (
717
PED_EXCEPTION_CANCEL,
718
_("failed to set dvh partition name to %s:\n"
719
"Only logical partitions (boot files) have a name."),
726
dvh_partition_get_name (const PedPartition* part)
728
DVHPartData* dvh_part_data = part->disk_specific;
729
return dvh_part_data->name;
732
/* The constraint for the volume header partition is different, because it must
733
* contain the first sector of the disk.
735
static PedConstraint*
736
_get_extended_constraint (PedDisk* disk)
738
PedGeometry min_geom;
739
if (!ped_geometry_init (&min_geom, disk->dev, 0, 1))
741
return ped_constraint_new_from_min (&min_geom);
744
static PedConstraint*
745
_get_primary_constraint (PedDisk* disk)
747
PedGeometry max_geom;
748
if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1))
750
return ped_constraint_new_from_max (&max_geom);
754
dvh_partition_align (PedPartition* part, const PedConstraint* constraint)
756
PED_ASSERT (part != NULL);
758
if (_ped_partition_attempt_align (
760
(part->type == PED_PARTITION_EXTENDED)
761
? _get_extended_constraint (part->disk)
762
: _get_primary_constraint (part->disk)))
765
#ifndef DISCOVER_ONLY
766
ped_exception_throw (
768
PED_EXCEPTION_CANCEL,
769
_("Unable to satisfy all constraints on the partition."));
775
dvh_partition_enumerate (PedPartition* part)
779
/* never change the partition numbers */
783
_flush_stale_flags (part->disk);
785
if (part->type & PED_PARTITION_LOGICAL) {
787
for (i = 1 + NPARTAB; i <= NPARTAB + NVDIR; i++) {
788
if (!ped_disk_get_partition (part->disk, i)) {
794
} else if (part->type & PED_PARTITION_EXTENDED) {
796
part->num = PNUM_VOLHDR + 1;
798
for (i = 1; i <= NPARTAB; i++) {
799
/* reserved for full volume partition */
800
if (i == PNUM_VOLUME + 1)
803
if (!ped_disk_get_partition (part->disk, i)) {
808
ped_exception_throw (
810
PED_EXCEPTION_CANCEL,
811
_("Too many primary partitions"));
818
dvh_get_max_primary_partition_count (const PedDisk* disk)
824
dvh_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
832
dvh_alloc_metadata (PedDisk* disk)
835
PedPartition* extended_part;
836
PedPartitionType metadata_type;
837
PED_ASSERT(disk != NULL);
839
/* We don't need to "protect" the start of the disk from the volume
842
extended_part = ped_disk_extended_partition (disk);
843
if (extended_part && extended_part->geom.start == 0)
844
metadata_type = PED_PARTITION_METADATA | PED_PARTITION_LOGICAL;
846
metadata_type = PED_PARTITION_METADATA;
848
part = ped_partition_new (disk, metadata_type, NULL, 0, 0);
852
PedConstraint *constraint_exact
853
= ped_constraint_exact (&part->geom);
854
bool ok = ped_disk_add_partition (disk, part, constraint_exact);
855
ped_constraint_destroy (constraint_exact);
859
ped_partition_destroy (part);
864
#include "pt-common.h"
865
PT_define_limit_functions (dvh)
867
static PedDiskOps dvh_disk_ops = {
869
write: NULL_IF_DISCOVER_ONLY (dvh_write),
871
partition_set_name: dvh_partition_set_name,
872
partition_get_name: dvh_partition_get_name,
873
PT_op_function_initializers (dvh)
876
static PedDiskType dvh_disk_type = {
880
features: PED_DISK_TYPE_PARTITION_NAME | PED_DISK_TYPE_EXTENDED
886
PED_ASSERT (sizeof (struct volume_header) == 512);
888
ped_disk_type_register (&dvh_disk_type);
894
ped_disk_type_unregister (&dvh_disk_type);