OSDN Git Service

Remove PED_ASSERT action argument
[android-x86/external-parted.git] / libparted / disk.c
index e2e55c3..1057aa8 100644 (file)
@@ -1,7 +1,6 @@
  /*
     libparted - a library for manipulating disk partitions
-    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2007
-                  Free Software Foundation, Inc.
+    Copyright (C) 1999-2003, 2005, 2007-2011 Free Software Foundation, Inc.
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -23,7 +22,7 @@
  * \addtogroup PedDisk
  *
  * \brief Disk label access.
- * 
+ *
  * Most programs will need to use ped_disk_new() or ped_disk_new_fresh() to get
  * anything done.  A PedDisk is always associated with a device and has a
  * partition table.  There are different types of partition tables (or disk
 
 #include <parted/parted.h>
 #include <parted/debug.h>
+#include <stdbool.h>
+
+#include "architecture.h"
+#include "labels/pt-tools.h"
 
 #if ENABLE_NLS
 #  include <libintl.h>
@@ -50,8 +53,8 @@
 #ifdef DEBUG
 static int _disk_check_sanity (PedDisk* disk);
 #endif
-static void _disk_push_update_mode (PedDisk* disk);
-static void _disk_pop_update_mode (PedDisk* disk);
+static int _disk_push_update_mode (PedDisk* disk);
+static int _disk_pop_update_mode (PedDisk* disk);
 static int _disk_raw_insert_before (PedDisk* disk, PedPartition* loc,
                                    PedPartition* part);
 static int _disk_raw_insert_after (PedDisk* disk, PedPartition* loc,
@@ -64,13 +67,12 @@ static PedDiskType* disk_types = NULL;
 void
 ped_disk_type_register (PedDiskType* disk_type)
 {
-       PED_ASSERT (disk_type != NULL, return);
-       PED_ASSERT (disk_type->ops != NULL, return);
-       PED_ASSERT (disk_type->name != NULL, return);
-       
-       /* pretend that "next" isn't part of the struct :-) */
-       ((struct _PedDiskType*) disk_type)->next = disk_types;
-       disk_types = (struct _PedDiskType*) disk_type;
+       PED_ASSERT (disk_type != NULL);
+       PED_ASSERT (disk_type->ops != NULL);
+       PED_ASSERT (disk_type->name != NULL);
+
+        disk_type->next = disk_types;
+        disk_types =  disk_type;
 }
 
 void
@@ -79,13 +81,13 @@ ped_disk_type_unregister (PedDiskType* disk_type)
        PedDiskType*    walk;
        PedDiskType*    last = NULL;
 
-       PED_ASSERT (disk_types != NULL, return);
-       PED_ASSERT (disk_type != NULL, return);
+       PED_ASSERT (disk_types != NULL);
+       PED_ASSERT (disk_type != NULL);
 
        for (walk = disk_types; walk && walk != disk_type;
                 last = walk, walk = walk->next);
 
-       PED_ASSERT (walk != NULL, return);
+       PED_ASSERT (walk != NULL);
        if (last)
                ((struct _PedDiskType*) last)->next = disk_type->next;
        else
@@ -93,31 +95,13 @@ ped_disk_type_unregister (PedDiskType* disk_type)
 }
 
 /**
- * Deprecated: use ped_disk_type_regiser.
- */
-void
-ped_register_disk_type (PedDiskType* disk_type)
-{
-        ped_disk_type_register (disk_type);
-}
-
-/**
- * Deprecated: use ped_disk_type_unregiser.
- */
-void
-ped_unregister_disk_type (PedDiskType* disk_type)
-{
-        ped_disk_type_unregister (disk_type);
-}
-
-/**
  * Return the next disk type registers, after "type".  If "type" is
  * NULL, returns the first disk type.
  *
  * \return Next disk; NULL if "type" is the last registered disk type.
  */
 PedDiskType*
