OSDN Git Service

de2c3d28695457f1d4a6b9b29df1fb077e41f9a5
[android-x86/external-parted.git] / libparted / disk.c
1  /*
2     libparted - a library for manipulating disk partitions
3     Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005
4                   Free Software Foundation, Inc.
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 /** \file disk.c */
22
23 /**
24  * \addtogroup PedDisk
25  *
26  * \brief Disk label access.
27  * 
28  * Most programs will need to use ped_disk_new() or ped_disk_new_fresh() to get
29  * anything done.  A PedDisk is always associated with a device and has a
30  * partition table.  There are different types of partition tables (or disk
31  * labels).  These are represented by the PedDiskType enumeration.
32  *
33  * @{
34  */
35
36 #include "config.h"
37
38 #include <parted/parted.h>
39 #include <parted/debug.h>
40
41 #if ENABLE_NLS
42 #  include <libintl.h>
43 #  define _(String) dgettext (PACKAGE, String)
44 #  define N_(String) (String)
45 #else
46 #  define _(String) (String)
47 #  define N_(String) (String)
48 #endif /* ENABLE_NLS */
49
50 /* UPDATE MODE functions */
51 #ifdef DEBUG
52 static int _disk_check_sanity (PedDisk* disk);
53 #endif
54 static void _disk_push_update_mode (PedDisk* disk);
55 static void _disk_pop_update_mode (PedDisk* disk);
56 static int _disk_raw_insert_before (PedDisk* disk, PedPartition* loc,
57                                     PedPartition* part);
58 static int _disk_raw_insert_after (PedDisk* disk, PedPartition* loc,
59                                    PedPartition* part);
60 static int _disk_raw_remove (PedDisk* disk, PedPartition* part);
61 static int _disk_raw_add (PedDisk* disk, PedPartition* part);
62
63 static PedDiskType*     disk_types = NULL;
64
65 void
66 ped_disk_type_register (PedDiskType* disk_type)
67 {
68         PED_ASSERT (disk_type != NULL, return);
69         PED_ASSERT (disk_type->ops != NULL, return);
70         PED_ASSERT (disk_type->name != NULL, return);
71         
72         /* pretend that "next" isn't part of the struct :-) */
73         ((struct _PedDiskType*) disk_type)->next = disk_types;
74         disk_types = (struct _PedDiskType*) disk_type;
75 }
76
77 void
78 ped_disk_type_unregister (PedDiskType* disk_type)
79 {
80         PedDiskType*    walk;
81         PedDiskType*    last = NULL;
82
83         PED_ASSERT (disk_types != NULL, return);
84         PED_ASSERT (disk_type != NULL, return);
85
86         for (walk = disk_types; walk && walk != disk_type;
87                 last = walk, walk = walk->next);
88
89         PED_ASSERT (walk != NULL, return);
90         if (last)
91                 ((struct _PedDiskType*) last)->next = disk_type->next;
92         else
93                 disk_types = disk_type->next;
94 }
95
96 /**
97  * Deprecated: use ped_disk_type_regiser.
98  */
99 void
100 ped_register_disk_type (PedDiskType* disk_type)
101 {
102         ped_disk_type_register (disk_type);
103 }
104
105 /**
106  * Deprecated: use ped_disk_type_unregiser.
107  */
108 void
109 ped_unregister_disk_type (PedDiskType* disk_type)
110 {
111         ped_disk_type_unregister (disk_type);
112 }
113
114 /**
115  * Return the next disk type registers, after "type".  If "type" is
116  * NULL, returns the first disk type.
117  *
118  * \return Next disk; NULL if "type" is the last registered disk type.
119  */
120 PedDiskType*
121 ped_disk_type_get_next (PedDiskType* type)
122 {
123         if (type)
124                 return type->next;
125         else
126                 return disk_types;
127 }
128
129 /**
130  * Return the disk type with a name of "name".
131  *
132  * \return Disk type; NULL if no match.
133  */
134 PedDiskType*
135 ped_disk_type_get (const char* name)
136 {
137         PedDiskType*    walk = NULL;
138
139         PED_ASSERT (name != NULL, return NULL);
140
141         for (walk = ped_disk_type_get_next (NULL); walk;
142              walk = ped_disk_type_get_next (walk))
143                         if (strcasecmp (walk->name, name) == 0)
144                                         break;
145
146         return walk;
147 }
148
149 /**
150  * Return the type of partition table detected on "dev".
151  *
152  * \return Type; NULL if none was detected.
153  */
154 PedDiskType*
155 ped_disk_probe (PedDevice* dev)
156 {
157         PedDiskType*    walk = NULL;
158
159         PED_ASSERT (dev != NULL, return NULL);
160
161         if (!ped_device_open (dev))
162                 return NULL;
163
164         ped_exception_fetch_all ();
165         for (walk = ped_disk_type_get_next (NULL); walk;
166              walk = ped_disk_type_get_next (walk))
167                         if (walk->ops->probe (dev))
168                                         break;
169
170         if (ped_exception)
171                 ped_exception_catch ();
172         ped_exception_leave_all ();
173
174         ped_device_close (dev);
175         return walk;
176 }
177
178 /**
179  * Read the partition table off a device (if one is found). 
180  * 
181  * \warning May modify \p dev->cylinders, \p dev->heads and \p dev->sectors
182  *      if the partition table indicates that the existing values
183  *      are incorrect.
184  * 
185  * \return A new \link _PedDisk PedDisk \endlink object;
186  *         NULL on failure (e.g. partition table not detected).
187  */
188 PedDisk*
189 ped_disk_new (PedDevice* dev)
190 {
191         PedDiskType*    type;
192         PedDisk*        disk;
193
194         PED_ASSERT (dev != NULL, return NULL);
195
196         if (!ped_device_open (dev))
197                 goto error;
198
199         type = ped_disk_probe (dev);
200         if (!type) {
201                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
202                         _("Unable to open %s - unrecognised disk label."),
203                         dev->path);
204                 goto error_close_dev;
205         }
206         disk = ped_disk_new_fresh (dev, type);
207         if (!disk)
208                 goto error_close_dev;
209         if (!type->ops->read (disk))
210                 goto error_destroy_disk;
211         disk->needs_clobber = 0;
212         ped_device_close (dev);
213         return disk;
214
215 error_destroy_disk:
216         ped_disk_destroy (disk);
217 error_close_dev:
218         ped_device_close (dev);
219 error:
220         return NULL;
221 }
222
223 static int
224 _add_duplicate_part (PedDisk* disk, PedPartition* old_part)
225 {
226         PedPartition*   new_part;
227         PedConstraint*  constraint_exact;
228
229         new_part = disk->type->ops->partition_duplicate (old_part);
230         if (!new_part)
231                 goto error;
232         new_part->disk = disk;
233
234         constraint_exact = ped_constraint_exact (&new_part->geom);
235         if (!constraint_exact)
236                 goto error_destroy_new_part;
237         if (!ped_disk_add_partition (disk, new_part, constraint_exact))
238                 goto error_destroy_constraint_exact;
239         ped_constraint_destroy (constraint_exact);
240         return 1;
241
242 error_destroy_constraint_exact:
243         ped_constraint_destroy (constraint_exact);
244 error_destroy_new_part:
245         ped_partition_destroy (new_part);
246 error:
247         return 0;
248 }
249
250 /**
251  * Clone a \link _PedDisk PedDisk \endlink object.
252  *
253  * \return Deep copy of \p old_disk, NULL on failure.
254  */
255 PedDisk*
256 ped_disk_duplicate (const PedDisk* old_disk)
257 {
258         PedDisk*        new_disk;
259         PedPartition*   old_part;
260
261         PED_ASSERT (old_disk != NULL, return NULL);
262         PED_ASSERT (!old_disk->update_mode, return NULL);
263         PED_ASSERT (old_disk->type->ops->duplicate != NULL, return NULL);
264         PED_ASSERT (old_disk->type->ops->partition_duplicate != NULL,
265                     return NULL);
266
267         new_disk = old_disk->type->ops->duplicate (old_disk);
268         if (!new_disk)
269                 goto error;
270
271         _disk_push_update_mode (new_disk);
272         for (old_part = ped_disk_next_partition (old_disk, NULL); old_part;
273              old_part = ped_disk_next_partition (old_disk, old_part)) {
274                 if (ped_partition_is_active (old_part)) {
275                         if (!_add_duplicate_part (new_disk, old_part))
276                                 goto error_destroy_new_disk;
277                 }
278         }
279         _disk_pop_update_mode (new_disk);
280         return new_disk;
281
282 error_destroy_new_disk:
283         ped_disk_destroy (new_disk);
284 error:
285         return NULL;
286 }
287
288 /**
289  * Remove all identifying signatures of a partition table,
290  * except for partition tables of a given type.
291  * 
292  * \return 0 on error, 1 otherwise.
293  * 
294  * \sa ped_disk_clobber()
295  */
296 int
297 ped_disk_clobber_exclude (PedDevice* dev, const PedDiskType* exclude)
298 {
299         PedDiskType*    walk;
300
301         PED_ASSERT (dev != NULL, goto error);
302
303         if (!ped_device_open (dev))
304                 goto error;
305
306         for (walk = ped_disk_type_get_next (NULL); walk;
307              walk = ped_disk_type_get_next (walk)) {
308                 int     probed;
309
310                 if (walk == exclude)
311                         continue;
312
313                 ped_exception_fetch_all ();
314                 probed = walk->ops->probe (dev);
315                 if (!probed)
316                         ped_exception_catch ();
317                 ped_exception_leave_all ();
318
319                 if (probed && walk->ops->clobber) {
320                         if (!walk->ops->clobber (dev))
321                                 goto error_close_dev;
322                 }
323         }
324         ped_device_close (dev);
325         return 1;
326
327 error_close_dev:
328         ped_device_close (dev);
329 error:
330         return 0;
331 }
332
333 /** 
334  * Remove all identifying signatures of a partition table,
335  * 
336  * \return 0 on error, 1 otherwise.
337  * 
338  * \sa ped_disk_clobber_exclude()
339  */
340 int
341 ped_disk_clobber (PedDevice* dev)
342 {
343         return ped_disk_clobber_exclude (dev, NULL);
344 }
345
346 /**
347  * Create a new partition table on \p dev.
348  *
349  * This new partition table is only created in-memory, and nothing is written
350  * to disk until ped_disk_commit_to_dev() is called.
351  * 
352  * \return The newly constructed \link _PedDisk PedDisk \endlink,
353  *      NULL on failure.
354  */
355 PedDisk*
356 ped_disk_new_fresh (PedDevice* dev, const PedDiskType* type)
357 {
358         PedDisk*        disk;
359
360         PED_ASSERT (dev != NULL, return NULL);
361         PED_ASSERT (type != NULL, return NULL);
362         PED_ASSERT (type->ops->alloc != NULL, return NULL);
363
364         disk = type->ops->alloc (dev);
365         if (!disk)
366                 goto error;
367         _disk_pop_update_mode (disk);
368         PED_ASSERT (disk->update_mode == 0, goto error_destroy_disk);
369
370         disk->needs_clobber = 1;
371         return disk;
372
373 error_destroy_disk:
374         ped_disk_destroy (disk);
375 error:
376         return NULL;
377 }
378
379 PedDisk*
380 _ped_disk_alloc (const PedDevice* dev, const PedDiskType* disk_type)
381 {
382         PedDisk*        disk;
383
384         disk = (PedDisk*) ped_malloc (sizeof (PedDisk));
385         if (!disk)
386                 goto error;
387
388         disk->dev = (PedDevice*)dev;
389         disk->type = disk_type;
390         disk->update_mode = 1;
391         disk->part_list = NULL;
392         return disk;
393
394 error_free_disk:
395         ped_free (disk);
396 error:
397         return NULL;
398 }
399
400 void
401 _ped_disk_free (PedDisk* disk)
402 {
403         _disk_push_update_mode (disk);
404         ped_disk_delete_all (disk);
405         ped_free (disk);
406 }
407
408 /**
409  * Close \p disk.
410  *
411  * What this function does depends on the PedDiskType of \p disk,
412  * but you can generally assume that outstanding writes are flushed
413  * (this mainly means that _ped_disk_free is called).
414  */
415 void
416 ped_disk_destroy (PedDisk* disk)
417 {
418         PED_ASSERT (disk != NULL, return);
419         PED_ASSERT (!disk->update_mode, return);
420
421         disk->type->ops->free (disk);
422 }
423
424 /**
425  * Tell the operating system kernel about the partition table layout
426  * of \p disk.
427  *
428  * This is rather loosely defined: for example, on old versions of Linux,
429  * it simply calls the BLKRRPART ioctl, which tells the kernel to
430  * reread the partition table. On newer versions (2.4.x), it will
431  * use the new blkpg interface to tell Linux where each partition
432  * starts/ends, etc. In this case, Linux does not need to have support for
433  * a specific type of partition table.
434  * 
435  * \return 0 on failure, 1 otherwise.
436  */
437 int
438 ped_disk_commit_to_os (PedDisk* disk)
439 {
440         PED_ASSERT (disk != NULL, return 0);
441
442         if (!ped_device_open (disk->dev))
443                 goto error;
444         if (!ped_architecture->disk_ops->disk_commit (disk))
445                 goto error_close_dev;
446         ped_device_close (disk->dev);
447         return 1;
448
449 error_close_dev:
450         ped_device_close (disk->dev);
451 error:
452         return 0;
453 }
454
455 /**
456  * Write the changes made to the in-memory description
457  * of a partition table to the device.
458  *
459  * \return 0 on failure, 1 otherwise.
460  */
461 int
462 ped_disk_commit_to_dev (PedDisk* disk)
463 {
464         PED_ASSERT (disk != NULL, goto error);
465         PED_ASSERT (!disk->update_mode, goto error);
466
467         if (!disk->type->ops->write) {
468                 ped_exception_throw (
469                         PED_EXCEPTION_ERROR,
470                         PED_EXCEPTION_CANCEL,
471                         _("This libparted doesn't have write support for "
472                           "%s.  Perhaps it was compiled read-only."),
473                         disk->type->name);
474                 goto error;
475         }
476
477         if (!ped_device_open (disk->dev))
478                 goto error;
479
480         if (disk->needs_clobber) {
481                 if (!ped_disk_clobber_exclude (disk->dev, disk->type))
482                         goto error_close_dev;
483                 disk->needs_clobber = 0;
484         }
485         if (!disk->type->ops->write (disk))
486                 goto error_close_dev;
487         ped_device_close (disk->dev);
488         return 1;
489
490 error_close_dev:
491         ped_device_close (disk->dev);
492 error:
493         return 0;
494 }
495
496 /*
497  * This function writes the in-memory changes to a partition table to
498  * disk and informs the operating system of the changes.
499  *
500  * \note Equivalent to calling first ped_disk_commit_to_dev(), then
501  *      ped_disk_commit_to_os().
502  *
503  * \return 0 on failure, 1 otherwise.
504  */
505 int
506 ped_disk_commit (PedDisk* disk)
507 {
508         if (!ped_disk_commit_to_dev (disk))
509                 return 0;
510         return ped_disk_commit_to_os (disk);
511 }
512
513 /**
514  * \addtogroup PedPartition
515  *
516  * @{
517  */
518
519 /**
520  * Check whether a partition is mounted or busy in some
521  * other way.
522  *
523  * \note An extended partition is busy if any logical partitions are mounted.
524  *
525  * \return \c 1 if busy.
526  */
527 int
528 ped_partition_is_busy (const PedPartition* part)
529 {
530         PED_ASSERT (part != NULL, return 1);
531
532         return ped_architecture->disk_ops->partition_is_busy (part);
533 }
534
535 /**
536  * Return a path that can be used to address the partition in the
537  * operating system.
538  */
539 char*
540 ped_partition_get_path (const PedPartition* part)
541 {
542         PED_ASSERT (part != NULL, return NULL);
543
544         return ped_architecture->disk_ops->partition_get_path (part);
545 }
546
547 /** @} */
548
549 /**
550  * \addtogroup PedDisk
551  *
552  * @{
553  */
554
555 /**
556  * Perform a sanity check on a partition table.
557  *
558  * \note The check performed is generic (i.e. it does not depends on the label
559  *      type of the disk.
560  *
561  * \throws PED_EXCEPTION_WARNING if a partition type ID does not match the file
562  *      system on it.
563  *
564  * \return 0 if the check fails, 1 otherwise.
565  */
566 int
567 ped_disk_check (PedDisk* disk)
568 {
569         PedPartition*   walk;
570
571         PED_ASSERT (disk != NULL, return 0);
572
573         for (walk = disk->part_list; walk;
574              walk = ped_disk_next_partition (disk, walk)) {
575                 const PedFileSystemType*        fs_type = walk->fs_type;
576                 PedGeometry*                    geom;
577                 PedSector                       length_error;
578                 PedSector                       max_length_error;
579
580                 if (!ped_partition_is_active (walk) || !fs_type)
581                         continue;
582
583                 geom = ped_file_system_probe_specific (fs_type, &walk->geom);
584                 if (!geom)
585                         continue;
586
587                 length_error = abs (walk->geom.length - geom->length);
588                 max_length_error = PED_MAX (4096, walk->geom.length / 100);
589                 if (!ped_geometry_test_inside (&walk->geom, geom)
590                     || length_error > max_length_error) {
591                         char* part_size = ped_unit_format (disk->dev, walk->geom.length);
592                         char* fs_size = ped_unit_format (disk->dev, geom->length);
593                         PedExceptionOption choice;
594
595                         choice = ped_exception_throw (
596                                 PED_EXCEPTION_WARNING,
597                                 PED_EXCEPTION_IGNORE_CANCEL,
598                                 _("Partition %d is %s, but the file system is "
599                                   "%s."),
600                                 walk->num, part_size, fs_size);
601
602                         ped_free (part_size);
603                         ped_free (fs_size);
604
605                         if (choice != PED_EXCEPTION_IGNORE)
606                                 return 0;
607                 }
608         }
609
610         return 1;
611 }
612
613 /**
614  * This function checks if a particular type of partition table supports
615  * a feature.
616  *
617  * \return 1 if \p disk_type supports \p feature, 0 otherwise.
618  */
619 int
620 ped_disk_type_check_feature (const PedDiskType* disk_type,
621                              PedDiskTypeFeature feature)
622 {
623         return (disk_type->features & feature) != 0;
624 }
625
626 /**
627  * Get the number of primary partitions.
628  */
629 int
630 ped_disk_get_primary_partition_count (PedDisk* disk)
631 {
632         PedPartition*   walk;
633         int             count = 0;
634
635         PED_ASSERT (disk != NULL, return 0);
636
637         for (walk = disk->part_list; walk;
638              walk = ped_disk_next_partition (disk, walk)) {
639                 if (ped_partition_is_active (walk)
640                                 && ! (walk->type & PED_PARTITION_LOGICAL))
641                         count++;
642         }
643
644         return count;
645 }
646
647 /**
648  * Get the highest partition number on \p disk.
649  */
650 int
651 ped_disk_get_last_partition_num (PedDisk* disk)
652 {
653         PedPartition*   walk;
654         int             highest = -1;
655
656         PED_ASSERT (disk != NULL, return 0);
657
658         for (walk = disk->part_list; walk;
659              walk = ped_disk_next_partition (disk, walk)) {
660                 if (walk->num > highest)
661                         highest = walk->num;
662         }
663
664         return highest;
665 }
666
667 /**
668  * Get the maximum number of (primary) partitions the disk label supports.
669  * 
670  * For example, MacIntosh partition maps can have different sizes,
671  * and accordingly support a different number of partitions.
672  */
673 int
674 ped_disk_get_max_primary_partition_count (const PedDisk* disk)
675 {
676         PED_ASSERT (disk->type != NULL, return 0);
677         PED_ASSERT (disk->type->ops->get_max_primary_partition_count != NULL,
678                     return 0);
679
680         return disk->type->ops->get_max_primary_partition_count (disk);
681 }
682
683 /**
684  * \internal We turned a really nasty bureaucracy problem into an elegant maths
685  * problem :-)  Basically, there are some constraints to a partition's
686  * geometry:
687  *
688  * (1) it must start and end on a "disk" block, determined by the disk label
689  * (not the hardware).  (constraint represented by a PedAlignment)
690  *
691  * (2) if we're resizing a partition, we MIGHT need to keep each block aligned.
692  * Eg: if an ext2 file system has 4k blocks, then we can only move the start
693  * by a multiple of 4k.  (constraint represented by a PedAlignment)
694  *
695  * (3) we need to keep the start and end within the device's physical
696  * boundaries.  (constraint represented by a PedGeometry)
697  *
698  * Satisfying (1) and (2) simultaneously required a bit of fancy maths ;-)  See
699  * ped_alignment_intersect()
700  *
701  * The application of these constraints is in disk_*.c's *_partition_align()
702  * function.
703  */
704 static int
705 _partition_align (PedPartition* part, const PedConstraint* constraint)
706 {
707         const PedDiskType*      disk_type;
708
709         PED_ASSERT (part != NULL, return 0);
710         PED_ASSERT (part->num != -1, return 0);
711         PED_ASSERT (part->disk != NULL, return 0);
712         disk_type = part->disk->type;
713         PED_ASSERT (disk_type != NULL, return 0);
714         PED_ASSERT (disk_type->ops->partition_align != NULL, return 0);
715         PED_ASSERT (part->disk->update_mode, return 0);
716
717         return disk_type->ops->partition_align (part, constraint);
718 }
719
720 static int
721 _partition_enumerate (PedPartition* part)
722 {
723         const PedDiskType*      disk_type;
724
725         PED_ASSERT (part != NULL, return 0);
726         PED_ASSERT (part->disk != NULL, return 0);
727         disk_type = part->disk->type;
728         PED_ASSERT (disk_type != NULL, return 0);
729         PED_ASSERT (disk_type->ops->partition_enumerate != NULL, return 0);
730
731         return disk_type->ops->partition_enumerate (part);
732 }
733
734 /**
735  * Gives all the (active) partitions a number.  It should preserve the numbers
736  * and orders as much as possible.
737  */
738 static int
739 ped_disk_enumerate_partitions (PedDisk* disk)
740 {
741         PedPartition*   walk;
742         int             i;
743         int             end;
744
745         PED_ASSERT (disk != NULL, return 0);
746
747 /* first "sort" already-numbered partitions.  (e.g. if a logical partition
748  * is removed, then all logical partitions that were number higher MUST be
749  * renumbered)
750  */
751         end = ped_disk_get_last_partition_num (disk);
752         for (i=1; i<=end; i++) {
753                 walk = ped_disk_get_partition (disk, i);
754                 if (walk) {
755                         if (!_partition_enumerate (walk))
756                                 return 0;
757                 }
758         }
759
760 /* now, number un-numbered partitions */
761         for (walk = disk->part_list; walk;
762              walk = ped_disk_next_partition (disk, walk)) {
763                 if (ped_partition_is_active (walk) && walk->num == -1) {
764                         if (!_partition_enumerate (walk))
765                                 return 0;
766                 }
767         }
768
769         return 1;
770 }
771
772 static int
773 _disk_remove_metadata (PedDisk* disk)
774 {
775         PedPartition*   walk = NULL;
776         PedPartition*   next;
777
778         PED_ASSERT (disk != NULL, return 0);
779
780         next = ped_disk_next_partition (disk, walk);
781
782         while (next) {
783                 walk = next;
784                 while (1) {
785                         next = ped_disk_next_partition (disk, next);
786                         if (!next || next->type & PED_PARTITION_METADATA)
787                                 break;
788                 }
789                 if (walk->type & PED_PARTITION_METADATA)
790                         ped_disk_delete_partition (disk, walk);
791         }
792         return 1;
793 }
794
795 static int
796 _disk_alloc_metadata (PedDisk* disk)
797 {
798         PED_ASSERT (disk != NULL, return 0);
799
800         if (!disk->update_mode)
801                 _disk_remove_metadata (disk);
802
803         return disk->type->ops->alloc_metadata (disk);
804 }
805
806 static int
807 _disk_remove_freespace (PedDisk* disk)
808 {
809         PedPartition*   walk;
810         PedPartition*   next;
811
812         walk = ped_disk_next_partition (disk, NULL);
813         for (; walk; walk = next) {
814                 next = ped_disk_next_partition (disk, walk);
815
816                 if (walk->type & PED_PARTITION_FREESPACE) {
817                         _disk_raw_remove (disk, walk);
818                         ped_partition_destroy (walk);
819                 }
820         }
821
822         return 1;
823 }
824
825 static int
826 _alloc_extended_freespace (PedDisk* disk)
827 {
828         PedSector       last_end;
829         PedPartition*   walk;
830         PedPartition*   last;
831         PedPartition*   free_space;
832         PedPartition*   extended_part;
833
834         extended_part = ped_disk_extended_partition (disk);
835         if (!extended_part)
836                 return 1;
837
838         last_end = extended_part->geom.start;
839         last = NULL;
840         
841         for (walk = extended_part->part_list; walk; walk = walk->next) {
842                 if (walk->geom.start > last_end + 1) {
843                         free_space = ped_partition_new (
844                                         disk,
845                                         PED_PARTITION_FREESPACE
846                                                 | PED_PARTITION_LOGICAL,
847                                         NULL,
848                                         last_end + 1, walk->geom.start - 1);
849                         _disk_raw_insert_before (disk, walk, free_space);
850                 }
851
852                 last = walk;
853                 last_end = last->geom.end;
854         }
855
856         if (last_end < extended_part->geom.end) {
857                 free_space = ped_partition_new (
858                                 disk,
859                                 PED_PARTITION_FREESPACE | PED_PARTITION_LOGICAL,
860                                 NULL,
861                                 last_end + 1, extended_part->geom.end);
862
863                 if (last)
864                         return _disk_raw_insert_after (disk, last, free_space);
865                 else
866                         extended_part->part_list = free_space;
867         }
868
869         return 1;
870 }
871
872 static int
873 _disk_alloc_freespace (PedDisk* disk)
874 {
875         PedSector       last_end;
876         PedPartition*   walk;
877         PedPartition*   last;
878         PedPartition*   free_space;
879
880         if (!_disk_remove_freespace (disk))
881                 return 0;
882         if (!_alloc_extended_freespace (disk))
883                 return 0;
884
885         last = NULL;
886         last_end = -1;
887
888         for (walk = disk->part_list; walk; walk = walk->next) {
889                 if (walk->geom.start > last_end + 1) {
890                         free_space = ped_partition_new (disk,
891                                         PED_PARTITION_FREESPACE, NULL,
892                                         last_end + 1, walk->geom.start - 1);
893                         _disk_raw_insert_before (disk, walk, free_space);
894                 }
895
896                 last = walk;
897                 last_end = last->geom.end;
898         }
899
900         if (last_end < disk->dev->length - 1) {
901                 free_space = ped_partition_new (disk,
902                                         PED_PARTITION_FREESPACE, NULL,
903                                         last_end + 1, disk->dev->length - 1);
904                 if (last)
905                         return _disk_raw_insert_after (disk, last, free_space);
906                 else
907                         disk->part_list = free_space;
908         }
909
910         return 1;
911 }
912
913 /**
914  * Update mode: used when updating the internal representation of the partition
915  * table.  In update mode, the metadata and freespace placeholder/virtual
916  * partitions are removed, making it much easier for various manipulation
917  * routines...
918  */
919 static void
920 _disk_push_update_mode (PedDisk* disk)
921 {
922         if (!disk->update_mode) {
923 #ifdef DEBUG
924                 _disk_check_sanity (disk);
925 #endif
926
927                 _disk_remove_freespace (disk);
928                 disk->update_mode++;
929                 _disk_remove_metadata (disk);
930
931 #ifdef DEBUG
932                 _disk_check_sanity (disk);
933 #endif
934         } else {
935                 disk->update_mode++;
936         }
937 }
938
939 static void
940 _disk_pop_update_mode (PedDisk* disk)
941 {
942         PED_ASSERT (disk->update_mode, return);
943
944         if (disk->update_mode == 1) {
945         /* re-allocate metadata BEFORE leaving update mode, to prevent infinite
946          * recursion (metadata allocation requires update mode)
947          */
948 #ifdef DEBUG
949                 _disk_check_sanity (disk);
950 #endif
951
952                 _disk_alloc_metadata (disk);
953                 disk->update_mode--;
954                 _disk_alloc_freespace (disk);
955
956 #ifdef DEBUG
957                 _disk_check_sanity (disk);
958 #endif
959         } else {
960                 disk->update_mode--;
961         }
962 }
963
964 /** @} */
965
966 /**
967  * \addtogroup PedPartition
968  *
969  * \brief Partition access.
970  * 
971  * @{
972  */
973
974 PedPartition*
975 _ped_partition_alloc (const PedDisk* disk, PedPartitionType type,
976                       const PedFileSystemType* fs_type,
977                       PedSector start, PedSector end)
978 {
979         PedPartition*   part;
980
981         PED_ASSERT (disk != NULL, return 0);
982
983         part = (PedPartition*) ped_malloc (sizeof (PedPartition));
984         if (!part)
985                 goto error;
986
987         part->prev = NULL;
988         part->next = NULL;
989
990         part->disk = (PedDisk*) disk;
991         if (!ped_geometry_init (&part->geom, disk->dev, start, end - start + 1))
992                 goto error_free_part;
993
994         part->num = -1;
995         part->type = type;
996         part->part_list = NULL;
997         part->fs_type = fs_type;
998
999         return part;
1000
1001 error_free_part:
1002         ped_free (part);
1003 error:
1004         return NULL;
1005 }
1006
1007 void
1008 _ped_partition_free (PedPartition* part)
1009 {
1010         ped_free (part);
1011 }
1012
1013 int
1014 _ped_partition_attempt_align (PedPartition* part,
1015                               const PedConstraint* external,
1016                               PedConstraint* internal)
1017 {
1018         PedConstraint*          intersection;
1019         PedGeometry*            solution;
1020
1021         intersection = ped_constraint_intersect (external, internal);
1022         ped_constraint_destroy (internal);
1023         if (!intersection)
1024                 goto fail;
1025
1026         solution = ped_constraint_solve_nearest (intersection, &part->geom);
1027         if (!solution)
1028                 goto fail_free_intersection;
1029         ped_geometry_set (&part->geom, solution->start, solution->length);
1030         ped_geometry_destroy (solution);
1031         ped_constraint_destroy (intersection);
1032         return 1;
1033
1034 fail_free_intersection:
1035         ped_constraint_destroy (intersection);
1036 fail:
1037         return 0;
1038 }
1039
1040 /**
1041  * Create a new \link _PedPartition PedPartition \endlink on \p disk.
1042  *
1043  * \param type One of \p PED_PARTITION_PRIMARY, \p PED_PARTITION_EXTENDED,
1044  *      \p PED_PARTITION_LOGICAL.
1045  *
1046  * \note The constructed partition is not added to <tt>disk</tt>'s
1047  *      partition table. Use ped_disk_add_partition() to do this.
1048  * 
1049  * \return A new \link _PedPartition PedPartition \endlink object,
1050  *      NULL on failure.
1051  *
1052  * \throws PED_EXCEPTION_ERROR if \p type is \p EXTENDED or \p LOGICAL but the
1053  *      label does not support this concept.
1054  */ 
1055 PedPartition*
1056 ped_partition_new (const PedDisk* disk, PedPartitionType type,
1057                    const PedFileSystemType* fs_type, PedSector start,
1058                    PedSector end)
1059 {
1060         int             supports_extended;
1061         PedPartition*   part;
1062
1063         PED_ASSERT (disk != NULL, return NULL);
1064         PED_ASSERT (disk->type->ops->partition_new != NULL, return NULL);
1065
1066         supports_extended = ped_disk_type_check_feature (disk->type,
1067                                 PED_DISK_TYPE_EXTENDED);
1068
1069         if (!supports_extended
1070             && (type == PED_PARTITION_EXTENDED
1071                         || type == PED_PARTITION_LOGICAL)) {
1072                 ped_exception_throw (
1073                         PED_EXCEPTION_ERROR,
1074                         PED_EXCEPTION_CANCEL,
1075                         _("%s disk labels do not support extended "
1076                           "partitions."),
1077                         disk->type->name);
1078                 goto error;
1079         }
1080
1081         part = disk->type->ops->partition_new (disk, type, fs_type, start, end);
1082         if (!part)
1083                 goto error;
1084
1085         if (fs_type || part->type == PED_PARTITION_EXTENDED) {
1086                 if (!ped_partition_set_system (part, fs_type))
1087                         goto error_destroy_part;
1088         }
1089         return part;
1090
1091 error_destroy_part:
1092         ped_partition_destroy (part);
1093 error:
1094         return NULL;
1095 }
1096
1097 /**
1098  * Destroy a \link _PedPartition PedPartition \endlink object.
1099  *
1100  * \note Should not be called on a partition that is in a partition table.
1101  *      Use ped_disk_delete_partition() instead.
1102  */
1103 void
1104 ped_partition_destroy (PedPartition* part)
1105 {
1106         PED_ASSERT (part != NULL, return);
1107         PED_ASSERT (part->disk != NULL, return);
1108         PED_ASSERT (part->disk->type->ops->partition_new != NULL, return);
1109
1110         part->disk->type->ops->partition_destroy (part);
1111 }
1112
1113
1114 /**
1115  * Return whether or not the partition is "active".
1116  *
1117  * A partition is active if \p part->type is neither \p PED_PARTITION_METADATA
1118  * nor \p PED_PARTITION_FREE.
1119  */
1120 int
1121 ped_partition_is_active (const PedPartition* part)
1122 {
1123         PED_ASSERT (part != NULL, return 0);
1124
1125         return !(part->type & PED_PARTITION_FREESPACE
1126                  || part->type & PED_PARTITION_METADATA);
1127 }
1128
1129 /**
1130  * Set the state (\c 1 or \c 0) of a flag on a partition.
1131  * 
1132  * Flags are disk label specific, although they have a global
1133  * "namespace": the flag PED_PARTITION_BOOT, for example, roughly means
1134  * "this" partition is bootable". But this means different things on different
1135  * disk labels (and may not be defined on some disk labels). For example,
1136  * on MS-DOS disk labels, there can only be one boot partition, and this
1137  * refers to the partition that will be booted from on startup. On PC98
1138  * disk labels, the user can choose from any bootable partition on startup.
1139  * 
1140  * \note It is an error to call this on an unavailable flag -- use
1141  * ped_partition_is_flag_available() to determine which flags are available
1142  * for a given disk label.
1143  *
1144  * \throws PED_EXCEPTION_ERROR if the requested flag is not available for this
1145  *      label.
1146  */
1147 int
1148 ped_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
1149 {
1150         PedDiskOps*     ops;
1151
1152         PED_ASSERT (part != NULL, return 0);
1153         PED_ASSERT (part->disk != NULL, return 0);
1154         PED_ASSERT (ped_partition_is_active (part), return 0);
1155
1156         ops = part->disk->type->ops;
1157         PED_ASSERT (ops->partition_set_flag != NULL, return 0);
1158         PED_ASSERT (ops->partition_is_flag_available != NULL, return 0);
1159
1160         if (!ops->partition_is_flag_available (part, flag)) {
1161                 ped_exception_throw (
1162                         PED_EXCEPTION_ERROR,
1163                         PED_EXCEPTION_CANCEL,
1164                         "The flag '%s' is not available for %s disk labels.",
1165                         ped_partition_flag_get_name (flag),
1166                         part->disk->type->name);
1167                 return 0;
1168         }
1169
1170         return ops->partition_set_flag (part, flag, state);
1171 }
1172
1173 /**
1174  * Get the state (\c 1 or \c 0) of a flag on a partition.
1175  *
1176  * See ped_partition_set_flag() for conditions that must hold.
1177  *
1178  * \todo Where's the check for flag availability?
1179  */
1180 int
1181 ped_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
1182 {
1183         PED_ASSERT (part != NULL, return 0);
1184         PED_ASSERT (part->disk != NULL, return 0);
1185         PED_ASSERT (part->disk->type->ops->partition_get_flag != NULL,
1186                     return 0);
1187         PED_ASSERT (ped_partition_is_active (part), return 0);
1188
1189         return part->disk->type->ops->partition_get_flag (part, flag);
1190 }
1191
1192 /**
1193  * Check whether a given flag is available on a partition.
1194  *
1195  * \return \c 1 if the flag is available.
1196  */
1197 int
1198 ped_partition_is_flag_available (const PedPartition* part,
1199                                  PedPartitionFlag flag)
1200 {
1201         PED_ASSERT (part != NULL, return 0);
1202         PED_ASSERT (part->disk != NULL, return 0);
1203         PED_ASSERT (part->disk->type->ops->partition_is_flag_available != NULL,
1204                     return 0);
1205         PED_ASSERT (ped_partition_is_active (part), return 0);
1206
1207         return part->disk->type->ops->partition_is_flag_available (part, flag);
1208 }
1209
1210 /**
1211  * Sets the system type on the partition to \p fs_type.
1212  *
1213  * \note The file system may be opened, to get more information about the
1214  * file system, e.g. to determine if it's FAT16 or FAT32.
1215  *
1216  * \return \c 0 on failure.
1217  */
1218 int
1219 ped_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1220 {
1221         PedFileSystem*          fs;
1222         const PedDiskType*      disk_type;
1223
1224         PED_ASSERT (part != NULL, return 0);
1225         PED_ASSERT (ped_partition_is_active (part), return 0);
1226         PED_ASSERT (part->disk != NULL, return 0);
1227         disk_type = part->disk->type;
1228         PED_ASSERT (disk_type != NULL, return 0);
1229         PED_ASSERT (disk_type->ops != NULL, return 0);
1230         PED_ASSERT (disk_type->ops->partition_set_system != NULL, return 0);
1231
1232         return disk_type->ops->partition_set_system (part, fs_type);
1233 }
1234
1235 static int
1236 _assert_partition_name_feature (const PedDiskType* disk_type)
1237 {
1238         if (!ped_disk_type_check_feature (
1239                         disk_type, PED_DISK_TYPE_PARTITION_NAME)) {
1240                 ped_exception_throw (
1241                         PED_EXCEPTION_ERROR,
1242                         PED_EXCEPTION_CANCEL,
1243                         "%s disk labels do not support partition names.",
1244                         disk_type->name);
1245                 return 0;
1246         }
1247         return 1;
1248 }
1249
1250 /**
1251  * Sets the name of a partition.
1252  *
1253  * \note This will only work if the disk label supports it.
1254  *      You can use
1255  *      \code
1256  * ped_disk_type_check_feature (part->disk->type, PED_DISK_TYPE_PARTITION_NAME);
1257  *      \endcode
1258  *      to check whether this feature is enabled for a label.
1259  *      
1260  * \note \p name will not be modified by libparted. It can be freed
1261  *      by the caller immediately after ped_partition_set_name() is called.
1262  *
1263  * \return \c 1 on success, \c 0 otherwise.
1264  */
1265 int
1266 ped_partition_set_name (PedPartition* part, const char* name)
1267 {
1268         PED_ASSERT (part != NULL, return 0);
1269         PED_ASSERT (part->disk != NULL, return 0);
1270         PED_ASSERT (ped_partition_is_active (part), return 0);
1271         PED_ASSERT (name != NULL, return 0);
1272
1273         if (!_assert_partition_name_feature (part->disk->type))
1274                 return 0;
1275
1276         PED_ASSERT (part->disk->type->ops->partition_set_name != NULL,
1277                     return 0);
1278         part->disk->type->ops->partition_set_name (part, name);
1279         return 1;
1280 }
1281
1282 /**
1283  * Returns the name of a partition \p part.  This will only work if the disk
1284  * label supports it.
1285  *
1286  * \note The returned string should not be modified.  It should
1287  *      not be referenced after the partition is destroyed.
1288  */
1289 const char*
1290 ped_partition_get_name (const PedPartition* part)
1291 {
1292         PED_ASSERT (part != NULL, return NULL);
1293         PED_ASSERT (part->disk != NULL, return 0);
1294         PED_ASSERT (ped_partition_is_active (part), return 0);
1295
1296         if (!_assert_partition_name_feature (part->disk->type))
1297                 return NULL;
1298
1299         PED_ASSERT (part->disk->type->ops->partition_get_name != NULL,
1300                     return NULL);
1301         return part->disk->type->ops->partition_get_name (part);
1302 }
1303
1304 /** @} */
1305
1306 /**
1307  * \addtogroup PedDisk
1308  *
1309  * @{
1310  */
1311
1312 PedPartition*
1313 ped_disk_extended_partition (const PedDisk* disk)
1314 {
1315         PedPartition*           walk;
1316
1317         PED_ASSERT (disk != NULL, return 0);
1318
1319         for (walk = disk->part_list; walk; walk = walk->next) {
1320                 if (walk->type == PED_PARTITION_EXTENDED)
1321                         break;
1322         }
1323         return walk;
1324 }
1325
1326 /** 
1327  * Return the next partition after \p part on \p disk. If \p part is \c NULL,
1328  * return the first partition. If \p part is the last partition, returns
1329  * \c NULL. If \p part is an extended partition, returns the first logical
1330  * partition. If this is called repeatedly passing the return value as \p part,
1331  * a depth-first traversal is executed.
1332  *
1333  * \return The next partition, \c NULL if no more partitions left.
1334  */
1335 PedPartition*
1336 ped_disk_next_partition (const PedDisk* disk, const PedPartition* part)
1337 {
1338         PED_ASSERT (disk != NULL, return 0);
1339
1340         if (!part)
1341                 return disk->part_list;
1342         if (part->type == PED_PARTITION_EXTENDED)
1343                 return part->part_list ? part->part_list : part->next;
1344         if (part->next)
1345                 return part->next;
1346         if (part->type & PED_PARTITION_LOGICAL)
1347                 return ped_disk_extended_partition (disk)->next;
1348         return NULL;
1349 }
1350
1351 /** @} */
1352
1353 #ifdef DEBUG
1354 static int
1355 _disk_check_sanity (PedDisk* disk)
1356 {
1357         PedPartition*   walk;
1358
1359         PED_ASSERT (disk != NULL, return 0);
1360
1361         for (walk = disk->part_list; walk; walk = walk->next) {
1362                 PED_ASSERT (!(walk->type & PED_PARTITION_LOGICAL), return 0);
1363                 PED_ASSERT (!walk->prev || walk->prev->next == walk, return 0);
1364         }
1365
1366         if (!ped_disk_extended_partition (disk))
1367                 return 1;
1368
1369         for (walk = ped_disk_extended_partition (disk)->part_list; walk;
1370              walk = walk->next) {
1371                 PED_ASSERT (walk->type & PED_PARTITION_LOGICAL, return 0);
1372                 if (walk->prev)
1373                         PED_ASSERT (walk->prev->next == walk, return 0);
1374         }
1375         return 1;
1376 }
1377 #endif
1378
1379 /**
1380  * Returns the partition numbered \p num. 
1381  *
1382  * \return \c NULL if the specified partition does not exist.
1383  */
1384 PedPartition*
1385 ped_disk_get_partition (const PedDisk* disk, int num)
1386 {
1387         PedPartition*   walk;
1388
1389         PED_ASSERT (disk != NULL, return 0);
1390
1391         for (walk = disk->part_list; walk;
1392              walk = ped_disk_next_partition (disk, walk)) {
1393                 if (walk->num == num && !(walk->type & PED_PARTITION_FREESPACE))
1394                         return walk;
1395         }
1396
1397         return NULL;
1398 }
1399
1400 /**
1401  * Returns the partition that contains sect.  If sect lies within a logical
1402  * partition, then the logical partition is returned (not the extended
1403  * partition).
1404  */
1405 PedPartition*
1406 ped_disk_get_partition_by_sector (const PedDisk* disk, PedSector sect)
1407 {
1408         PedPartition*   walk;
1409
1410         PED_ASSERT (disk != NULL, return 0);
1411
1412         for (walk = disk->part_list; walk;
1413              walk = ped_disk_next_partition (disk, walk)) {
1414                 if (ped_geometry_test_sector_inside (&walk->geom, sect)
1415                     && walk->type != PED_PARTITION_EXTENDED)
1416                         return walk;
1417         }
1418
1419         /* should never get here, unless sect is outside of disk's useable
1420          * part, or we're in "update mode", and the free space place-holders
1421          * have been removed with _disk_remove_freespace()
1422          */
1423         return NULL;
1424 }
1425
1426 /* I'm beginning to agree with Sedgewick :-/ */
1427 static int
1428 _disk_raw_insert_before (PedDisk* disk, PedPartition* loc, PedPartition* part)
1429 {
1430         PED_ASSERT (disk != NULL, return 0);
1431         PED_ASSERT (loc != NULL, return 0);
1432         PED_ASSERT (part != NULL, return 0);
1433
1434         part->prev = loc->prev;
1435         part->next = loc;
1436         if (part->prev) {
1437                 part->prev->next = part;
1438         } else {
1439                 if (loc->type & PED_PARTITION_LOGICAL)
1440                         ped_disk_extended_partition (disk)->part_list = part;
1441                 else
1442                         disk->part_list = part;
1443         }
1444         loc->prev = part;
1445
1446         return 1;
1447 }
1448
1449 static int
1450 _disk_raw_insert_after (PedDisk* disk, PedPartition* loc, PedPartition* part)
1451 {
1452         PED_ASSERT (disk != NULL, return 0);
1453         PED_ASSERT (loc != NULL, return 0);
1454         PED_ASSERT (part != NULL, return 0);
1455
1456         part->prev = loc;
1457         part->next = loc->next;
1458         if (loc->next)
1459                 loc->next->prev = part;
1460         loc->next = part;
1461
1462         return 1;
1463 }
1464
1465 static int
1466 _disk_raw_remove (PedDisk* disk, PedPartition* part)
1467 {
1468         PED_ASSERT (disk != NULL, return 0);
1469         PED_ASSERT (part != NULL, return 0);
1470
1471         if (part->prev) {
1472                 part->prev->next = part->next;
1473                 if (part->next)
1474                         part->next->prev = part->prev;
1475         } else {
1476                 if (part->type & PED_PARTITION_LOGICAL) {
1477                         ped_disk_extended_partition (disk)->part_list
1478                                 = part->next;
1479                 } else {
1480                         disk->part_list = part->next;
1481                 }
1482                 if (part->next)
1483                         part->next->prev = NULL;
1484         }
1485
1486         return 1;
1487 }
1488
1489 /*
1490  *UPDATE MODE ONLY
1491  */
1492 static int
1493 _disk_raw_add (PedDisk* disk, PedPartition* part)
1494 {
1495         PedPartition*   walk;
1496         PedPartition*   last;
1497         PedPartition*   ext_part;
1498
1499         PED_ASSERT (disk->update_mode, return 0);
1500
1501         ext_part = ped_disk_extended_partition (disk);
1502
1503         last = NULL;
1504         walk = (part->type & PED_PARTITION_LOGICAL) ?
1505                         ext_part->part_list : disk->part_list;
1506
1507         for (; walk; last = walk, walk = walk->next) {
1508                 if (walk->geom.start > part->geom.end)
1509                         break;
1510         }
1511
1512         if (walk) {
1513                 return _disk_raw_insert_before (disk, walk, part);
1514         } else {
1515                 if (last) {
1516                         return _disk_raw_insert_after (disk, last, part);
1517                 } else {
1518                         if (part->type & PED_PARTITION_LOGICAL)
1519                                 ext_part->part_list = part;
1520                         else
1521                                 disk->part_list = part;
1522                 } 
1523         }
1524
1525         return 1;
1526 }
1527
1528 static PedConstraint*
1529 _partition_get_overlap_constraint (PedPartition* part, PedGeometry* geom)
1530 {
1531         PedSector       min_start;
1532         PedSector       max_end;
1533         PedPartition*   walk;
1534         PedGeometry     free_space;
1535
1536         PED_ASSERT (part->disk->update_mode, return NULL);
1537         PED_ASSERT (part->geom.dev == geom->dev, return NULL);
1538
1539         if (part->type & PED_PARTITION_LOGICAL) {
1540                 PedPartition* ext_part;
1541                 
1542                 ext_part = ped_disk_extended_partition (part->disk);
1543                 PED_ASSERT (ext_part != NULL, return NULL);
1544
1545                 min_start = ext_part->geom.start;
1546                 max_end = ext_part->geom.end;
1547                 walk = ext_part->part_list;
1548         } else {
1549                 min_start = 0;
1550                 max_end = part->disk->dev->length - 1;
1551                 walk = part->disk->part_list;
1552         }
1553
1554         while (walk != NULL
1555                && (walk->geom.start < geom->start
1556                             || min_start >= walk->geom.start)) {
1557                 if (walk != part)
1558                         min_start = walk->geom.end + 1;
1559                 walk = walk->next;
1560         }
1561
1562         if (walk == part)
1563                 walk = walk->next;
1564
1565         if (walk)
1566                 max_end = walk->geom.start - 1;
1567
1568         if (min_start >= max_end)
1569                 return NULL;
1570
1571         ped_geometry_init (&free_space, part->disk->dev,
1572                            min_start, max_end - min_start + 1);
1573         return ped_constraint_new_from_max (&free_space);
1574 }
1575
1576 /*
1577  * Returns \c 0 if the partition, \p part overlaps with any partitions on the
1578  * \p disk.  The geometry of \p part is taken to be \p geom, NOT \p part->geom
1579  * (the idea here is to check if \p geom is valid, before changing \p part).
1580  * 
1581  * This is useful for seeing if a resized partitions new geometry is going to
1582  * fit, without the existing geomtry getting in the way.
1583  *
1584  * Note: overlap with an extended partition is also allowed, provided that
1585  * \p geom lies completely inside the extended partition.
1586  */
1587 static int
1588 _disk_check_part_overlaps (PedDisk* disk, PedPartition* part)
1589 {
1590         PedPartition*   walk;
1591
1592         PED_ASSERT (disk != NULL, return 0);
1593         PED_ASSERT (part != NULL, return 0);
1594
1595         for (walk = ped_disk_next_partition (disk, NULL); walk;
1596              walk = ped_disk_next_partition (disk, walk)) {
1597                 if (walk->type & PED_PARTITION_FREESPACE)
1598                         continue;
1599                 if (walk == part)
1600                         continue;
1601                 if (part->type & PED_PARTITION_EXTENDED
1602                     && walk->type & PED_PARTITION_LOGICAL)
1603                         continue;
1604
1605                 if (ped_geometry_test_overlap (&walk->geom, &part->geom)) {
1606                         if (walk->type & PED_PARTITION_EXTENDED
1607                             && part->type & PED_PARTITION_LOGICAL
1608                             && ped_geometry_test_inside (&walk->geom,
1609                                                          &part->geom))
1610                                 continue;
1611                         return 0;
1612                 }
1613         }
1614
1615         return 1;
1616 }
1617
1618 static int
1619 _partition_check_basic_sanity (PedDisk* disk, PedPartition* part)
1620 {
1621         PedPartition*   ext_part = ped_disk_extended_partition (disk);
1622
1623         PED_ASSERT (part->disk == disk, return 0);
1624
1625         PED_ASSERT (part->geom.start >= 0, return 0);
1626         PED_ASSERT (part->geom.end < disk->dev->length, return 0);
1627         PED_ASSERT (part->geom.start <= part->geom.end, return 0);
1628
1629         if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)
1630             && (part->type == PED_PARTITION_EXTENDED
1631                     || part->type == PED_PARTITION_LOGICAL)) {
1632                 ped_exception_throw (
1633                         PED_EXCEPTION_ERROR,
1634                         PED_EXCEPTION_CANCEL,
1635                         _("%s disk labels don't support logical or extended "
1636                           "partitions."),
1637                         disk->type->name);
1638                 return 0;
1639         }
1640
1641         if (ped_partition_is_active (part)
1642                         && ! (part->type & PED_PARTITION_LOGICAL)) {
1643                 if (ped_disk_get_primary_partition_count (disk) + 1
1644                     > ped_disk_get_max_primary_partition_count (disk)) {
1645                         ped_exception_throw (
1646                                 PED_EXCEPTION_ERROR,
1647                                 PED_EXCEPTION_CANCEL,
1648                                 _("Too many primary partitions."));
1649                         return 0;
1650                 }
1651         }
1652
1653         if ((part->type & PED_PARTITION_LOGICAL) && !ext_part) {
1654                 ped_exception_throw (
1655                         PED_EXCEPTION_ERROR,
1656                         PED_EXCEPTION_CANCEL,
1657                         _("Can't add a logical partition to %s, because "
1658                         "there is no extended partition."),
1659                         disk->dev->path);
1660                 return 0;
1661         }
1662
1663         return 1;
1664 }
1665
1666 static int
1667 _check_extended_partition (PedDisk* disk, PedPartition* part)
1668 {
1669         PedPartition*           walk;
1670         PedPartition*           ext_part;
1671
1672         PED_ASSERT (disk != NULL, return 0);
1673         ext_part = ped_disk_extended_partition (disk);
1674         if (!ext_part) ext_part = part;
1675         PED_ASSERT (ext_part != NULL, return 0);
1676
1677         if (part != ext_part) {
1678                 ped_exception_throw (
1679                         PED_EXCEPTION_ERROR,
1680                         PED_EXCEPTION_CANCEL,
1681                         _("Can't have more than one extended partition on %s."),
1682                         disk->dev->path);
1683                 return 0;
1684         }
1685
1686         for (walk = ext_part->part_list; walk; walk = walk->next) {
1687                 if (!ped_geometry_test_inside (&ext_part->geom, &walk->geom)) {
1688                         ped_exception_throw (
1689                                 PED_EXCEPTION_ERROR,
1690                                 PED_EXCEPTION_CANCEL,
1691                                 _("Can't have logical partitions outside of "
1692                                   "the extended partition."));
1693                         return 0;
1694                 }
1695         }
1696         return 1;
1697 }
1698
1699 static int
1700 _check_partition (PedDisk* disk, PedPartition* part)
1701 {
1702         PedPartition*   ext_part = ped_disk_extended_partition (disk);
1703
1704         PED_ASSERT (part->geom.start <= part->geom.end, return 0);
1705
1706         if (part->type == PED_PARTITION_EXTENDED) {
1707                 if (!_check_extended_partition (disk, part))
1708                         return 0;
1709         }
1710
1711         if (part->type & PED_PARTITION_LOGICAL
1712             && !ped_geometry_test_inside (&ext_part->geom, &part->geom)) {
1713                 ped_exception_throw (
1714                         PED_EXCEPTION_ERROR,
1715                         PED_EXCEPTION_CANCEL,
1716                         _("Can't have a logical partition outside of the "
1717                           "extended partition on %s."),
1718                         disk->dev->path);
1719                 return 0;
1720         }
1721
1722         if (!_disk_check_part_overlaps (disk, part)) {
1723                 ped_exception_throw (
1724                         PED_EXCEPTION_ERROR,
1725                         PED_EXCEPTION_CANCEL,
1726                         _("Can't have overlapping partitions."));
1727                 return 0;
1728         }
1729
1730         if (! (part->type & PED_PARTITION_LOGICAL)
1731             && ext_part && ext_part != part
1732             && ped_geometry_test_inside (&ext_part->geom, &part->geom)) {
1733                 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1734                         _("Can't have a primary partition inside an extended "
1735                          "partition."));
1736                 return 0;
1737         }
1738
1739         return 1;
1740 }
1741
1742 /**
1743  * Adds PedPartition \p part to PedPartition \p disk.
1744  * 
1745  * \warning The partition's geometry may be changed, subject to \p constraint.
1746  * You could set \p constraint to <tt>ped_constraint_exact(&part->geom)</tt>,
1747  * but many partition table schemes have special requirements on the start
1748  * and end of partitions.  Therefore, having an overly strict constraint
1749  * will probably mean that this function will fail (in which
1750  * case \p part will be left unmodified)
1751  * \p part is assigned a number (\p part->num) in this process.
1752  * 
1753  * \return \c 0 on failure.
1754  */
1755 int
1756 ped_disk_add_partition (PedDisk* disk, PedPartition* part,
1757                         const PedConstraint* constraint)
1758 {
1759         PedConstraint*  overlap_constraint = NULL;
1760         PedConstraint*  constraints = NULL;
1761
1762         PED_ASSERT (disk != NULL, return 0);
1763         PED_ASSERT (part != NULL, return 0);
1764
1765         if (!_partition_check_basic_sanity (disk, part))
1766                 return 0;
1767
1768         _disk_push_update_mode (disk);
1769
1770         if (ped_partition_is_active (part)) {
1771                 overlap_constraint
1772                         = _partition_get_overlap_constraint (part, &part->geom);
1773                 constraints = ped_constraint_intersect (overlap_constraint,
1774                                                         constraint);
1775
1776                 if (!constraints && constraint) {
1777                         ped_exception_throw (
1778                                 PED_EXCEPTION_ERROR,
1779                                 PED_EXCEPTION_CANCEL,
1780                                 _("Can't have overlapping partitions."));
1781                         goto error;
1782                 }
1783
1784                 if (!_partition_enumerate (part))
1785                         goto error;
1786                 if (!_partition_align (part, constraints))
1787                         goto error;
1788         }
1789         if (!_check_partition (disk, part))
1790                 goto error;
1791         if (!_disk_raw_add (disk, part))
1792                 goto error;
1793
1794         ped_constraint_destroy (overlap_constraint);
1795         ped_constraint_destroy (constraints);
1796         _disk_pop_update_mode (disk);
1797 #ifdef DEBUG
1798         if (!_disk_check_sanity (disk))
1799                 return 0;
1800 #endif
1801         return 1;
1802
1803 error:
1804         ped_constraint_destroy (overlap_constraint);
1805         ped_constraint_destroy (constraints);
1806         _disk_pop_update_mode (disk);
1807         return 0;
1808 }
1809
1810 /**
1811  * Removes PedPartition \p part from PedDisk \p disk.
1812  *
1813  * If \p part is an extended partition, it must not contain any logical
1814  * partitions. \p part is *NOT* destroyed. The caller must call
1815  * ped_partition_destroy(), or use ped_disk_delete_partition() instead.
1816  *
1817  * \return \c 0 on error.
1818  */
1819 int
1820 ped_disk_remove_partition (PedDisk* disk, PedPartition* part)
1821 {
1822         PED_ASSERT (disk != NULL, return 0);
1823         PED_ASSERT (part != NULL, return 0);
1824
1825         _disk_push_update_mode (disk);
1826         PED_ASSERT (part->part_list == NULL, goto error);
1827         _disk_raw_remove (disk, part);
1828         _disk_pop_update_mode (disk);
1829         ped_disk_enumerate_partitions (disk);
1830         return 1;
1831
1832 error:
1833         _disk_pop_update_mode (disk);
1834         return 0;
1835 }
1836
1837 static int
1838 ped_disk_delete_all_logical (PedDisk* disk);
1839
1840 /**
1841  * Removes \p part from \p disk, and destroys \p part.
1842  *
1843  * \return \c 0 on failure.
1844  */
1845 int
1846 ped_disk_delete_partition (PedDisk* disk, PedPartition* part)
1847 {
1848         PED_ASSERT (disk != NULL, return 0);
1849         PED_ASSERT (part != NULL, return 0);
1850
1851         _disk_push_update_mode (disk);
1852         if (part->type == PED_PARTITION_EXTENDED)
1853                 ped_disk_delete_all_logical (disk);
1854         ped_disk_remove_partition (disk, part);
1855         ped_partition_destroy (part);
1856         _disk_pop_update_mode (disk);
1857
1858         return 1;
1859 }
1860
1861 static int
1862 ped_disk_delete_all_logical (PedDisk* disk)
1863 {
1864         PedPartition*           walk;
1865         PedPartition*           next;
1866         PedPartition*           ext_part;
1867
1868         PED_ASSERT (disk != NULL, return 0);
1869         ext_part = ped_disk_extended_partition (disk);
1870         PED_ASSERT (ext_part != NULL, return 0);
1871
1872         for (walk = ext_part->part_list; walk; walk = next) {
1873                 next = walk->next;
1874
1875                 if (!ped_disk_delete_partition (disk, walk))
1876                         return 0;
1877         }
1878         return 1;
1879 }
1880
1881 /**
1882  * Removes and destroys all partitions on \p disk.
1883  *
1884  * \return \c 0 on failure.
1885  */
1886 int
1887 ped_disk_delete_all (PedDisk* disk)
1888 {
1889         PedPartition*           walk;
1890         PedPartition*           next;
1891
1892         PED_ASSERT (disk != NULL, return 0);
1893
1894         _disk_push_update_mode (disk);
1895
1896         for (walk = disk->part_list; walk; walk = next) {
1897                 next = walk->next;
1898
1899                 if (!ped_disk_delete_partition (disk, walk))
1900                         return 0;
1901         }
1902
1903         _disk_pop_update_mode (disk);
1904
1905         return 1;
1906 }
1907
1908 /**
1909  * Sets the geometry of \p part (i.e. change a partitions location). This can
1910  * fail for many reasons, e.g. can't overlap with other partitions. If it
1911  * does fail, \p part will remain unchanged. Returns \c 0 on failure. \p part's
1912  * geometry may be set to something different from \p start and \p end subject
1913  * to \p constraint.
1914  *
1915  * \warning The constraint warning from ped_disk_add_partition() applies.
1916  * 
1917  * \note this function does not modify the contents of the partition.  You need
1918  *       to call ped_file_system_resize() separately.
1919  */
1920 int
1921 ped_disk_set_partition_geom (PedDisk* disk, PedPartition* part,
1922                              const PedConstraint* constraint,
1923                              PedSector start, PedSector end)
1924 {
1925         PedConstraint*  overlap_constraint = NULL;
1926         PedConstraint*  constraints = NULL;
1927         PedGeometry     old_geom;
1928         PedGeometry     new_geom;
1929
1930         PED_ASSERT (disk != NULL, return 0);
1931         PED_ASSERT (part != NULL, return 0);
1932         PED_ASSERT (part->disk == disk, return 0);
1933
1934         old_geom = part->geom;
1935         ped_geometry_init (&new_geom, part->geom.dev, start, end - start + 1);
1936
1937         _disk_push_update_mode (disk);
1938
1939         overlap_constraint
1940                 = _partition_get_overlap_constraint (part, &new_geom);
1941         constraints = ped_constraint_intersect (overlap_constraint, constraint);
1942         if (!constraints && constraint) {
1943                 ped_exception_throw (
1944                         PED_EXCEPTION_ERROR,
1945                         PED_EXCEPTION_CANCEL,
1946                         _("Can't have overlapping partitions."));
1947                 goto error_pop_update_mode;
1948         }
1949
1950         part->geom = new_geom;
1951         if (!_partition_align (part, constraints))
1952                 goto error_pop_update_mode;
1953         if (!_check_partition (disk, part))
1954                 goto error_pop_update_mode;
1955
1956         /* remove and add, to ensure the ordering gets updated if necessary */
1957         _disk_raw_remove (disk, part);
1958         _disk_raw_add (disk, part);
1959
1960         _disk_pop_update_mode (disk);
1961
1962         ped_constraint_destroy (overlap_constraint);
1963         ped_constraint_destroy (constraints);
1964         return 1;
1965
1966 error_pop_update_mode:
1967         _disk_pop_update_mode (disk);
1968 error:
1969         ped_constraint_destroy (overlap_constraint);
1970         ped_constraint_destroy (constraints);
1971         part->geom = old_geom;
1972         return 0;
1973 }
1974
1975 /**
1976  * Grow PedPartition \p part geometry to the maximum possible subject to
1977  * \p constraint.  The new geometry will be a superset of the old geometry.
1978  * 
1979  * \return 0 on failure
1980  */
1981 int
1982 ped_disk_maximize_partition (PedDisk* disk, PedPartition* part,
1983                              const PedConstraint* constraint)
1984 {
1985         PedGeometry     old_geom;
1986         PedSector       global_min_start;
1987         PedSector       global_max_end;
1988         PedSector       new_start;
1989         PedSector       new_end;
1990         PedPartition*   ext_part = ped_disk_extended_partition (disk);
1991         PedConstraint*  constraint_any;
1992
1993         PED_ASSERT (disk != NULL, return 0);
1994         PED_ASSERT (part != NULL, return 0);
1995
1996         if (part->type & PED_PARTITION_LOGICAL) {
1997                 PED_ASSERT (ext_part != NULL, return 0);
1998                 global_min_start = ext_part->geom.start;
1999                 global_max_end = ext_part->geom.end;
2000         } else {
2001                 global_min_start = 0;
2002                 global_max_end = disk->dev->length - 1;
2003         }
2004
2005         old_geom = part->geom;
2006
2007         _disk_push_update_mode (disk);
2008
2009         if (part->prev)
2010                 new_start = part->prev->geom.end + 1;
2011         else
2012                 new_start = global_min_start;
2013
2014         if (part->next)
2015                 new_end = part->next->geom.start - 1;
2016         else
2017                 new_end = global_max_end;
2018
2019         if (!ped_disk_set_partition_geom (disk, part, constraint, new_start,
2020                                           new_end))
2021                 goto error;
2022
2023         _disk_pop_update_mode (disk);
2024         return 1;
2025
2026 error:
2027         constraint_any = ped_constraint_any (disk->dev);
2028         ped_disk_set_partition_geom (disk, part, constraint_any,
2029                                      old_geom.start, old_geom.end);
2030         ped_constraint_destroy (constraint_any);
2031         _disk_pop_update_mode (disk);
2032         return 0;
2033 }
2034
2035 /**
2036  * Get the maximum geometry \p part can be grown to, subject to
2037  * \p constraint.
2038  *
2039  * \return \c NULL on failure.
2040  */
2041 PedGeometry*
2042 ped_disk_get_max_partition_geometry (PedDisk* disk, PedPartition* part,
2043                                      const PedConstraint* constraint)
2044 {
2045         PedGeometry     old_geom;
2046         PedGeometry*    max_geom;
2047         PedConstraint*  constraint_exact;
2048
2049         PED_ASSERT(disk != NULL, return NULL);
2050         PED_ASSERT(part != NULL, return NULL);
2051         PED_ASSERT(ped_partition_is_active (part), return NULL);
2052
2053         old_geom = part->geom;
2054         if (!ped_disk_maximize_partition (disk, part, constraint))
2055                 return NULL;
2056         max_geom = ped_geometry_duplicate (&part->geom);
2057
2058         constraint_exact = ped_constraint_exact (&old_geom);
2059         ped_disk_set_partition_geom (disk, part, constraint_exact,
2060                                      old_geom.start, old_geom.end);
2061         ped_constraint_destroy (constraint_exact);
2062
2063         /* this assertion should never fail, because the old
2064          * geometry was valid
2065          */
2066         PED_ASSERT (ped_geometry_test_equal (&part->geom, &old_geom),
2067                     return NULL);
2068
2069         return max_geom;
2070 }
2071
2072 /** 
2073  * Reduce the size of the extended partition to a minimum while still wrapping
2074  * its logical partitions.  If there are no logical partitions, remove the
2075  * extended partition.
2076  *
2077  * \return 0 on failure.
2078  */
2079 int
2080 ped_disk_minimize_extended_partition (PedDisk* disk)
2081 {
2082         PedPartition*           first_logical;
2083         PedPartition*           last_logical;
2084         PedPartition*           walk;
2085         PedPartition*           ext_part;
2086         PedConstraint*          constraint;
2087         int                     status;
2088
2089         PED_ASSERT (disk != NULL, return 0);
2090
2091         ext_part = ped_disk_extended_partition (disk);
2092         if (!ext_part)
2093                 return 1;
2094
2095         _disk_push_update_mode (disk);
2096
2097         first_logical = ext_part->part_list;
2098         if (!first_logical) {
2099                 _disk_pop_update_mode (disk);
2100                 return ped_disk_delete_partition (disk, ext_part);
2101         }
2102
2103         for (walk = first_logical; walk->next; walk = walk->next);
2104         last_logical = walk;
2105
2106         constraint = ped_constraint_any (disk->dev);
2107         status = ped_disk_set_partition_geom (disk, ext_part, constraint,
2108                                               first_logical->geom.start,
2109                                               last_logical->geom.end);
2110         ped_constraint_destroy (constraint);
2111
2112         _disk_pop_update_mode (disk);
2113         return status;
2114 }
2115
2116 /**
2117  * @}
2118  */
2119
2120 /**
2121  * \addtogroup PedPartition
2122  *
2123  * @{
2124  */
2125
2126 /**
2127  * Returns a name that seems mildly appropriate for a partition type \p type.
2128  * 
2129  * Eg, if you pass (PED_PARTITION_LOGICAL & PED_PARTITION_FREESPACE), it
2130  * will return "free".  This isn't to be taken too seriously - it's just
2131  * useful for user interfaces, so you can show the user something ;-)
2132  * 
2133  * \note The returned string will be in English.  However,
2134  * translations are provided, so the caller can call
2135  * dgettext("parted", RESULT) on the result.
2136  *
2137  */
2138 const char*
2139 ped_partition_type_get_name (PedPartitionType type)
2140 {
2141         if (type & PED_PARTITION_METADATA)
2142                 return N_("metadata");
2143         else if (type & PED_PARTITION_FREESPACE)
2144                 return N_("free");
2145         else if (type & PED_PARTITION_EXTENDED)
2146                 return N_("extended");
2147         else if (type & PED_PARTITION_LOGICAL)
2148                 return N_("logical");
2149         else
2150                 return N_("primary");
2151 }
2152
2153
2154 /**
2155  * Returns a name for a \p flag, e.g. PED_PARTITION_BOOT will return "boot".
2156  * 
2157  * \note The returned string will be in English.  However,
2158  * translations are provided, so the caller can call
2159  * dgettext("parted", RESULT) on the result.
2160  */
2161 const char*
2162 ped_partition_flag_get_name (PedPartitionFlag flag)
2163 {
2164         switch (flag) {
2165         case PED_PARTITION_BOOT:
2166                 return N_("boot");
2167         case PED_PARTITION_ROOT:
2168                 return N_("root");
2169         case PED_PARTITION_SWAP:
2170                 return N_("swap");
2171         case PED_PARTITION_HIDDEN:
2172                 return N_("hidden");
2173         case PED_PARTITION_RAID:
2174                 return N_("raid");
2175         case PED_PARTITION_LVM:
2176                 return N_("lvm");
2177         case PED_PARTITION_LBA:
2178                 return N_("lba");
2179         case PED_PARTITION_HPSERVICE:
2180                 return N_("hp-service");
2181         case PED_PARTITION_PALO:
2182                 return N_("palo");
2183         case PED_PARTITION_PREP:
2184                 return N_("prep");
2185         case PED_PARTITION_MSFT_RESERVED:
2186                 return N_("msftres");
2187
2188         default:
2189                 ped_exception_throw (
2190                         PED_EXCEPTION_BUG,
2191                         PED_EXCEPTION_CANCEL,
2192                         _("Unknown partition flag, %d."),
2193                         flag);
2194                 return NULL;
2195         }
2196 }
2197
2198 /**
2199  * Iterates through all flags. 
2200  * 
2201  * ped_partition_flag_next(0) returns the first flag
2202  *
2203  * \return the next flag, or 0 if there are no more flags
2204  */
2205 PedPartitionFlag
2206 ped_partition_flag_next (PedPartitionFlag flag)
2207 {
2208         return (flag + 1) % (PED_PARTITION_LAST_FLAG + 1);
2209 }
2210
2211 /**
2212  * Returns the flag associated with \p name.  
2213  *
2214  * \p name can be the English
2215  * string, or the translation for the native language.
2216  */
2217 PedPartitionFlag
2218 ped_partition_flag_get_by_name (const char* name)
2219 {
2220         PedPartitionFlag        flag;
2221         const char*             flag_name;
2222
2223         for (flag = ped_partition_flag_next (0); flag;
2224                         flag = ped_partition_flag_next (flag)) {
2225                 flag_name = ped_partition_flag_get_name (flag);
2226                 if (strcasecmp (name, flag_name) == 0
2227                     || strcasecmp (name, _(flag_name)) == 0)
2228                         return flag;
2229         }
2230
2231         return 0;
2232 }
2233
2234 void
2235 ped_partition_print (PedPartition* part)
2236 {
2237         PED_ASSERT (part != NULL, return);
2238
2239         printf ("  %-10s %02d  (%d->%d)\n",
2240                 ped_partition_type_get_name (part->type),
2241                 part->num,
2242                 (int) part->geom.start, (int) part->geom.end);
2243 }
2244
2245 /** @} */
2246
2247 /**
2248  * \addtogroup PedDisk
2249  *
2250  * @{
2251  */
2252
2253 /**
2254  * Prints a summary of disk's partitions.  Useful for debugging.
2255  */
2256 void
2257 ped_disk_print (PedDisk* disk)
2258 {
2259         PedPartition*   part;
2260
2261         PED_ASSERT (disk != NULL, return);
2262
2263         for (part = disk->part_list; part;
2264              part = ped_disk_next_partition (disk, part))
2265                 ped_partition_print (part);
2266 }
2267
2268 /** @} */