]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: (dos) Add function fdisk_dos_fix_chs() for fixing CHS values for all partitions
authorPali Rohár <pali.rohar@gmail.com>
Fri, 30 Jul 2021 09:15:15 +0000 (11:15 +0200)
committerPali Rohár <pali.rohar@gmail.com>
Fri, 30 Jul 2021 09:58:27 +0000 (11:58 +0200)
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>
libfdisk/docs/libfdisk-sections.txt
libfdisk/src/dos.c
libfdisk/src/libfdisk.h.in
libfdisk/src/libfdisk.sym

index 4894c3633bbdfaf329cd302b0966964c44b66826..1589413b86d008bfa8e3d40b314d479d51cd2de6 100644 (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>
index 0ace22666f7e0712ee3b953b33708bac9d9bd602..e72b644f2e03c333efa461a45e6f8601cf28ce7e 100644 (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)
 {
index 238aa1304b10d2f08025f55878c35a899f55046d..6d1262a55b50c5e9949da6b3d22c1024e6858321 100644 (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);
index 3e3031057150743b6abff4235e00352965694b8e..71de80589ccf259d5ac0653e9956e57978f13000 100644 (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;