]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: rewrite freespace code
authorKarel Zak <kzak@redhat.com>
Thu, 30 Jan 2014 11:21:11 +0000 (12:21 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 11 Mar 2014 10:35:13 +0000 (11:35 +0100)
 * use separate function to get free space
 * allow to use label-specific get_freespace() function
   (this is necessary for MBR extended partitions mess)

Signed-off-by: Karel Zak <kzak@redhat.com>
fdisks/cfdisk.c
fdisks/fdisk.c
libfdisk/src/context.c
libfdisk/src/fdiskP.h
libfdisk/src/libfdisk.h
libfdisk/src/table.c

index 1abde1abb97aba8e065aab057d6161600ea232f4..93f0db41b96397d84514f7957757f65a7f6249e4 100644 (file)
@@ -249,9 +249,11 @@ static int lines_refresh(struct cfdisk *cf)
 
        fdisk_unref_table(cf->table);
        cf->table = NULL;
-       fdisk_context_enable_freespace(cf->cxt, 1);
 
-       rc = fdisk_get_table(cf->cxt, &cf->table);
+       /* read partitions and free spaces into cf->table */
+       rc = fdisk_get_partitions(cf->cxt, &cf->table);
+       if (!rc)
+               rc = fdisk_get_freespaces(cf->cxt, &cf->table);
        if (rc)
                return rc;
 
@@ -1119,7 +1121,8 @@ static int ui_get_size(struct cfdisk *cf, const char *prompt, uintmax_t *res,
                                ui_warnx(_("Maximal size is %ju bytes."), up);
                                rc = -ERANGE;
                        }
-               }
+               } else
+                       ui_warnx(_("Failed to parse size."));
        } while (rc != 0);
 
        if (rc == 0)
@@ -1214,7 +1217,6 @@ int main(int argc, char *argv[])
                err(EXIT_FAILURE, _("failed to allocate libfdisk context"));
 
        fdisk_context_set_ask(cf->cxt, ask_callback, (void *) cf);
-       fdisk_context_enable_freespace(cf->cxt, 1);
 
        if (argc != 2)
                err(EXIT_FAILURE, "usage: %s <device>", argv[0]);
index fa74ec0ae776f1696d003eafb722d6d1d0ef7e01..ba99fe74fc877401e07bf4248a8e034803e385ee 100644 (file)
@@ -241,7 +241,7 @@ void list_disklabel(struct fdisk_context *cxt)
        fdisk_list_disklabel(cxt);
 
        /* print partitions */
-       if (fdisk_get_table(cxt, &tb))
+       if (fdisk_get_partitions(cxt, &tb))
                return;
        if (fdisk_table_to_string(tb, cxt, NULL, 0, &str) == 0) {
                fputc('\n', stdout);
index 0db21c81e069138ae036dd58cc1cb8b12ef70bae..c4054034e5f2ba418990b6a57429960e078708f8 100644 (file)
@@ -381,28 +381,6 @@ int fdisk_context_display_details(struct fdisk_context *cxt)
        return cxt->display_details == 1;
 }
 
-/**
- * fdisk_context_enable_freespace
- * cxt: context
- * enable: true/flase
- *
- * Enables or disables "free space" in list() output
- *
- * Returns: 0 on success, < 0 on error.
- */
-int fdisk_context_enable_freespace(struct fdisk_context *cxt, int enable)
-{
-       assert(cxt);
-       cxt->display_freespace = enable ? 1 : 0;
-       return 0;
-}
-
-int fdisk_context_display_freespace(struct fdisk_context *cxt)
-{
-       assert(cxt);
-       return cxt->display_freespace == 1;
-}
-
 /**
  * fdisk_context_enable_listonly:
  * cxt: context
index eb8b90bc9bbb860285c1159133fb9eb88990e70f..46e6c430e2ec5a327f27e816e4b81063bd61c359 100644 (file)
@@ -201,6 +201,13 @@ struct fdisk_table {
        size_t                  nents;          /* number of partitions */
 };
 
+extern int fdisk_table_add_freespace(
+                       struct fdisk_context *cxt,
+                       struct fdisk_table *tb,
+                       uint64_t start,
+                       uint64_t end,
+                       int dosort);
+
 /*
  * Legacy CHS based geometry
  */
