diff options
author | Karel Zak | 2014-11-20 13:11:38 +0100 |
---|---|---|
committer | Karel Zak | 2014-11-20 13:11:38 +0100 |
commit | 333c3761383d6dd166f032080055e9333b09628c (patch) | |
tree | f8d1552c10c100c40411edc9bf8da2e1a0ca60cb /libfdisk/src/dos.c | |
parent | aggety: always set default serial line speed (diff) | |
download | kernel-qcow2-util-linux-333c3761383d6dd166f032080055e9333b09628c.tar.gz kernel-qcow2-util-linux-333c3761383d6dd166f032080055e9333b09628c.tar.xz kernel-qcow2-util-linux-333c3761383d6dd166f032080055e9333b09628c.zip |
libfdisk: (dos) allow to maximize partition
The struct fdisk_partition has special flag "end_follow_default" to
make the partition large as much as possible. This patch makes this
flag usable for fdisk_set_partition() function.
Command line example (enlarge the first partition):
# echo ',+' | ./sfdisk -N1 /dev/sdb
...
Disk /dev/sdb: 100 MiB, 104857600 bytes, 204800 sectors
...
Old situation:
Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 22527 20480 10M 83 Linux
^^^^^
New situation:
Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 204799 202752 99M 83 Linux
^^^^^^
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'libfdisk/src/dos.c')
-rw-r--r-- | libfdisk/src/dos.c | 121 |
1 files changed, 96 insertions, 25 deletions
diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c index 1972ce252..54af66cf9 100644 --- a/libfdisk/src/dos.c +++ b/libfdisk/src/dos.c @@ -949,6 +949,57 @@ static int get_start_from_user( struct fdisk_context *cxt, return 0; } +static sector_t get_possible_last(struct fdisk_context *cxt, size_t n) +{ + sector_t limit; + + if (n >= 4) { + /* logical partitions */ + struct fdisk_dos_label *l = self_label(cxt); + struct pte *ext_pe = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL; + + if (!ext_pe) + return 0; + limit = get_abs_partition_end(ext_pe); + } else { + /* primary partitions */ + if (fdisk_use_cylinders(cxt) || !cxt->total_sectors) + limit = cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders - 1; + else + limit = cxt->total_sectors - 1; + + if (limit > UINT_MAX) + limit = UINT_MAX; + } + + DBG(LABEL, ul_debug("DOS: last possible sector for #%zu is %ju", + n, (uintmax_t) limit)); + return limit; +} + +/* returns last free sector for area addressed by @start, the first[] and + * last[] are fill_bounds() results */ +static sector_t get_unused_last(struct fdisk_context *cxt, size_t n, + sector_t start, + sector_t first[], sector_t last[]) +{ + size_t i; + sector_t limit = get_possible_last(cxt, n); + + for (i = 0; i < cxt->label->nparts_max; i++) { + struct pte *pe = self_pte(cxt, i); + + if (start < pe->offset && limit >= pe->offset) + limit = pe->offset - 1; + if (start < first[i] && limit >= first[i]) + limit = first[i] - 1; + } + + DBG(LABEL, ul_debug("DOS: unused sector for #%zu is %ju", + n, (uintmax_t) limit)); + return limit; +} + static int add_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partition *pa) { @@ -973,6 +1024,8 @@ static int add_partition(struct fdisk_context *cxt, size_t n, return -EINVAL; } fill_bounds(cxt, first, last); + limit = get_possible_last(cxt, n); + if (n < 4) { if (cxt->parent && fdisk_is_label(cxt->parent, GPT)) start = 1; /* Bad boy modifies hybrid MBR */ @@ -985,14 +1038,6 @@ static int add_partition(struct fdisk_context *cxt, size_t n, start = cxt->first_lba; } - if (fdisk_use_cylinders(cxt) || !cxt->total_sectors) - limit = cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders - 1; - else - limit = cxt->total_sectors - 1; - - if (limit > UINT_MAX) - limit = UINT_MAX; - if (l->ext_offset) { assert(ext_pe); first[l->ext_index] = l->ext_offset; @@ -1000,7 +1045,6 @@ static int add_partition(struct fdisk_context *cxt, size_t n, } } else { assert(ext_pe); - limit = get_abs_partition_end(ext_pe); if (cxt->script && pa && fdisk_partition_has_start(pa) && pa->start >= l->ext_offset @@ -1008,8 +1052,8 @@ static int add_partition(struct fdisk_context *cxt, size_t n, fdisk_set_first_lba(cxt, 1); start = l->ext_offset + cxt->first_lba; - } + if (fdisk_use_cylinders(cxt)) for (i = 0; i < cxt->label->nparts_max; i++) { first[i] = (fdisk_cround(cxt, first[i]) - 1) @@ -1078,14 +1122,8 @@ static int add_partition(struct fdisk_context *cxt, size_t n, } } - for (i = 0; i < cxt->label->nparts_max; i++) { - struct pte *pe = self_pte(cxt, i); + limit = get_unused_last(cxt, n, start, first, last); - if (start < pe->offset && limit >= pe->offset) - limit = pe->offset - 1; - if (start < first[i] && limit >= first[i]) - limit = first[i] - 1; - } if (start > limit) { fdisk_info(cxt, _("No free sectors available.")); if (n > 4) @@ -1822,8 +1860,10 @@ static int dos_get_partition(struct fdisk_context *cxt, size_t n, static int dos_set_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partition *pa) { + struct fdisk_dos_label *l; struct dos_partition *p; struct pte *pe; + sector_t start, size; assert(cxt); assert(pa); @@ -1842,23 +1882,54 @@ static int dos_set_partition(struct fdisk_context *cxt, size_t n, if (pa->type && !pa->type->code) fdisk_warnx(cxt, _("Type 0 means free space to many systems. " "Having partitions of type 0 is probably unwise.")); + l = self_label(cxt); + p = self_partition(cxt, n); + pe = self_pte(cxt, n); - p = self_partition(cxt, n); + FDISK_INIT_UNDEF(start); + FDISK_INIT_UNDEF(size); - if (fdisk_partition_has_start(pa) || fdisk_partition_has_size(pa)) { - sector_t start, size; + if (fdisk_partition_has_start(pa)) + start = pa->start; + if (fdisk_partition_has_size(pa)) + size = pa->size; - DBG(LABEL, ul_debug("DOS: resize partition")); + if (pa->end_follow_default) { + sector_t first[cxt->label->nparts_max], + last[cxt->label->nparts_max], + xlast; + struct pte *ext = l->ext_offset ? self_pte(cxt, l->ext_index) : NULL; + + fill_bounds(cxt, first, last); + + if (ext && l->ext_offset) { + first[l->ext_index] = l->ext_offset; + last[l->ext_index] = get_abs_partition_end(ext); + } + if (FDISK_IS_UNDEF(start)) + start = get_abs_partition_start(pe); + + DBG(LABEL, ul_debug("DOS: #%zu now %ju +%ju sectors", + n, (uintmax_t) start, (uintmax_t) dos_partition_get_size(p))); + + xlast = get_unused_last(cxt, n, start, first, last); + size = xlast ? xlast - start + 1: dos_partition_get_size(p); - pe = self_pte(cxt, n); + DBG(LABEL, ul_debug("DOS: #%zu wanted %ju +%ju sectors", + n, (uintmax_t) start, (uintmax_t) size)); + } + + if (!FDISK_IS_UNDEF(start) || !FDISK_IS_UNDEF(size)) { + DBG(LABEL, ul_debug("DOS: resize partition")); - start = fdisk_partition_has_start(pa) ? pa->start : get_abs_partition_start(pe); - size = fdisk_partition_has_size(pa) ? pa->size : dos_partition_get_size(p); + if (FDISK_IS_UNDEF(start)) + start = get_abs_partition_start(pe); + if (FDISK_IS_UNDEF(size)) + size = dos_partition_get_size(p); set_partition(cxt, n, 0, start, start + size - 1, pa->type ? pa->type->code : p->sys_ind, pa->boot == 1); - } else { DBG(LABEL, ul_debug("DOS: keep size, modify properties")); if (pa->type) |