]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: improve freesapce detection
authorKarel Zak <kzak@redhat.com>
Mon, 3 Feb 2014 13:40:27 +0000 (14:40 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 11 Mar 2014 10:35:14 +0000 (11:35 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
libfdisk/src/dos.c
libfdisk/src/fdiskP.h
libfdisk/src/libfdisk.h
libfdisk/src/partition.c
libfdisk/src/table.c

index cb34be8aba963ea1842011088ab8a22bbade62d6..327a747cf7b25e94f9b379fc644b37c3d73cb5bf 100644 (file)
@@ -1612,6 +1612,11 @@ static int dos_get_partition(struct fdisk_context *cxt, size_t n,
        pa->end = get_abs_partition_start(pe) + psects - (psects ? 1 : 0);
        pa->size = psects;
 
+       if (n >= 4) {
+               pa->parent_partno = self_label(cxt)->ext_index;
+               pa->nested = 1;
+       }
+
        if (asprintf(&pa->attrs, "%02x", p->boot_ind) < 0)
                return -ENOMEM;
 
index 46e6c430e2ec5a327f27e816e4b81063bd61c359..899a043b0acbf9f912a401f9b5692fe95450c2fe 100644 (file)
@@ -158,6 +158,7 @@ enum {
 struct fdisk_partition {
        int             refcount;               /* reference counter */
        size_t          partno;                 /* partition number */
+       size_t          parent_partno;          /* for logical partitions */
 
        uint64_t        start;                  /* first sectors */
        uint64_t        end;                    /* last sector */
@@ -188,8 +189,7 @@ struct fdisk_partition {
                        end_follow_default : 1,         /* use default end */
                        freespace : 1,          /* dthis is not partition, this is free space */
                        nested : 1,             /* logical partition */
-                       used   : 1,             /* partition already used */
-                       endrel : 1;             /* end  is specified as relative number */
+                       used   : 1;             /* partition already used */
 };
 
 #define FDISK_EMPTY_PARTNO     ((size_t) -1)
@@ -201,13 +201,6 @@ 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
  */
index af31b6b8c185ac3950be87ca320b21ef825690ed..726296c3203645a68e9e9e9b46430b84db4df3b1 100644 (file)
@@ -188,7 +188,7 @@ extern uint64_t fdisk_partition_get_start(struct fdisk_partition *pa);
 extern int fdisk_partition_cmp_start(struct fdisk_partition *a,
                              struct fdisk_partition *b);
 
-extern int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off, int isrel);
+extern int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off);
 extern uint64_t fdisk_partition_get_end(struct fdisk_partition *pa);
 extern int fdisk_partition_set_size(struct fdisk_partition *pa, uint64_t size);
 extern uint64_t fdisk_partition_get_size(struct fdisk_partition *pa);
@@ -207,6 +207,7 @@ extern const char *fdisk_partition_get_uuid(struct fdisk_partition *pa);
 extern const char *fdisk_partition_get_attrs(struct fdisk_partition *pa);
 extern int fdisk_partition_set_nested(struct fdisk_partition *pa, int nested);
 extern int fdisk_partition_is_nested(struct fdisk_partition *pa);
+extern int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent);
 extern int fdisk_partition_is_used(struct fdisk_partition *pa);
 extern int fdisk_partition_to_string(struct fdisk_partition *pa,
                                     struct fdisk_context *cxt,
index da5e75c258bae770a08d260ed2a7692f6d6b394f..20993ba3ab298b4b0839d64898f00ff51291a660 100644 (file)
@@ -72,13 +72,12 @@ int fdisk_partition_cmp_start(struct fdisk_partition *a,
        return a->start - b->start;
 }
 
-int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off, int isrel)
+int fdisk_partition_set_end(struct fdisk_partition *pa, uint64_t off)
 {
        if (!pa)
                return -EINVAL;
        pa->end = off;
        pa->size = 0;
-       pa->endrel = isrel ? 1 : 0;
        return 0;
 }
 
@@ -220,6 +219,15 @@ int fdisk_partition_is_nested(struct fdisk_partition *pa)
        return pa && pa->nested;
 }
 
+int fdisk_partition_get_parent(struct fdisk_partition *pa, size_t *parent)
+{
+       if (pa && parent)
+               *parent = pa->parent_partno;
+       else
+               return -EINVAL;
+       return 0;
+}
+
 int fdisk_partition_is_used(struct fdisk_partition *pa)
 {
        return pa && pa->used;
index 84ce357dd11a1a1333525f29699109fd9b008c7b..a78be477fb4e3c0eb54059ed6eded071888acfcc 100644 (file)
@@ -310,12 +310,13 @@ int fdisk_table_sort_partitions(struct fdisk_table *tb,
        return 0;
 }
 
-int fdisk_table_add_freespace(
+static int table_add_freespace(
                        struct fdisk_context *cxt,
                        struct fdisk_table *tb,
                        uint64_t start,
                        uint64_t end,
-                       int dosort)
+                       int dosort,
+                       struct fdisk_partition **res)
 {
        struct fdisk_partition *pa;
        int rc = 0;
@@ -346,6 +347,8 @@ int fdisk_table_add_freespace(
                }
                rc = table_insert_partition(tb, best, pa);
        }
+       if (res)
+               *res = pa;
        fdisk_unref_partition(pa);
        return rc;
 }
@@ -368,6 +371,7 @@ int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb)
        struct fdisk_table *parts = NULL;
        struct fdisk_partition *pa;
        struct fdisk_iter itr;
