diff options
author | Karel Zak | 2013-01-21 12:06:17 +0100 |
---|---|---|
committer | Karel Zak | 2013-03-11 12:47:30 +0100 |
commit | dfc96cbf1fee8b52d36cbcbb262024ccd3073873 (patch) | |
tree | 87da4efb44246fb7a1a7953752d08aedd4296f29 /fdisks/fdiskdoslabel.c | |
parent | fdisk: (dos) move list table code to fdiskdoslabe.c (diff) | |
download | kernel-qcow2-util-linux-dfc96cbf1fee8b52d36cbcbb262024ccd3073873.tar.gz kernel-qcow2-util-linux-dfc96cbf1fee8b52d36cbcbb262024ccd3073873.tar.xz kernel-qcow2-util-linux-dfc96cbf1fee8b52d36cbcbb262024ccd3073873.zip |
fdisk: (dos) move fix order code to fdiskdoslabe.c
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'fdisks/fdiskdoslabel.c')
-rw-r--r-- | fdisks/fdiskdoslabel.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c index da6526e3f..d174c735a 100644 --- a/fdisks/fdiskdoslabel.c +++ b/fdisks/fdiskdoslabel.c @@ -964,6 +964,39 @@ static int dos_set_parttype( return 0; } +/* + * Check whether partition entries are ordered by their starting positions. + * Return 0 if OK. Return i if partition i should have been earlier. + * Two separate checks: primary and logical partitions. + */ +static int wrong_p_order(int *prev) +{ + struct pte *pe; + struct partition *p; + unsigned int last_p_start_pos = 0, p_start_pos; + int i, last_i = 0; + + for (i = 0 ; i < partitions; i++) { + if (i == 4) { + last_i = 4; + last_p_start_pos = 0; + } + pe = &ptes[i]; + if ((p = pe->part_table)->sys_ind) { + p_start_pos = get_partition_start(pe); + + if (last_p_start_pos > p_start_pos) { + if (prev) + *prev = last_i; + return i; + } + + last_p_start_pos = p_start_pos; + last_i = i; + } + } + return 0; +} static int is_garbage_table(void) { @@ -1047,6 +1080,106 @@ int dos_list_table(struct fdisk_context *cxt, return 0; } +/* + * Fix the chain of logicals. + * extended_offset is unchanged, the set of sectors used is unchanged + * The chain is sorted so that sectors increase, and so that + * starting sectors increase. + * + * After this it may still be that cfdisk doesn't like the table. + * (This is because cfdisk considers expanded parts, from link to + * end of partition, and these may still overlap.) + * Now + * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda + * may help. + */ +static void fix_chain_of_logicals(void) +{ + int j, oj, ojj, sj, sjj; + struct partition *pj,*pjj,tmp; + + /* Stage 1: sort sectors but leave sector of part 4 */ + /* (Its sector is the global extended_offset.) */ + stage1: + for (j = 5; j < partitions-1; j++) { + oj = ptes[j].offset; + ojj = ptes[j+1].offset; + if (oj > ojj) { + ptes[j].offset = ojj; + ptes[j+1].offset = oj; + pj = ptes[j].part_table; + set_start_sect(pj, get_start_sect(pj)+oj-ojj); + pjj = ptes[j+1].part_table; + set_start_sect(pjj, get_start_sect(pjj)+ojj-oj); + set_start_sect(ptes[j-1].ext_pointer, + ojj-extended_offset); + set_start_sect(ptes[j].ext_pointer, + oj-extended_offset); + goto stage1; + } + } + + /* Stage 2: sort starting sectors */ + stage2: + for (j = 4; j < partitions-1; j++) { + pj = ptes[j].part_table; + pjj = ptes[j+1].part_table; + sj = get_start_sect(pj); + sjj = get_start_sect(pjj); + oj = ptes[j].offset; + ojj = ptes[j+1].offset; + if (oj+sj > ojj+sjj) { + tmp = *pj; + *pj = *pjj; + *pjj = tmp; + set_start_sect(pj, ojj+sjj-oj); + set_start_sect(pjj, oj+sj-ojj); + goto stage2; + } + } + + /* Probably something was changed */ + for (j = 4; j < partitions; j++) + ptes[j].changed = 1; +} + +void dos_fix_partition_table_order(void) +{ + struct pte *pei, *pek; + int i,k; + + if (!wrong_p_order(NULL)) { + printf(_("Nothing to do. Ordering is correct already.\n\n")); + return; + } + + while ((i = wrong_p_order(&k)) != 0 && i < 4) { + /* partition i should have come earlier, move it */ + /* We have to move data in the MBR */ + struct partition *pi, *pk, *pe, pbuf; + pei = &ptes[i]; + pek = &ptes[k]; + + pe = pei->ext_pointer; + pei->ext_pointer = pek->ext_pointer; + pek->ext_pointer = pe; + + pi = pei->part_table; + pk = pek->part_table; + + memmove(&pbuf, pi, sizeof(struct partition)); + memmove(pi, pk, sizeof(struct partition)); + memmove(pk, &pbuf, sizeof(struct partition)); + + pei->changed = pek->changed = 1; + } + + if (i) + fix_chain_of_logicals(); + + printf(_("Done.\n")); + +} static const struct fdisk_label_operations dos_operations = |