From: Karel Zak Date: Thu, 30 Jan 2014 11:21:11 +0000 (+0100) Subject: libfdisk: rewrite freespace code X-Git-Tag: v2.25-rc1~493 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2cec7949947aa6d48112ea4f0928e6698174f342;p=thirdparty%2Futil-linux.git libfdisk: rewrite freespace code * 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 --- diff --git a/fdisks/cfdisk.c b/fdisks/cfdisk.c index 1abde1abb9..93f0db41b9 100644 --- a/fdisks/cfdisk.c +++ b/fdisks/cfdisk.c @@ -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 ", argv[0]); diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c index fa74ec0ae7..ba99fe74fc 100644 --- a/fdisks/fdisk.c +++ b/fdisks/fdisk.c @@ -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); diff --git a/libfdisk/src/context.c b/libfdisk/src/context.c index 0db21c81e0..c4054034e5 100644 --- a/libfdisk/src/context.c +++ b/libfdisk/src/context.c @@ -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 diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h index eb8b90bc9b..46e6c430e2 100644 --- a/libfdisk/src/fdiskP.h +++ b/libfdisk/src/fdiskP.h @@ -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 */ diff --git a/libfdisk/src/libfdisk.h b/libfdisk/src/libfdisk.h index fe1d290aac..d3f51c812d 100644 --- a/libfdisk/src/libfdisk.h +++ b/libfdisk/src/libfdisk.h @@ -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); diff --git a/libfdisk/src/table.c b/libfdisk/src/table.c index 88c6ebff7b..af056da188 100644 --- a/libfdisk/src/table.c +++ b/libfdisk/src/table.c @@ -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; } /**