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