diff -up util-linux-2.26.2/libfdisk/src/dos.c.kzak util-linux-2.26.2/libfdisk/src/dos.c --- util-linux-2.26.2/libfdisk/src/dos.c.kzak 2015-04-29 12:41:22.705973232 +0200 +++ util-linux-2.26.2/libfdisk/src/dos.c 2015-08-13 10:24:23.651856847 +0200 @@ -1529,7 +1529,7 @@ static int dos_add_partition(struct fdis goto done; /* pa specifies that extended partition is wanted */ - } else if (pa && pa->type && pa->type->code == MBR_DOS_EXTENDED_PARTITION) { + } else if (pa && pa->type && IS_EXTENDED(pa->type->code)) { DBG(LABEL, ul_debug("DOS: pa template %p: add extened", pa)); if (l->ext_offset) { fdisk_warnx(cxt, _("Extended partition already exists.")); @@ -1894,11 +1894,25 @@ static int dos_get_partition(struct fdis return 0; } +static int has_logical(struct fdisk_context *cxt) +{ + size_t i; + struct fdisk_dos_label *l = self_label(cxt); + + for (i = 4; i < cxt->label->nparts_max; i++) { + if (l->ptes[i].pt_entry) + return 1; + } + return 0; +} + 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; + int orgtype; fdisk_sector_t start, size; assert(cxt); @@ -1909,17 +1923,29 @@ static int dos_set_partition(struct fdis if (n >= cxt->label->nparts_max) return -EINVAL; - if (pa->type && IS_EXTENDED(pa->type->code)) { - fdisk_warnx(cxt, _("You cannot change a partition into an " - "extended one or vice versa. Delete it first.")); - return -EINVAL; - } - - 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); + orgtype = p->sys_ind; + + if (pa->type) { + if (IS_EXTENDED(pa->type->code) && l->ext_offset) { + fdisk_warnx(cxt, _("Extended partition already exists.")); + return -EINVAL; + } + + if (!pa->type->code) + fdisk_warnx(cxt, _("Type 0 means free space to many systems. " + "Having partitions of type 0 is probably unwise.")); + + if (IS_EXTENDED(p->sys_ind) && !IS_EXTENDED(pa->type->code) && has_logical(cxt)) { + fdisk_warnx(cxt, _( + "Cannot change type of the extended partition which is " + "already used by logical partitons. Delete logical " + "partitions first.")); + return -EINVAL; + } + } FDISK_INIT_UNDEF(start); FDISK_INIT_UNDEF(size); @@ -1950,6 +1976,21 @@ static int dos_set_partition(struct fdis p->boot_ind = fdisk_partition_is_bootable(pa) ? ACTIVE_FLAG : 0; } + if (pa->type) { + if (IS_EXTENDED(pa->type->code) && !IS_EXTENDED(orgtype)) { + /* new extended partition - create a reference */ + l->ext_index = n; + l->ext_offset = dos_partition_get_start(p); + pe->ex_entry = p; + } else if (IS_EXTENDED(orgtype)) { + /* remove extended partition */ + cxt->label->nparts_max = 4; + l->ptes[l->ext_index].ex_entry = NULL; + l->ext_offset = 0; + l->ext_index = 0; + } + } + partition_set_changed(cxt, n, 1); return 0; }