summaryrefslogtreecommitdiffstats
path: root/libfdisk/src/table.c
diff options
context:
space:
mode:
authorKarel Zak2014-01-30 12:21:11 +0100
committerKarel Zak2014-03-11 11:35:13 +0100
commit2cec7949947aa6d48112ea4f0928e6698174f342 (patch)
treecb3e63b0ef026c1f13bd7e9e99c8995aa817b8c8 /libfdisk/src/table.c
parentcfdisk: add UI for linfdisk menus, ask for size (diff)
downloadkernel-qcow2-util-linux-2cec7949947aa6d48112ea4f0928e6698174f342.tar.gz
kernel-qcow2-util-linux-2cec7949947aa6d48112ea4f0928e6698174f342.tar.xz
kernel-qcow2-util-linux-2cec7949947aa6d48112ea4f0928e6698174f342.zip
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 <kzak@redhat.com>
Diffstat (limited to 'libfdisk/src/table.c')
-rw-r--r--libfdisk/src/table.c149
1 files changed, 112 insertions, 37 deletions
diff --git a/libfdisk/src/table.c b/libfdisk/src/table.c
index 88c6ebff7..af056da18 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;
}
/**