+       size_t cont = FDISK_EMPTY_PARTNO;
 
        DBG(LABEL, dbgprint("get freespace"));
 
@@ -390,31 +394,79 @@ int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb)
 
        dosort = !fdisk_table_is_empty(*tb);
        last = cxt->first_lba;
-       grain = cxt->grain / cxt->sector_size;
+       grain = cxt->grain > cxt->sector_size ? cxt->grain / cxt->sector_size : 1;
 
        /* analyze gaps between partitions */
        while (fdisk_table_next_partition(parts, &itr, &pa) == 0) {
-
+               if (pa->nested)
+                       cont = (int) pa->parent_partno;
+               if (!pa->used || pa->nested)
+                       continue;
                DBG(LABEL, dbgprint("freespace analyze: partno=%zu, start=%ju, end=%ju",
                                        pa->partno, pa->start, pa->end));
-
-               if (!fdisk_partition_is_used(pa))
-                       continue;
                if (last + grain < pa->start) {
-                       rc = fdisk_table_add_freespace(cxt, *tb,
+                       rc = table_add_freespace(cxt, *tb,
                                last + (last > cxt->first_lba ? 1 : 0),
                                pa->start - 1,
-                               dosort);
+                               dosort, NULL);
                }
                last = pa->end;
        }
 
-       /* add free-space (behind last partition) to the list */
+       /* add free-space behind last partition to the list */
        if (rc == 0 && last + grain < cxt->total_sectors - 1)
-               rc = fdisk_table_add_freespace(cxt, *tb,
+               rc = table_add_freespace(cxt, *tb,
                        last + (last > cxt->first_lba ? 1 : 0),
                        cxt->last_lba,
-                       dosort);
+                       dosort, NULL);
+
+       /* add gaps between logical partitions */
+       if (cont != FDISK_EMPTY_PARTNO) {
+               uint64_t x;
+               struct fdisk_partition *fr;
+               struct fdisk_partition *parent =
+                               fdisk_table_get_partition(parts, cont);
+               if (!parent)
+                       goto done;
+               last = fdisk_partition_get_start(parent) + cxt->first_lba;
+
+               DBG(LABEL, dbgprint("check container freespace last=%ju, "
+                                   "grain=%ju, partno=%zu, start=%ju, end=%ju",
+                                   last, grain, parent->partno, parent->start,
+                                   parent->end));
+
+               fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
+
+               while (fdisk_table_next_partition(parts, &itr, &pa) == 0) {
+                       uint64_t lastfree = pa->start - 1 - cxt->first_lba;
+
+                       if (!pa->used || !pa->nested)
+                               continue;
+                       if (last + grain < lastfree) {
+                               rc = table_add_freespace(cxt, *tb,
+                                               last + grain, lastfree,
+                                               dosort, &fr);
+                               if (rc == 0 && fr) {
+                                       fr->parent_partno = parent->partno;
+                                       fr->nested = 1;
+                               }
+                       }
+                       last = pa->end;
+               }
+
+               /* free-space remaining in extended partition */
+               x = fdisk_partition_get_start(parent)
+                                       + fdisk_partition_get_size(parent) - 1;
+               if (last + grain < x)
+                       rc = table_add_freespace(cxt, *tb,
+                                       last + grain, x - 1,
+                                       dosort, &fr);
+                       if (rc == 0 && fr) {
+                               fr->parent_partno = parent->partno;
+                               fr->nested = 1;
+                       }
+               }
+
 done:
        fdisk_unref_table(parts);
        return rc;