libfdisk: (dos) Add function fdisk_dos_fix_chs() for fixing CHS values for all partitions

This function fixes beginning and ending CHS values for every partition
according to LBA relative offset, relative beginning and size and fdisk
idea of disk geometry (sectors per track and number of heads). This
function may be used for repairing existing partitions to be compatible
with CHS addressing.

Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
This commit is contained in:
Pali Rohár 2021-07-30 11:15:15 +02:00
parent e63d9ab1d6
commit dac364addb
4 changed files with 90 additions and 3 deletions

View File

@ -220,6 +220,7 @@ DOS_FLAG_ACTIVE
fdisk_dos_enable_compatible
fdisk_dos_is_compatible
fdisk_dos_move_begin
fdisk_dos_fix_chs
</SECTION>
<SECTION>

View File

@ -780,10 +780,10 @@ static inline int chs_overflowed(unsigned int c, unsigned int h, unsigned int s)
return (c == 1023 && (h == 254 || h == 255) && s == 63);
}
static inline int lba_overflowed(unsigned int start, unsigned int sects)
static inline int lba_overflowed(fdisk_sector_t start, fdisk_sector_t sects)
{
/* Check if the last LBA sector can be represented by unsigned int */
return (start + (sects-1) < start);
/* Check if the last LBA sector can be represented by unsigned 32bit int */
return (start + (sects-1) > UINT32_MAX);
}
static void get_partition_table_geometry(struct fdisk_context *cxt,
@ -2586,6 +2586,87 @@ static int dos_reorder(struct fdisk_context *cxt)
return 0;
}
/**
* fdisk_dos_fix_chs:
* @cxt: fdisk context
*
* Fix beginning and ending C/H/S values for every partition
* according to LBA relative offset, relative beginning and
* size and fdisk idea of disk geometry (sectors per track
* and number of heads).
*
* Returns: number of fixed (changed) partitions.
*/
int fdisk_dos_fix_chs(struct fdisk_context *cxt)
{
unsigned int obc, obh, obs; /* old beginning c, h, s */
unsigned int oec, oeh, oes; /* old ending c, h, s */
unsigned int nbc, nbh, nbs; /* new beginning c, h, s */
unsigned int nec, neh, nes; /* new ending c, h, s */
fdisk_sector_t l, sects; /* lba beginning and size */
struct dos_partition *p;
struct pte *pe;
int changed = 0;
size_t i;
assert(fdisk_is_label(cxt, DOS));
for (i = 0; i < cxt->label->nparts_max; i++) {
p = self_partition(cxt, i);
if (!p || !is_used_partition(p))
continue;
pe = self_pte(cxt, i);
/* old beginning c, h, s */
obc = cylinder(p->bs, p->bc);
obh = p->bh;
obs = sector(p->bs);
/* old ending c, h, s */
oec = cylinder(p->es, p->ec);
oeh = p->eh;
oes = sector(p->es);
/* new beginning c, h, s */
l = get_abs_partition_start(pe);
long2chs(cxt, l, &nbc, &nbh, &nbs);
if (l > UINT32_MAX || nbc >= 1024) {
nbc = 1023;
nbh = cxt->geom.heads-1;
nbs = cxt->geom.sectors;
}
/* new ending c, h, s */
sects = dos_partition_get_size(p);
long2chs(cxt, l + sects - 1, &nec, &neh, &nes);
if (lba_overflowed(l, sects) || nec >= 1024) {
nec = 1023;
neh = cxt->geom.heads-1;
nes = cxt->geom.sectors;
}
if (obc != nbc || obh != nbh || obs != nbs ||
oec != nec || oeh != neh || oes != nes) {
DBG(LABEL, ul_debug("DOS: changing %zu partition CHS "
"from (%d, %d, %d)-(%d, %d, %d) "
"to (%d, %d, %d)-(%d, %d, %d)",
i+1, obc, obh, obs, oec, oeh, oes,
nbc, nbh, nbs, nec, neh, nes));
p->bc = nbc & 0xff;
p->bh = nbh;
p->bs = nbs | ((nbc >> 2) & 0xc0);
p->ec = nec & 0xff;
p->eh = neh;
p->es = nes | ((nec >> 2) & 0xc0);
partition_set_changed(cxt, i, 1);
changed++;
}
}
return changed;
}
/* TODO: use fdisk_set_partition() API */
int fdisk_dos_move_begin(struct fdisk_context *cxt, size_t i)
{

View File

@ -619,6 +619,7 @@ extern int fdisk_iter_get_direction(struct fdisk_iter *itr);
/* dos.c */
#define DOS_FLAG_ACTIVE 1
extern int fdisk_dos_fix_chs(struct fdisk_context *cxt);
extern int fdisk_dos_move_begin(struct fdisk_context *cxt, size_t i);
extern int fdisk_dos_enable_compatible(struct fdisk_label *lb, int enable);
extern int fdisk_dos_is_compatible(struct fdisk_label *lb);

View File

@ -316,3 +316,7 @@ FDISK_2.36 {
fdisk_label_advparse_parttype;
fdisk_label_get_parttype_shortcut;
} FDISK_2.35;
FDISK_2.38 {
fdisk_dos_fix_chs;
} FDISK_2.36;