-ped_disk_type_get_next (PedDiskTypetype)
+ped_disk_type_get_next (PedDiskType const *type)
 {
        if (type)
                return type->next;
@@ -135,7 +119,7 @@ ped_disk_type_get (const char* name)
 {
        PedDiskType*    walk = NULL;
 
-       PED_ASSERT (name != NULL, return NULL);
+       PED_ASSERT (name != NULL);
 
        for (walk = ped_disk_type_get_next (NULL); walk;
             walk = ped_disk_type_get_next (walk))
@@ -155,7 +139,7 @@ ped_disk_probe (PedDevice* dev)
 {
         PedDiskType* walk = NULL;
 
-        PED_ASSERT (dev != NULL, return NULL);
+        PED_ASSERT (dev != NULL);
 
         if (!ped_device_open (dev))
                 return NULL;
@@ -163,8 +147,15 @@ ped_disk_probe (PedDevice* dev)
         ped_exception_fetch_all ();
         for (walk = ped_disk_type_get_next (NULL); walk;
              walk = ped_disk_type_get_next (walk))
+          {
+                if (getenv ("PARTED_DEBUG")) {
+                        fprintf (stderr, "probe label: %s\n",
+                                 walk->name);
+                        fflush (stderr);
+                }
                 if (walk->ops->probe (dev))
                         break;
+          }
 
         if (ped_exception)
                 ped_exception_catch ();
@@ -175,12 +166,12 @@ ped_disk_probe (PedDevice* dev)
 }
 
 /**
- * Read the partition table off a device (if one is found). 
- * 
+ * Read the partition table off a device (if one is found).
+ *
  * \warning May modify \p dev->cylinders, \p dev->heads and \p dev->sectors
  *      if the partition table indicates that the existing values
  *      are incorrect.
- * 
+ *
  * \return A new \link _PedDisk PedDisk \endlink object;
  *         NULL on failure (e.g. partition table not detected).
  */
@@ -190,7 +181,7 @@ ped_disk_new (PedDevice* dev)
        PedDiskType*    type;
        PedDisk*        disk;
 
-       PED_ASSERT (dev != NULL, return NULL);
+       PED_ASSERT (dev != NULL);
 
        if (!ped_device_open (dev))
                goto error;
@@ -223,23 +214,26 @@ static int
 _add_duplicate_part (PedDisk* disk, PedPartition* old_part)
 {
        PedPartition*   new_part;
-       PedConstraint*  constraint_exact;
+       int ret;
 
        new_part = disk->type->ops->partition_duplicate (old_part);
        if (!new_part)
                goto error;
        new_part->disk = disk;
 
-       constraint_exact = ped_constraint_exact (&new_part->geom);
-       if (!constraint_exact)
+       if (!_disk_push_update_mode (disk))
                goto error_destroy_new_part;
-       if (!ped_disk_add_partition (disk, new_part, constraint_exact))
-                       goto error_destroy_constraint_exact;
-       ped_constraint_destroy (constraint_exact);
+       ret = _disk_raw_add (disk, new_part);
+       if (!_disk_pop_update_mode (disk))
+               goto error_destroy_new_part;
+       if (!ret)
+               goto error_destroy_new_part;
+#ifdef DEBUG
+       if (!_disk_check_sanity (disk))
+               goto error_destroy_new_part;
+#endif
        return 1;
 
-error_destroy_constraint_exact:
-       ped_constraint_destroy (constraint_exact);
 error_destroy_new_part:
        ped_partition_destroy (new_part);
 error:
@@ -257,25 +251,31 @@ ped_disk_duplicate (const PedDisk* old_disk)
        PedDisk*        new_disk;
        PedPartition*   old_part;
 
-       PED_ASSERT (old_disk != NULL, return NULL);
-       PED_ASSERT (!old_disk->update_mode, return NULL);
-       PED_ASSERT (old_disk->type->ops->duplicate != NULL, return NULL);
-       PED_ASSERT (old_disk->type->ops->partition_duplicate != NULL,
-                   return NULL);
+       PED_ASSERT (old_disk != NULL);
+       PED_ASSERT (!old_disk->update_mode);
+       PED_ASSERT (old_disk->type->ops->duplicate != NULL);
+       PED_ASSERT (old_disk->type->ops->partition_duplicate != NULL);
 
        new_disk = old_disk->type->ops->duplicate (old_disk);
        if (!new_disk)
                goto error;
 
-       _disk_push_update_mode (new_disk);
+       if (!_disk_push_update_mode (new_disk))
+               goto error_destroy_new_disk;
        for (old_part = ped_disk_next_partition (old_disk, NULL); old_part;
             old_part = ped_disk_next_partition (old_disk, old_part)) {
                if (ped_partition_is_active (old_part)) {
-                       if (!_add_duplicate_part (new_disk, old_part))
+                       if (!_add_duplicate_part (new_disk, old_part)){
+                               _disk_pop_update_mode (new_disk);
                                goto error_destroy_new_disk;
+                       }
                }
        }
-       _disk_pop_update_mode (new_disk);
+       if (!_disk_pop_update_mode (new_disk))
+               goto error_destroy_new_disk;
+
+        new_disk->needs_clobber = old_disk->needs_clobber;
+
        return new_disk;
 
 error_destroy_new_disk:
@@ -284,42 +284,67 @@ error:
        return NULL;
 }
 
+/* Given a partition table type NAME, e.g., "gpt", return its PedDiskType
+   handle.  If no known type has a name matching NAME, return NULL.  */
+static PedDiskType const *
+find_disk_type (char const *name)
+{
+  PedDiskType const *t;
+  for (t = ped_disk_type_get_next (NULL); t; t = ped_disk_type_get_next (t))
+    {
+      if (strcmp (t->name, name) == 0)
+        return t;
+    }
+  return NULL;
+}
+
 /**
  * Remove all identifying signatures of a partition table,
- * except for partition tables of a given type.
- * 
+ *
  * \return 0 on error, 1 otherwise.
- * 
+ *
  * \sa ped_disk_clobber()
  */
 int
-ped_disk_clobber_exclude (PedDevice* dev, const PedDiskType* exclude)
+ped_disk_clobber (PedDevice* dev)
 {
-       PedDiskType*    walk;
-
-       PED_ASSERT (dev != NULL, goto error);
+       PED_ASSERT (dev != NULL);
 
        if (!ped_device_open (dev))
                goto error;
 
-       for (walk = ped_disk_type_get_next (NULL); walk;
-            walk = ped_disk_type_get_next (walk)) {
-               int     probed;
+        PedDiskType const *gpt = find_disk_type ("gpt");
+       PED_ASSERT (gpt != NULL);
+
+        /* If there is a GPT table, don't clobber the protective MBR.  */
+        bool is_gpt = gpt->ops->probe (dev);
+        PedSector first_sector = (is_gpt ? 1 : 0);
+
+       /* How many sectors to zero out at each end.
+          This must be large enough to zero out the magic bytes
+          starting at offset 8KiB on a DASD partition table.
+          Doing the same from the end of the disk is probably
+          overkill, but at least on GPT, we do need to zero out
+          the final sector.  */
+       const PedSector n_sectors = 9 * 1024 / dev->sector_size + 1;
+
+       /* Clear the first few.  */
+       PedSector n = n_sectors;
+       if (dev->length < first_sector + n_sectors)
+         n = dev->length - first_sector;
+        if (!ptt_clear_sectors (dev, first_sector, n))
+          goto error_close_dev;
+
+       /* Clear the last few.  */
+       PedSector t = (dev->length -
+                      (n_sectors < dev->length ? n_sectors : 1));
+
+        /* Don't clobber the pMBR if we have a pathologically small disk.  */
+        if (t < first_sector)
+          t = first_sector;
+        if (!ptt_clear_sectors (dev, t, dev->length - t))
+          goto error_close_dev;
 
-               if (walk == exclude)
-                       continue;
-
-               ped_exception_fetch_all ();
-               probed = walk->ops->probe (dev);
-               if (!probed)
-                       ped_exception_catch ();
-               ped_exception_leave_all ();
-
-               if (probed && walk->ops->clobber) {
-                       if (!walk->ops->clobber (dev))
-                               goto error_close_dev;
-               }
-       }
        ped_device_close (dev);
        return 1;
 
@@ -329,25 +354,12 @@ error:
        return 0;
 }
 
-/** 
- * Remove all identifying signatures of a partition table,
- * 
- * \return 0 on error, 1 otherwise.
- * 
- * \sa ped_disk_clobber_exclude()
- */
-int
-ped_disk_clobber (PedDevice* dev)
-{
-       return ped_disk_clobber_exclude (dev, NULL);
-}
-
 /**
  * Create a new partition table on \p dev.
  *
  * This new partition table is only created in-memory, and nothing is written
  * to disk until ped_disk_commit_to_dev() is called.
- * 
+ *
  * \return The newly constructed \link _PedDisk PedDisk \endlink,
  *      NULL on failure.
  */
@@ -356,21 +368,25 @@ ped_disk_new_fresh (PedDevice* dev, const PedDiskType* type)
 {
        PedDisk*        disk;
 
-       PED_ASSERT (dev != NULL, return NULL);
-       PED_ASSERT (type != NULL, return NULL);
-       PED_ASSERT (type->ops->alloc != NULL, return NULL);
+       PED_ASSERT (dev != NULL);
+       PED_ASSERT (type != NULL);
+       PED_ASSERT (type->ops->alloc != NULL);
+       PedCHSGeometry* bios_geom = &dev->bios_geom;
+       PED_ASSERT (bios_geom->sectors != 0);
+       PED_ASSERT (bios_geom->heads != 0);
 
        disk = type->ops->alloc (dev);
        if (!disk)
                        goto error;
-       _disk_pop_update_mode (disk);
-       PED_ASSERT (disk->update_mode == 0, goto error_destroy_disk);
+        if (!_disk_pop_update_mode (disk))
+                goto error_destroy_disk;
+       PED_ASSERT (disk->update_mode == 0);
 
        disk->needs_clobber = 1;
        return disk;
 
 error_destroy_disk:
-       ped_disk_destroy (disk);
+        ped_disk_destroy (disk);
 error:
        return NULL;
 }
@@ -390,7 +406,6 @@ _ped_disk_alloc (const PedDevice* dev, const PedDiskType* disk_type)
        disk->part_list = NULL;
        return disk;
 
-       ped_free (disk);
 error:
        return NULL;
 }
@@ -400,7 +415,7 @@ _ped_disk_free (PedDisk* disk)
 {
        _disk_push_update_mode (disk);
        ped_disk_delete_all (disk);
-       ped_free (disk);
+       free (disk);
 }
 
 /**
@@ -413,8 +428,8 @@ _ped_disk_free (PedDisk* disk)
 void
 ped_disk_destroy (PedDisk* disk)
 {
-       PED_ASSERT (disk != NULL, return);
-       PED_ASSERT (!disk->update_mode, return);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (!disk->update_mode);
 
        disk->type->ops->free (disk);
 }
@@ -429,13 +444,13 @@ ped_disk_destroy (PedDisk* disk)
  * use the new blkpg interface to tell Linux where each partition
  * starts/ends, etc. In this case, Linux does not need to have support for
  * a specific type of partition table.
- * 
+ *
  * \return 0 on failure, 1 otherwise.
  */
 int
 ped_disk_commit_to_os (PedDisk* disk)
 {
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        if (!ped_device_open (disk->dev))
                goto error;
@@ -459,8 +474,8 @@ error:
 int
 ped_disk_commit_to_dev (PedDisk* disk)
 {
-       PED_ASSERT (disk != NULL, goto error);
-       PED_ASSERT (!disk->update_mode, goto error);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (!disk->update_mode);
 
        if (!disk->type->ops->write) {
                ped_exception_throw (
@@ -476,7 +491,7 @@ ped_disk_commit_to_dev (PedDisk* disk)
                goto error;
 
        if (disk->needs_clobber) {
-               if (!ped_disk_clobber_exclude (disk->dev, disk->type))
+               if (!ped_disk_clobber (disk->dev))
                        goto error_close_dev;
                disk->needs_clobber = 0;
        }
@@ -503,9 +518,25 @@ error:
 int
 ped_disk_commit (PedDisk* disk)
 {
+        /* Open the device here, so that the underlying fd is not closed
+           between commit_to_dev and commit_to_os (closing causes unwanted
+           udev events to be sent under Linux). */
+       if (!ped_device_open (disk->dev))
+               goto error;
+
        if (!ped_disk_commit_to_dev (disk))
-               return 0;
-       return ped_disk_commit_to_os (disk);
+               goto error_close_dev;
+
+       if (!ped_disk_commit_to_os (disk))
+               goto error_close_dev;
+
+       ped_device_close (disk->dev);
+       return 1;
+
+error_close_dev:
+       ped_device_close (disk->dev);
+error:
+       return 0;
 }
 
 /**
@@ -525,7 +556,7 @@ ped_disk_commit (PedDisk* disk)
 int
 ped_partition_is_busy (const PedPartition* part)
 {
-       PED_ASSERT (part != NULL, return 1);
+       PED_ASSERT (part != NULL);
 
        return ped_architecture->disk_ops->partition_is_busy (part);
 }
@@ -537,7 +568,7 @@ ped_partition_is_busy (const PedPartition* part)
 char*
 ped_partition_get_path (const PedPartition* part)
 {
-       PED_ASSERT (part != NULL, return NULL);
+       PED_ASSERT (part != NULL);
 
        return ped_architecture->disk_ops->partition_get_path (part);
 }
@@ -566,7 +597,7 @@ ped_disk_check (const PedDisk* disk)
 {
        PedPartition*   walk;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        for (walk = disk->part_list; walk;
             walk = ped_disk_next_partition (disk, walk)) {
@@ -584,12 +615,14 @@ ped_disk_check (const PedDisk* disk)
 
                length_error = abs (walk->geom.length - geom->length);
                max_length_error = PED_MAX (4096, walk->geom.length / 100);
-               if (!ped_geometry_test_inside (&walk->geom, geom)
-                   || length_error > max_length_error) {
-                       char* part_size = ped_unit_format (disk->dev, walk->geom.length);
-                       char* fs_size = ped_unit_format (disk->dev, geom->length);
+                bool ok = (ped_geometry_test_inside (&walk->geom, geom)
+                           && length_error <= max_length_error);
+                char *fs_size = ped_unit_format (disk->dev, geom->length);
+                ped_geometry_destroy (geom);
+                if (!ok) {
+                       char* part_size = ped_unit_format (disk->dev,
+                                                           walk->geom.length);
                        PedExceptionOption choice;
-
                        choice = ped_exception_throw (
                                PED_EXCEPTION_WARNING,
                                PED_EXCEPTION_IGNORE_CANCEL,
@@ -597,12 +630,15 @@ ped_disk_check (const PedDisk* disk)
                                  "%s."),
                                walk->num, part_size, fs_size);
 
-                       ped_free (part_size);
-                       ped_free (fs_size);
+                       free (part_size);
+
+                       free (fs_size);
+                       fs_size = NULL;
 
                        if (choice != PED_EXCEPTION_IGNORE)
                                return 0;
                }
+               free (fs_size);
        }
 
        return 1;
@@ -630,7 +666,7 @@ ped_disk_get_primary_partition_count (const PedDisk* disk)
        PedPartition*   walk;
        int             count = 0;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        for (walk = disk->part_list; walk;
             walk = ped_disk_next_partition (disk, walk)) {
@@ -643,7 +679,7 @@ ped_disk_get_primary_partition_count (const PedDisk* disk)
 }
 
 /**
- * Get the highest partition number on \p disk.
+ * Get the highest available partition number on \p disk.
  */
 int
 ped_disk_get_last_partition_num (const PedDisk* disk)
@@ -651,7 +687,7 @@ ped_disk_get_last_partition_num (const PedDisk* disk)
        PedPartition*   walk;
        int             highest = -1;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        for (walk = disk->part_list; walk;
             walk = ped_disk_next_partition (disk, walk)) {
@@ -663,22 +699,190 @@ ped_disk_get_last_partition_num (const PedDisk* disk)
 }
 
 /**
+ * Get the highest supported partition number on \p disk.
+ *
+ * \return 0 if call fails. 1 otherwise.
+ */
+bool
+ped_disk_get_max_supported_partition_count(const PedDisk* disk, int* supported)
+{
+       PED_ASSERT(disk != NULL);
+       PED_ASSERT(disk->type->ops->get_max_supported_partition_count != NULL);
+
+       return disk->type->ops->get_max_supported_partition_count(disk, supported);
+}
+
+/**
+ * Get the alignment needed for partition boundaries on this disk.
+ * The returned alignment describes the alignment for the start sector of the
+ * partition, for all disklabel types which require alignment, except Sun
+ * disklabels, the end sector must be aligned too. To get the end sector
+ * alignment decrease the PedAlignment offset by 1.
+ *
+ * \return NULL on error, otherwise a pointer to a dynamically allocated
+ *         alignment.
+ */
+PedAlignment*
+ped_disk_get_partition_alignment(const PedDisk *disk)
+{
+        /* disklabel handlers which don't need alignment don't define this */
+        if (!disk->type->ops->get_partition_alignment)
+                return ped_alignment_duplicate(ped_alignment_any);
+
+        return disk->type->ops->get_partition_alignment(disk);
+}
+
+/**
  * Get the maximum number of (primary) partitions the disk label supports.
- * 
+ *
  * For example, MacIntosh partition maps can have different sizes,
  * and accordingly support a different number of partitions.
  */
 int
 ped_disk_get_max_primary_partition_count (const PedDisk* disk)
 {
-       PED_ASSERT (disk->type != NULL, return 0);
-       PED_ASSERT (disk->type->ops->get_max_primary_partition_count != NULL,
-                   return 0);
+       PED_ASSERT (disk->type != NULL);
+       PED_ASSERT (disk->type->ops->get_max_primary_partition_count != NULL);
 
        return disk->type->ops->get_max_primary_partition_count (disk);
 }
 
 /**
+ * Set the state (\c 1 or \c 0) of a flag on a disk.
+ *
+ * \note It is an error to call this on an unavailable flag -- use
+ * ped_disk_is_flag_available() to determine which flags are available
+ * for a given disk label.
+ *
+ * \throws PED_EXCEPTION_ERROR if the requested flag is not available for this
+ *      label.
+ */
+int
+ped_disk_set_flag(PedDisk *disk, PedDiskFlag flag, int state)
+{
+        int ret;
+
+        PED_ASSERT (disk != NULL);
+
+        PedDiskOps *ops = disk->type->ops;
+
+        if (!_disk_push_update_mode(disk))
+                return 0;
+
+        if (!ped_disk_is_flag_available(disk, flag)) {
+                ped_exception_throw (
+                        PED_EXCEPTION_ERROR,
+                        PED_EXCEPTION_CANCEL,
+                        "The flag '%s' is not available for %s disk labels.",
+                        ped_disk_flag_get_name(flag),
+                        disk->type->name);
+                _disk_pop_update_mode(disk);
+                return 0;
+        }
+
+        ret = ops->disk_set_flag(disk, flag, state);
+
+        if (!_disk_pop_update_mode (disk))
+                return 0;
+
+        return ret;
+}
+
+/**
+ * Get the state (\c 1 or \c 0) of a flag on a disk.
+ */
+int
+ped_disk_get_flag(const PedDisk *disk, PedDiskFlag flag)
+{
+        PED_ASSERT (disk != NULL);
+
+        PedDiskOps *ops = disk->type->ops;
+
+        if (!ped_disk_is_flag_available(disk, flag))
+                return 0;
+
+        return ops->disk_get_flag(disk, flag);
+}
+
+/**
+ * Check whether a given flag is available on a disk.
+ *
+ * \return \c 1 if the flag is available.
+ */
+int
+ped_disk_is_flag_available(const PedDisk *disk, PedDiskFlag flag)
+{
+        PED_ASSERT (disk != NULL);
+
+        PedDiskOps *ops = disk->type->ops;
+
+        if (!ops->disk_is_flag_available)
+                return 0;
+
+        return ops->disk_is_flag_available(disk, flag);
+}
+
+/**
+ * Returns a name for a \p flag, e.g. PED_DISK_CYLINDER_ALIGNMENT will return
+ * "cylinder_alignment".
+ *
+ * \note The returned string will be in English.  However,
+ * translations are provided, so the caller can call
+ * dgettext("parted", RESULT) on the result.
+ */
+const char *
+ped_disk_flag_get_name(PedDiskFlag flag)
+{
+        switch (flag) {
+        case PED_DISK_CYLINDER_ALIGNMENT:
+                return N_("cylinder_alignment");
+
+        default:
+                ped_exception_throw (
+                        PED_EXCEPTION_BUG,
+                        PED_EXCEPTION_CANCEL,
+                        _("Unknown disk flag, %d."),
+                        flag);
+                return NULL;
+        }
+}
+
+/**
+ * Returns the flag associated with \p name.
+ *
+ * \p name can be the English
+ * string, or the translation for the native language.
+ */
+PedDiskFlag
+ped_disk_flag_get_by_name(const char *name)
+{
+        PedDiskFlag flag;
+
+        for (flag = ped_disk_flag_next(0); flag;
+             flag = ped_disk_flag_next(flag)) {
+                const char *flag_name = ped_disk_flag_get_name(flag);
+                if (strcasecmp(name, flag_name) == 0
+                    || strcasecmp(name, _(flag_name)) == 0)
+                        return flag;
+        }
+
+        return 0;
+}
+
+/**
+ * Iterates through all disk flags.
+ *
+ * ped_disk_flag_next(0) returns the first flag
+ *
+ * \return the next flag, or 0 if there are no more flags
+ */
+PedDiskFlag
+ped_disk_flag_next(PedDiskFlag flag)
+{
+        return (flag + 1) % (PED_DISK_LAST_FLAG + 1);
+}
+
+/**
  * \internal We turned a really nasty bureaucracy problem into an elegant maths
  * problem :-)  Basically, there are some constraints to a partition's
  * geometry:
@@ -704,13 +908,13 @@ _partition_align (PedPartition* part, const PedConstraint* constraint)
 {
        const PedDiskType*      disk_type;
 
-       PED_ASSERT (part != NULL, return 0);
-       PED_ASSERT (part->num != -1, return 0);
-       PED_ASSERT (part->disk != NULL, return 0);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (part->num != -1);
+       PED_ASSERT (part->disk != NULL);
        disk_type = part->disk->type;
-       PED_ASSERT (disk_type != NULL, return 0);
-       PED_ASSERT (disk_type->ops->partition_align != NULL, return 0);
-       PED_ASSERT (part->disk->update_mode, return 0);
+       PED_ASSERT (disk_type != NULL);
+       PED_ASSERT (disk_type->ops->partition_align != NULL);
+       PED_ASSERT (part->disk->update_mode);
 
        return disk_type->ops->partition_align (part, constraint);
 }
@@ -720,11 +924,11 @@ _partition_enumerate (PedPartition* part)
 {
        const PedDiskType*      disk_type;
 
-       PED_ASSERT (part != NULL, return 0);
-       PED_ASSERT (part->disk != NULL, return 0);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (part->disk != NULL);
        disk_type = part->disk->type;
-       PED_ASSERT (disk_type != NULL, return 0);
-       PED_ASSERT (disk_type->ops->partition_enumerate != NULL, return 0);
+       PED_ASSERT (disk_type != NULL);
+       PED_ASSERT (disk_type->ops->partition_enumerate != NULL);
 
        return disk_type->ops->partition_enumerate (part);
 }
@@ -740,7 +944,7 @@ ped_disk_enumerate_partitions (PedDisk* disk)
        int             i;
        int             end;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
 /* first "sort" already-numbered partitions.  (e.g. if a logical partition
  * is removed, then all logical partitions that were number higher MUST be
@@ -773,7 +977,7 @@ _disk_remove_metadata (PedDisk* disk)
        PedPartition*   walk = NULL;
        PedPartition*   next;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        next = ped_disk_next_partition (disk, walk);
 
@@ -793,7 +997,7 @@ _disk_remove_metadata (PedDisk* disk)
 static int
 _disk_alloc_metadata (PedDisk* disk)
 {
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        if (!disk->update_mode)
                _disk_remove_metadata (disk);
@@ -835,7 +1039,7 @@ _alloc_extended_freespace (PedDisk* disk)
 
        last_end = extended_part->geom.start;
        last = NULL;
-       
+
        for (walk = extended_part->part_list; walk; walk = walk->next) {
                if (walk->geom.start > last_end + 1) {
                        free_space = ped_partition_new (
@@ -914,12 +1118,13 @@ _disk_alloc_freespace (PedDisk* disk)
  * partitions are removed, making it much easier for various manipulation
  * routines...
  */
-static void
+static int
 _disk_push_update_mode (PedDisk* disk)
 {
        if (!disk->update_mode) {
 #ifdef DEBUG
-               _disk_check_sanity (disk);
+               if (!_disk_check_sanity (disk))
+                       return 0;
 #endif
 
                _disk_remove_freespace (disk);
@@ -927,24 +1132,27 @@ _disk_push_update_mode (PedDisk* disk)
                _disk_remove_metadata (disk);
 
 #ifdef DEBUG
-               _disk_check_sanity (disk);
+               if (!_disk_check_sanity (disk))
+                       return 0;
 #endif
        } else {
                disk->update_mode++;
        }
+       return 1;
 }
 
-static void
+static int
 _disk_pop_update_mode (PedDisk* disk)
 {
-       PED_ASSERT (disk->update_mode, return);
+       PED_ASSERT (disk->update_mode);
 
        if (disk->update_mode == 1) {
        /* re-allocate metadata BEFORE leaving update mode, to prevent infinite
         * recursion (metadata allocation requires update mode)
         */
 #ifdef DEBUG
-               _disk_check_sanity (disk);
+               if (!_disk_check_sanity (disk))
+                       return 0;
 #endif
 
                _disk_alloc_metadata (disk);
@@ -952,11 +1160,13 @@ _disk_pop_update_mode (PedDisk* disk)
                _disk_alloc_freespace (disk);
 
 #ifdef DEBUG
-               _disk_check_sanity (disk);
+               if (!_disk_check_sanity (disk))
+                       return 0;
 #endif
        } else {
                disk->update_mode--;
        }
+       return 1;
 }
 
 /** @} */
@@ -965,7 +1175,7 @@ _disk_pop_update_mode (PedDisk* disk)
  * \addtogroup PedPartition
  *
  * \brief Partition access.
- * 
+ *
  * @{
  */
 
@@ -976,7 +1186,7 @@ _ped_partition_alloc (const PedDisk* disk, PedPartitionType type,
 {
        PedPartition*   part;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        part = (PedPartition*) ped_malloc (sizeof (PedPartition));
        if (!part)
@@ -997,7 +1207,7 @@ _ped_partition_alloc (const PedDisk* disk, PedPartitionType type,
        return part;
 
 error_free_part:
-       ped_free (part);
+       free (part);
 error:
        return NULL;
 }
@@ -1005,7 +1215,7 @@ error:
 void
 _ped_partition_free (PedPartition* part)
 {
-       ped_free (part);
+       free (part);
 }
 
 int
@@ -1043,13 +1253,13 @@ fail:
  *
  * \note The constructed partition is not added to <tt>disk</tt>'s
  *      partition table. Use ped_disk_add_partition() to do this.
- * 
+ *
  * \return A new \link _PedPartition PedPartition \endlink object,
  *      NULL on failure.
  *
  * \throws PED_EXCEPTION_ERROR if \p type is \p EXTENDED or \p LOGICAL but the
  *      label does not support this concept.
- */ 
+ */
 PedPartition*
 ped_partition_new (const PedDisk* disk, PedPartitionType type,
                   const PedFileSystemType* fs_type, PedSector start,
@@ -1058,8 +1268,8 @@ ped_partition_new (const PedDisk* disk, PedPartitionType type,
        int             supports_extended;
        PedPartition*   part;
 
-       PED_ASSERT (disk != NULL, return NULL);
-       PED_ASSERT (disk->type->ops->partition_new != NULL, return NULL);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (disk->type->ops->partition_new != NULL);
 
        supports_extended = ped_disk_type_check_feature (disk->type,
                                PED_DISK_TYPE_EXTENDED);
@@ -1101,9 +1311,9 @@ error:
 void
 ped_partition_destroy (PedPartition* part)
 {
-       PED_ASSERT (part != NULL, return);
-       PED_ASSERT (part->disk != NULL, return);
-       PED_ASSERT (part->disk->type->ops->partition_new != NULL, return);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (part->disk != NULL);
+       PED_ASSERT (part->disk->type->ops->partition_new != NULL);
 
        part->disk->type->ops->partition_destroy (part);
 }
@@ -1118,7 +1328,7 @@ ped_partition_destroy (PedPartition* part)
 int
 ped_partition_is_active (const PedPartition* part)
 {
-       PED_ASSERT (part != NULL, return 0);
+       PED_ASSERT (part != NULL);
 
        return !(part->type & PED_PARTITION_FREESPACE
                 || part->type & PED_PARTITION_METADATA);
@@ -1126,7 +1336,7 @@ ped_partition_is_active (const PedPartition* part)
 
 /**
  * Set the state (\c 1 or \c 0) of a flag on a partition.
- * 
+ *
  * Flags are disk label specific, although they have a global
  * "namespace": the flag PED_PARTITION_BOOT, for example, roughly means
  * "this" partition is bootable". But this means different things on different
@@ -1134,7 +1344,7 @@ ped_partition_is_active (const PedPartition* part)
  * on MS-DOS disk labels, there can only be one boot partition, and this
  * refers to the partition that will be booted from on startup. On PC98
  * disk labels, the user can choose from any bootable partition on startup.
- * 
+ *
  * \note It is an error to call this on an unavailable flag -- use
  * ped_partition_is_flag_available() to determine which flags are available
  * for a given disk label.
@@ -1147,13 +1357,13 @@ ped_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
 {
        PedDiskOps*     ops;
 
-       PED_ASSERT (part != NULL, return 0);
-       PED_ASSERT (part->disk != NULL, return 0);
-       PED_ASSERT (ped_partition_is_active (part), return 0);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (part->disk != NULL);
+       PED_ASSERT (ped_partition_is_active (part));
 
        ops = part->disk->type->ops;
-       PED_ASSERT (ops->partition_set_flag != NULL, return 0);
-       PED_ASSERT (ops->partition_is_flag_available != NULL, return 0);
+       PED_ASSERT (ops->partition_set_flag != NULL);
+       PED_ASSERT (ops->partition_is_flag_available != NULL);
 
        if (!ops->partition_is_flag_available (part, flag)) {
                ped_exception_throw (
@@ -1178,11 +1388,10 @@ ped_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
 int
 ped_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
 {
-       PED_ASSERT (part != NULL, return 0);
-       PED_ASSERT (part->disk != NULL, return 0);
-       PED_ASSERT (part->disk->type->ops->partition_get_flag != NULL,
-                   return 0);
-       PED_ASSERT (ped_partition_is_active (part), return 0);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (part->disk != NULL);
+       PED_ASSERT (part->disk->type->ops->partition_get_flag != NULL);
+       PED_ASSERT (ped_partition_is_active (part));
 
        return part->disk->type->ops->partition_get_flag (part, flag);
 }
@@ -1196,11 +1405,10 @@ int
 ped_partition_is_flag_available (const PedPartition* part,
                                 PedPartitionFlag flag)
 {
-       PED_ASSERT (part != NULL, return 0);
-       PED_ASSERT (part->disk != NULL, return 0);
-       PED_ASSERT (part->disk->type->ops->partition_is_flag_available != NULL,
-                   return 0);
-       PED_ASSERT (ped_partition_is_active (part), return 0);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (part->disk != NULL);
+       PED_ASSERT (part->disk->type->ops->partition_is_flag_available != NULL);
+       PED_ASSERT (ped_partition_is_active (part));
 
        return part->disk->type->ops->partition_is_flag_available (part, flag);
 }
@@ -1218,13 +1426,13 @@ ped_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
 {
        const PedDiskType*      disk_type;
 
-       PED_ASSERT (part != NULL, return 0);
-       PED_ASSERT (ped_partition_is_active (part), return 0);
-       PED_ASSERT (part->disk != NULL, return 0);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (ped_partition_is_active (part));
+       PED_ASSERT (part->disk != NULL);
        disk_type = part->disk->type;
-       PED_ASSERT (disk_type != NULL, return 0);
-       PED_ASSERT (disk_type->ops != NULL, return 0);
-       PED_ASSERT (disk_type->ops->partition_set_system != NULL, return 0);
+       PED_ASSERT (disk_type != NULL);
+       PED_ASSERT (disk_type->ops != NULL);
+       PED_ASSERT (disk_type->ops->partition_set_system != NULL);
 
        return disk_type->ops->partition_set_system (part, fs_type);
 }
@@ -1253,7 +1461,7 @@ _assert_partition_name_feature (const PedDiskType* disk_type)
  * ped_disk_type_check_feature (part->disk->type, PED_DISK_TYPE_PARTITION_NAME);
  *      \endcode
  *      to check whether this feature is enabled for a label.
- *      
+ *
  * \note \p name will not be modified by libparted. It can be freed
  *      by the caller immediately after ped_partition_set_name() is called.
  *
@@ -1262,16 +1470,15 @@ _assert_partition_name_feature (const PedDiskType* disk_type)
 int
 ped_partition_set_name (PedPartition* part, const char* name)
 {
-       PED_ASSERT (part != NULL, return 0);
-       PED_ASSERT (part->disk != NULL, return 0);
-       PED_ASSERT (ped_partition_is_active (part), return 0);
-       PED_ASSERT (name != NULL, return 0);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (part->disk != NULL);
+       PED_ASSERT (ped_partition_is_active (part));
+       PED_ASSERT (name != NULL);
 
        if (!_assert_partition_name_feature (part->disk->type))
                return 0;
 
-       PED_ASSERT (part->disk->type->ops->partition_set_name != NULL,
-                   return 0);
+       PED_ASSERT (part->disk->type->ops->partition_set_name != NULL);
        part->disk->type->ops->partition_set_name (part, name);
        return 1;
 }
@@ -1286,15 +1493,14 @@ ped_partition_set_name (PedPartition* part, const char* name)
 const char*
 ped_partition_get_name (const PedPartition* part)
 {
-       PED_ASSERT (part != NULL, return NULL);
-       PED_ASSERT (part->disk != NULL, return 0);
-       PED_ASSERT (ped_partition_is_active (part), return 0);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (part->disk != NULL);
+       PED_ASSERT (ped_partition_is_active (part));
 
        if (!_assert_partition_name_feature (part->disk->type))
                return NULL;
 
-       PED_ASSERT (part->disk->type->ops->partition_get_name != NULL,
-                   return NULL);
+       PED_ASSERT (part->disk->type->ops->partition_get_name != NULL);
        return part->disk->type->ops->partition_get_name (part);
 }
 
@@ -1311,7 +1517,7 @@ ped_disk_extended_partition (const PedDisk* disk)
 {
        PedPartition*           walk;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        for (walk = disk->part_list; walk; walk = walk->next) {
                if (walk->type == PED_PARTITION_EXTENDED)
@@ -1320,7 +1526,7 @@ ped_disk_extended_partition (const PedDisk* disk)
        return walk;
 }
 
-/** 
+/**
  * Return the next partition after \p part on \p disk. If \p part is \c NULL,
  * return the first partition. If \p part is the last partition, returns
  * \c NULL. If \p part is an extended partition, returns the first logical
@@ -1332,7 +1538,7 @@ ped_disk_extended_partition (const PedDisk* disk)
 PedPartition*
 ped_disk_next_partition (const PedDisk* disk, const PedPartition* part)
 {
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        if (!part)
                return disk->part_list;
@@ -1353,11 +1559,11 @@ _disk_check_sanity (PedDisk* disk)
 {
        PedPartition*   walk;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        for (walk = disk->part_list; walk; walk = walk->next) {
-               PED_ASSERT (!(walk->type & PED_PARTITION_LOGICAL), return 0);
-               PED_ASSERT (!walk->prev || walk->prev->next == walk, return 0);
+               PED_ASSERT (!(walk->type & PED_PARTITION_LOGICAL));
+               PED_ASSERT (!walk->prev || walk->prev->next == walk);
        }
 
        if (!ped_disk_extended_partition (disk))
@@ -1365,16 +1571,16 @@ _disk_check_sanity (PedDisk* disk)
 
        for (walk = ped_disk_extended_partition (disk)->part_list; walk;
             walk = walk->next) {
-               PED_ASSERT (walk->type & PED_PARTITION_LOGICAL, return 0);
+               PED_ASSERT (walk->type & PED_PARTITION_LOGICAL);
                if (walk->prev)
-                       PED_ASSERT (walk->prev->next == walk, return 0);
+                       PED_ASSERT (walk->prev->next == walk);
        }
        return 1;
 }
 #endif
 
 /**
- * Returns the partition numbered \p num. 
+ * Returns the partition numbered \p num.
  *
  * \return \c NULL if the specified partition does not exist.
  */
@@ -1383,7 +1589,7 @@ ped_disk_get_partition (const PedDisk* disk, int num)
 {
        PedPartition*   walk;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        for (walk = disk->part_list; walk;
             walk = ped_disk_next_partition (disk, walk)) {
@@ -1404,7 +1610,7 @@ ped_disk_get_partition_by_sector (const PedDisk* disk, PedSector sect)
 {
        PedPartition*   walk;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        for (walk = disk->part_list; walk;
             walk = ped_disk_next_partition (disk, walk)) {
@@ -1420,13 +1626,33 @@ ped_disk_get_partition_by_sector (const PedDisk* disk, PedSector sect)
        return NULL;
 }
 
+/**
+ * Return the maximum representable length (in sectors) of a
+ * partition on disk \disk.
+ */
+PedSector
+ped_disk_max_partition_length (const PedDisk* disk)
+{
+  return disk->type->ops->max_length ();
+}
+
+/**
+ * Return the maximum representable start sector of a
+ * partition on disk \disk.
+ */
+PedSector
+ped_disk_max_partition_start_sector (const PedDisk* disk)
+{
+  return disk->type->ops->max_start_sector ();
+}
+
 /* I'm beginning to agree with Sedgewick :-/ */
 static int
 _disk_raw_insert_before (PedDisk* disk, PedPartition* loc, PedPartition* part)
 {
-       PED_ASSERT (disk != NULL, return 0);
-       PED_ASSERT (loc != NULL, return 0);
-       PED_ASSERT (part != NULL, return 0);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (loc != NULL);
+       PED_ASSERT (part != NULL);
 
        part->prev = loc->prev;
        part->next = loc;
@@ -1446,9 +1672,9 @@ _disk_raw_insert_before (PedDisk* disk, PedPartition* loc, PedPartition* part)
 static int
 _disk_raw_insert_after (PedDisk* disk, PedPartition* loc, PedPartition* part)
 {
-       PED_ASSERT (disk != NULL, return 0);
-       PED_ASSERT (loc != NULL, return 0);
-       PED_ASSERT (part != NULL, return 0);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (loc != NULL);
+       PED_ASSERT (part != NULL);
 
        part->prev = loc;
        part->next = loc->next;
@@ -1462,8 +1688,8 @@ _disk_raw_insert_after (PedDisk* disk, PedPartition* loc, PedPartition* part)
 static int
 _disk_raw_remove (PedDisk* disk, PedPartition* part)
 {
-       PED_ASSERT (disk != NULL, return 0);
-       PED_ASSERT (part != NULL, return 0);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (part != NULL);
 
        if (part->prev) {
                part->prev->next = part->next;
@@ -1493,7 +1719,7 @@ _disk_raw_add (PedDisk* disk, PedPartition* part)
        PedPartition*   last;
        PedPartition*   ext_part;
 
-       PED_ASSERT (disk->update_mode, return 0);
+       PED_ASSERT (disk->update_mode);
 
        ext_part = ped_disk_extended_partition (disk);
 
@@ -1516,7 +1742,7 @@ _disk_raw_add (PedDisk* disk, PedPartition* part)
                                ext_part->part_list = part;
                        else
                                disk->part_list = part;
-               } 
+               }
        }
 
        return 1;
@@ -1530,14 +1756,14 @@ _partition_get_overlap_constraint (PedPartition* part, PedGeometry* geom)
        PedPartition*   walk;
        PedGeometry     free_space;
 
-       PED_ASSERT (part->disk->update_mode, return NULL);
-       PED_ASSERT (part->geom.dev == geom->dev, return NULL);
+       PED_ASSERT (part->disk->update_mode);
+       PED_ASSERT (part->geom.dev == geom->dev);
 
        if (part->type & PED_PARTITION_LOGICAL) {
                PedPartition* ext_part;
-               
+
                ext_part = ped_disk_extended_partition (part->disk);
-               PED_ASSERT (ext_part != NULL, return NULL);
+               PED_ASSERT (ext_part != NULL);
 
                min_start = ext_part->geom.start;
                max_end = ext_part->geom.end;
@@ -1574,7 +1800,7 @@ _partition_get_overlap_constraint (PedPartition* part, PedGeometry* geom)
  * Returns \c 0 if the partition, \p part overlaps with any partitions on the
  * \p disk.  The geometry of \p part is taken to be \p geom, NOT \p part->geom
  * (the idea here is to check if \p geom is valid, before changing \p part).
- * 
+ *
  * This is useful for seeing if a resized partitions new geometry is going to
  * fit, without the existing geomtry getting in the way.
  *
@@ -1586,8 +1812,8 @@ _disk_check_part_overlaps (PedDisk* disk, PedPartition* part)
 {
        PedPartition*   walk;
 
-       PED_ASSERT (disk != NULL, return 0);
-       PED_ASSERT (part != NULL, return 0);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (part != NULL);
 
        for (walk = ped_disk_next_partition (disk, NULL); walk;
             walk = ped_disk_next_partition (disk, walk)) {
@@ -1617,11 +1843,11 @@ _partition_check_basic_sanity (PedDisk* disk, PedPartition* part)
 {
        PedPartition*   ext_part = ped_disk_extended_partition (disk);
 
-       PED_ASSERT (part->disk == disk, return 0);
+       PED_ASSERT (part->disk == disk);
 
-       PED_ASSERT (part->geom.start >= 0, return 0);
-       PED_ASSERT (part->geom.end < disk->dev->length, return 0);
-       PED_ASSERT (part->geom.start <= part->geom.end, return 0);
+       PED_ASSERT (part->geom.start >= 0);
+       PED_ASSERT (part->geom.end < disk->dev->length);
+       PED_ASSERT (part->geom.start <= part->geom.end);
 
        if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)
            && (part->type == PED_PARTITION_EXTENDED
@@ -1666,10 +1892,10 @@ _check_extended_partition (PedDisk* disk, PedPartition* part)
        PedPartition*           walk;
        PedPartition*           ext_part;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
        ext_part = ped_disk_extended_partition (disk);
        if (!ext_part) ext_part = part;
-       PED_ASSERT (ext_part != NULL, return 0);
+       PED_ASSERT (ext_part != NULL);
 
        if (part != ext_part) {
                ped_exception_throw (
@@ -1698,7 +1924,7 @@ _check_partition (PedDisk* disk, PedPartition* part)
 {
        PedPartition*   ext_part = ped_disk_extended_partition (disk);
 
-       PED_ASSERT (part->geom.start <= part->geom.end, return 0);
+       PED_ASSERT (part->geom.start <= part->geom.end);
 
        if (part->type == PED_PARTITION_EXTENDED) {
                if (!_check_extended_partition (disk, part))
@@ -1733,12 +1959,16 @@ _check_partition (PedDisk* disk, PedPartition* part)
                return 0;
        }
 
+       if (!(part->type & PED_PARTITION_METADATA))
+               if (!disk->type->ops->partition_check(part))
+                       return 0;
+
        return 1;
 }
 
 /**
  * Adds PedPartition \p part to PedPartition \p disk.
- * 
+ *
  * \warning The partition's geometry may be changed, subject to \p constraint.
  * You could set \p constraint to <tt>ped_constraint_exact(&part->geom)</tt>,
  * but many partition table schemes have special requirements on the start
@@ -1746,7 +1976,7 @@ _check_partition (PedDisk* disk, PedPartition* part)
  * will probably mean that this function will fail (in which
  * case \p part will be left unmodified)
  * \p part is assigned a number (\p part->num) in this process.
- * 
+ *
  * \return \c 0 on failure.
  */
 int
@@ -1756,13 +1986,14 @@ ped_disk_add_partition (PedDisk* disk, PedPartition* part,
        PedConstraint*  overlap_constraint = NULL;
        PedConstraint*  constraints = NULL;
 
-       PED_ASSERT (disk != NULL, return 0);
-       PED_ASSERT (part != NULL, return 0);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (part != NULL);
 
        if (!_partition_check_basic_sanity (disk, part))
                return 0;
 
-       _disk_push_update_mode (disk);
+       if (!_disk_push_update_mode (disk))
+               return 0;
 
        if (ped_partition_is_active (part)) {
                overlap_constraint
@@ -1783,6 +2014,12 @@ ped_disk_add_partition (PedDisk* disk, PedPartition* part,
                if (!_partition_align (part, constraints))
                        goto error;
        }
+        /* FIXME: when _check_partition fails, we end up leaking PART
+           at least for DVH partition tables.  Simply calling
+           ped_partition_destroy(part) here fixes it for DVH, but
+           causes trouble for other partition types.  Similarly,
+           reordering these two checks, putting _check_partition after
+           _disk_raw_add induces an infinite loop.  */
        if (!_check_partition (disk, part))
                goto error;
        if (!_disk_raw_add (disk, part))
@@ -1790,7 +2027,8 @@ ped_disk_add_partition (PedDisk* disk, PedPartition* part,
 
        ped_constraint_destroy (overlap_constraint);
        ped_constraint_destroy (constraints);
-       _disk_pop_update_mode (disk);
+       if (!_disk_pop_update_mode (disk))
+               return 0;
 #ifdef DEBUG
        if (!_disk_check_sanity (disk))
                return 0;
@@ -1816,19 +2054,17 @@ error:
 int
 ped_disk_remove_partition (PedDisk* disk, PedPartition* part)
 {
-       PED_ASSERT (disk != NULL, return 0);
-       PED_ASSERT (part != NULL, return 0);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (part != NULL);
 
-       _disk_push_update_mode (disk);
-       PED_ASSERT (part->part_list == NULL, goto error);
+       if (!_disk_push_update_mode (disk))
+               return 0;
+       PED_ASSERT (part->part_list == NULL);
        _disk_raw_remove (disk, part);
-       _disk_pop_update_mode (disk);
+       if (!_disk_pop_update_mode (disk))
+               return 0;
        ped_disk_enumerate_partitions (disk);
        return 1;
-
-error:
-       _disk_pop_update_mode (disk);
-       return 0;
 }
 
 static int
@@ -1842,15 +2078,17 @@ ped_disk_delete_all_logical (PedDisk* disk);
 int
 ped_disk_delete_partition (PedDisk* disk, PedPartition* part)
 {
-       PED_ASSERT (disk != NULL, return 0);
-       PED_ASSERT (part != NULL, return 0);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (part != NULL);
 
-       _disk_push_update_mode (disk);
+       if (!_disk_push_update_mode (disk))
+               return 0;
        if (part->type == PED_PARTITION_EXTENDED)
                ped_disk_delete_all_logical (disk);
        ped_disk_remove_partition (disk, part);
        ped_partition_destroy (part);
-       _disk_pop_update_mode (disk);
+       if (!_disk_pop_update_mode (disk))
+               return 0;
 
        return 1;
 }
@@ -1862,9 +2100,9 @@ ped_disk_delete_all_logical (PedDisk* disk)
        PedPartition*           next;
        PedPartition*           ext_part;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
        ext_part = ped_disk_extended_partition (disk);
-       PED_ASSERT (ext_part != NULL, return 0);
+       PED_ASSERT (ext_part != NULL);
 
        for (walk = ext_part->part_list; walk; walk = next) {
                next = walk->next;
@@ -1886,18 +2124,22 @@ ped_disk_delete_all (PedDisk* disk)
        PedPartition*           walk;
        PedPartition*           next;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
-       _disk_push_update_mode (disk);
+       if (!_disk_push_update_mode (disk))
+               return 0;
 
        for (walk = disk->part_list; walk; walk = next) {
                next = walk->next;
 
-               if (!ped_disk_delete_partition (disk, walk))
+               if (!ped_disk_delete_partition (disk, walk)) {
+                       _disk_pop_update_mode(disk);
                        return 0;
+                }
        }
 
-       _disk_pop_update_mode (disk);
+       if (!_disk_pop_update_mode (disk))
+               return 0;
 
        return 1;
 }
@@ -1910,7 +2152,7 @@ ped_disk_delete_all (PedDisk* disk)
  * to \p constraint.
  *
  * \warning The constraint warning from ped_disk_add_partition() applies.
- * 
+ *
  * \note this function does not modify the contents of the partition.  You need
  *       to call ped_file_system_resize() separately.
  */
@@ -1924,14 +2166,15 @@ ped_disk_set_partition_geom (PedDisk* disk, PedPartition* part,
        PedGeometry     old_geom;
        PedGeometry     new_geom;
 
-       PED_ASSERT (disk != NULL, return 0);
-       PED_ASSERT (part != NULL, return 0);
-       PED_ASSERT (part->disk == disk, return 0);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (part != NULL);
+       PED_ASSERT (part->disk == disk);
 
        old_geom = part->geom;
        ped_geometry_init (&new_geom, part->geom.dev, start, end - start + 1);
 
-       _disk_push_update_mode (disk);
+       if (!_disk_push_update_mode (disk))
+               return 0;
 
        overlap_constraint
                = _partition_get_overlap_constraint (part, &new_geom);
@@ -1954,7 +2197,8 @@ ped_disk_set_partition_geom (PedDisk* disk, PedPartition* part,
        _disk_raw_remove (disk, part);
        _disk_raw_add (disk, part);
 
-       _disk_pop_update_mode (disk);
+       if (!_disk_pop_update_mode (disk))
+               goto error;
 
        ped_constraint_destroy (overlap_constraint);
        ped_constraint_destroy (constraints);
@@ -1962,6 +2206,7 @@ ped_disk_set_partition_geom (PedDisk* disk, PedPartition* part,
 
 error_pop_update_mode:
        _disk_pop_update_mode (disk);
+error:
        ped_constraint_destroy (overlap_constraint);
        ped_constraint_destroy (constraints);
        part->geom = old_geom;
@@ -1971,7 +2216,7 @@ error_pop_update_mode:
 /**
  * Grow PedPartition \p part geometry to the maximum possible subject to
  * \p constraint.  The new geometry will be a superset of the old geometry.
- * 
+ *
  * \return 0 on failure
  */
 int
@@ -1986,11 +2231,11 @@ ped_disk_maximize_partition (PedDisk* disk, PedPartition* part,
        PedPartition*   ext_part = ped_disk_extended_partition (disk);
        PedConstraint*  constraint_any;
 
-       PED_ASSERT (disk != NULL, return 0);
-       PED_ASSERT (part != NULL, return 0);
+       PED_ASSERT (disk != NULL);
+       PED_ASSERT (part != NULL);
 
        if (part->type & PED_PARTITION_LOGICAL) {
-               PED_ASSERT (ext_part != NULL, return 0);
+               PED_ASSERT (ext_part != NULL);
                global_min_start = ext_part->geom.start;
                global_max_end = ext_part->geom.end;
        } else {
@@ -2000,7 +2245,8 @@ ped_disk_maximize_partition (PedDisk* disk, PedPartition* part,
 
        old_geom = part->geom;
 
-       _disk_push_update_mode (disk);
+       if (!_disk_push_update_mode (disk))
+               return 0;
 
        if (part->prev)
                new_start = part->prev->geom.end + 1;
@@ -2016,7 +2262,8 @@ ped_disk_maximize_partition (PedDisk* disk, PedPartition* part,
                                          new_end))
                goto error;
 
-       _disk_pop_update_mode (disk);
+       if (!_disk_pop_update_mode (disk))
+               return 0;
        return 1;
 
 error:
@@ -2042,9 +2289,9 @@ ped_disk_get_max_partition_geometry (PedDisk* disk, PedPartition* part,
        PedGeometry*    max_geom;
        PedConstraint*  constraint_exact;
 
-       PED_ASSERT(disk != NULL, return NULL);
-       PED_ASSERT(part != NULL, return NULL);
-       PED_ASSERT(ped_partition_is_active (part), return NULL);
+       PED_ASSERT(disk != NULL);
+       PED_ASSERT(part != NULL);
+       PED_ASSERT(ped_partition_is_active (part));
 
        old_geom = part->geom;
        if (!ped_disk_maximize_partition (disk, part, constraint))
@@ -2059,13 +2306,12 @@ ped_disk_get_max_partition_geometry (PedDisk* disk, PedPartition* part,
        /* this assertion should never fail, because the old
         * geometry was valid
         */
-       PED_ASSERT (ped_geometry_test_equal (&part->geom, &old_geom),
-                   return NULL);
+       PED_ASSERT (ped_geometry_test_equal (&part->geom, &old_geom));
 
        return max_geom;
 }
 
-/** 
+/**
  * Reduce the size of the extended partition to a minimum while still wrapping
  * its logical partitions.  If there are no logical partitions, remove the
  * extended partition.
@@ -2082,17 +2328,19 @@ ped_disk_minimize_extended_partition (PedDisk* disk)
        PedConstraint*          constraint;
        int                     status;
 
-       PED_ASSERT (disk != NULL, return 0);
+       PED_ASSERT (disk != NULL);
 
        ext_part = ped_disk_extended_partition (disk);
        if (!ext_part)
                return 1;
 
-       _disk_push_update_mode (disk);
+       if (!_disk_push_update_mode (disk))
+               return 0;
 
        first_logical = ext_part->part_list;
        if (!first_logical) {
-               _disk_pop_update_mode (disk);
+               if (!_disk_pop_update_mode (disk))
+                       return 0;
                return ped_disk_delete_partition (disk, ext_part);
        }
 
@@ -2105,7 +2353,8 @@ ped_disk_minimize_extended_partition (PedDisk* disk)
                                              last_logical->geom.end);
        ped_constraint_destroy (constraint);
 
-       _disk_pop_update_mode (disk);
+       if (!_disk_pop_update_mode (disk))
+               return 0;
        return status;
 }
 
@@ -2121,11 +2370,11 @@ ped_disk_minimize_extended_partition (PedDisk* disk)
 
 /**
  * Returns a name that seems mildly appropriate for a partition type \p type.
- * 
+ *
  * Eg, if you pass (PED_PARTITION_LOGICAL & PED_PARTITION_FREESPACE), it
  * will return "free".  This isn't to be taken too seriously - it's just
  * useful for user interfaces, so you can show the user something ;-)
- * 
+ *
  * \note The returned string will be in English.  However,
  * translations are provided, so the caller can call
  * dgettext("parted", RESULT) on the result.
@@ -2149,7 +2398,7 @@ ped_partition_type_get_name (PedPartitionType type)
 
 /**
  * Returns a name for a \p flag, e.g. PED_PARTITION_BOOT will return "boot".
- * 
+ *
  * \note The returned string will be in English.  However,
  * translations are provided, so the caller can call
  * dgettext("parted", RESULT) on the result.
@@ -2160,6 +2409,8 @@ ped_partition_flag_get_name (PedPartitionFlag flag)
        switch (flag) {
        case PED_PARTITION_BOOT:
                return N_("boot");
+       case PED_PARTITION_BIOS_GRUB:
+               return N_("bios_grub");
        case PED_PARTITION_ROOT:
                return N_("root");
        case PED_PARTITION_SWAP:
@@ -2180,6 +2431,12 @@ ped_partition_flag_get_name (PedPartitionFlag flag)
                return N_("prep");
        case PED_PARTITION_MSFT_RESERVED:
                return N_("msftres");
+        case PED_PARTITION_APPLE_TV_RECOVERY:
+                return N_("atvrecv");
+        case PED_PARTITION_DIAG:
+                return N_("diag");
+        case PED_PARTITION_LEGACY_BOOT:
+                return N_("legacy_boot");
 
        default:
                ped_exception_throw (
@@ -2192,8 +2449,8 @@ ped_partition_flag_get_name (PedPartitionFlag flag)
 }
 
 /**
- * Iterates through all flags. 
- * 
+ * Iterates through all flags.
+ *
  * ped_partition_flag_next(0) returns the first flag
  *
  * \return the next flag, or 0 if there are no more flags
@@ -2205,7 +2462,7 @@ ped_partition_flag_next (PedPartitionFlag flag)
 }
 
 /**
- * Returns the flag associated with \p name.  
+ * Returns the flag associated with \p name.
  *
  * \p name can be the English
  * string, or the translation for the native language.
@@ -2230,7 +2487,7 @@ ped_partition_flag_get_by_name (const char* name)
 static void
 ped_partition_print (const PedPartition* part)
 {
-       PED_ASSERT (part != NULL, return);
+       PED_ASSERT (part != NULL);
 
        printf ("  %-10s %02d  (%d->%d)\n",
                ped_partition_type_get_name (part->type),
@@ -2254,7 +2511,7 @@ ped_disk_print (const PedDisk* disk)
 {
        PedPartition*   part;
 
-       PED_ASSERT (disk != NULL, return);
+       PED_ASSERT (disk != NULL);
 
        for (part = disk->part_list; part;
             part = ped_disk_next_partition (disk, part))