@@ -253,6 +260,8 @@ struct fdisk_label_operations {
        int (*get_part)(struct fdisk_context *cxt,
                                                size_t n,
                                                struct fdisk_partition *pa);
+       /* add all gaps to table */
+       int (*get_freespace)(struct fdisk_context *cxt, struct fdisk_table *tb);
 
        int (*part_toggle_flag)(struct fdisk_context *cxt, size_t i, unsigned long flag);
 
@@ -388,7 +397,6 @@ struct fdisk_context {
 
        unsigned int display_in_cyl_units : 1,  /* for obscure labels */
                     display_details : 1,       /* expert display mode */
-                    display_freespace : 1,     /* freesapce in list() output */
                     listonly : 1;              /* list partition, nothing else */
 
        /* alignment */
index fe1d290aaca8aae0aae93335b6574f8b3e9a3750..d3f51c812d53da32aa36d684b49330275133f527 100644 (file)
@@ -98,10 +98,8 @@ extern const char *fdisk_context_get_unit(struct fdisk_context *cxt, int n);
 extern unsigned int fdisk_context_get_units_per_sector(struct fdisk_context *cxt);
 
 extern int fdisk_context_enable_details(struct fdisk_context *cxt, int enable);
-extern int fdisk_context_enable_freespace(struct fdisk_context *cxt, int enable);
 extern int fdisk_context_use_cylinders(struct fdisk_context *cxt);
 extern int fdisk_context_display_details(struct fdisk_context *cxt);
-extern int fdisk_context_display_freespace(struct fdisk_context *cxt);
 
 /* parttype.c */
 extern struct fdisk_parttype *fdisk_get_parttype_from_code(struct fdisk_context *cxt,
@@ -224,7 +222,9 @@ extern int fdisk_table_is_empty(struct fdisk_table *tb);
 extern int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa);
 extern int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa);
 
-extern int fdisk_get_table(struct fdisk_context *cxt, struct fdisk_table **tb);
+extern int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb);
+extern int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb);
+
 extern int fdisk_table_to_string(struct fdisk_table *tb,
                          struct fdisk_context *cxt,
                          int *cols, size_t ncols,  char **data);
index 88c6ebff7b9799ecc61485660d7e541cbd9b73be..af056da188fdcc69942675f219e73cca02e00b5f 100644 (file)
@@ -198,6 +198,28 @@ int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa
        return 0;
 }
 
+/* inserts @pa after @poz */
+static int table_insert_partition(
+                       struct fdisk_table *tb,
+                       struct fdisk_partition *poz,
+                       struct fdisk_partition *pa)
+{
+       assert(tb);
+       assert(pa);
+
+       fdisk_ref_partition(pa);
+       if (poz)
+               list_add(&pa->parts, &poz->parts);
+       else
+               list_add(&pa->parts, &tb->parts);
+       tb->nents++;
+
+       DBG(TAB, dbgprint("insert entry %p [start=%ju, end=%ju, size=%ju, freespace=%s]",
+                               pa, pa->start, pa->end, pa->size,
+                               pa->freespace ? "yes" : "no"));
+       return 0;
+}
+
 /**
  * fdisk_table_remove_partition
  * @tb: tab pointer
@@ -228,88 +250,141 @@ int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition
        return 0;
 }
 
-static int fdisk_table_add_freespace(
+/**
+ * fdisk_get_partitions
+ * @cxt: fdisk context
+ * @tb: returns table
+ *
+ * This function adds partitions from disklabel to @table, it allocates a new
+ * table if if @table points to NULL.
+ *
+ * Returns 0 on success, otherwise, a corresponding error.
+ */
+int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb)
+{
+       size_t i;
+
+       if (!cxt || !cxt->label || !tb)
+               return -EINVAL;
+       if (!cxt->label->op->get_part)
+               return -ENOSYS;
+
+       DBG(LABEL, dbgprint("get table"));
+
+       if (!*tb && !(*tb = fdisk_new_table()))
+               return -ENOMEM;
+
+       for (i = 0; i < cxt->label->nparts_max; i++) {
+               struct fdisk_partition *pa = NULL;
+
+               if (fdisk_get_partition(cxt, i, &pa) != 0)
+                       continue;
+               if (fdisk_partition_is_used(pa))
+                       fdisk_table_add_partition(*tb, pa);
+               fdisk_unref_partition(pa);
+       }
+
+       return 0;
+}
+
+int fdisk_table_add_freespace(
                        struct fdisk_context *cxt,
                        struct fdisk_table *tb,
                        uint64_t start,
-                       uint64_t end)
+                       uint64_t end,
+                       int dosort)
 {
        struct fdisk_partition *pa = fdisk_new_partition();
-       int rc;
-
-       if (!pa)
-               return -ENOMEM;
+       int rc = 0;
 
        assert(tb);
 
+       if (!pa)
+               return -ENOMEM;
        pa->freespace = 1;
-
        pa->start = fdisk_align_lba_in_range(cxt, start, start, end);
        pa->end = end;
        pa->size = pa->end - pa->start + 1ULL;
 
-       rc = fdisk_table_add_partition(tb, pa);
+       if (!dosort)
+               rc = fdisk_table_add_partition(tb, pa);
+       else {
+               struct fdisk_partition *x, *best = NULL;
+               struct fdisk_iter itr;
+
+               fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+               while (fdisk_table_next_partition(tb, &itr, &x) == 0) {
+                       if (x->end < pa->start && (!best || best->end < x->end))
+                               best = x;
+               }
+               rc = table_insert_partition(tb, best, pa);
+       }
        fdisk_unref_partition(pa);
        return rc;
 }
