OSDN Git Service

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