+
+
 /**
- * fdisk_get_table
+ * fdisk_get_freespaces
  * @cxt: fdisk context
- * @tb: returns table (allocate a new if not allocate yet)
+ * @tb: returns table
  *
+ * This function adds freespace (described by fdisk_partition) to @table, it
+ * allocates a new table if if @table points to NULL.
+
  * Returns 0 on success, otherwise, a corresponding error.
  */
-int fdisk_get_table(struct fdisk_context *cxt, struct fdisk_table **tb)
+int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb)
 {
-       struct fdisk_partition *pa = NULL;
+       int dosort, rc = 0;
        size_t i;
        uint64_t last, grain;
 
+       DBG(LABEL, dbgprint("get freespace"));
+
        if (!cxt || !cxt->label || !tb)
                return -EINVAL;
-       if (!cxt->label->op->get_part)
-               return -ENOSYS;
-
-       DBG(LABEL, dbgprint("get table [freespace=%s]",
-               fdisk_context_display_freespace(cxt) ? "yes" : "no"));
+       if (!*tb && !(*tb = fdisk_new_table()))
+               return -ENOMEM;
 
-       if (!*tb) {
-               *tb = fdisk_new_table();
-               if (!*tb)
-                       return -ENOMEM;
-       }
+       /* label specific way */
+       if (cxt->label->op->get_freespace)
+               return cxt->label->op->get_freespace(cxt, *tb);
 
+       /* generic way -- check for gaps betten partitions */
+       dosort = !fdisk_table_is_empty(*tb);
        last = cxt->first_lba;
        grain = cxt->grain / cxt->sector_size;
 
-       for (i = 0; i < cxt->label->nparts_max; i++) {
+       for (i = 0; rc == 0 && i < cxt->label->nparts_max; i++) {
+               struct fdisk_partition *pa = NULL;
+
                if (fdisk_get_partition(cxt, i, &pa))
                        continue;
-               if (!fdisk_partition_is_used(pa))
+               if (!fdisk_partition_is_used(pa)) {
+                       fdisk_unref_partition(pa);
                        continue;
+               }
 
                /* add free-space (before partition) to the list */
-               if (fdisk_context_display_freespace(cxt) &&
-                   last + grain < pa->start) {
-                       fdisk_table_add_freespace(cxt, *tb,
+               if (last + grain < pa->start) {
+                       rc = fdisk_table_add_freespace(cxt, *tb,
                                last + (last > cxt->first_lba ? 1 : 0),
-                               pa->start - 1);
+                               pa->start - 1,
+                               dosort);
                }
+
                last = pa->end;
-               fdisk_table_add_partition(*tb, pa);
                fdisk_unref_partition(pa);
-               pa = NULL;
        }
 
        /* add free-space (behind last partition) to the list */
-       if (fdisk_context_display_freespace(cxt) &&
-           last + grain < cxt->total_sectors - 1) {
-               fdisk_table_add_freespace(cxt, *tb,
+       if (rc == 0 && last + grain < cxt->total_sectors - 1)
+               rc = fdisk_table_add_freespace(cxt, *tb,
                        last + (last > cxt->first_lba ? 1 : 0),
-                       cxt->last_lba);
-       }
-
-       return 0;
+                       cxt->last_lba,
+                       dosort);
+       return rc;
 }
 
 /**