Index | Thread | Search

From:
Thomas de Grivel <thodg@kmx.io>
Subject:
msdosfs: allocate more memory if possible and write recommended cluster sizes
To:
tech@openbsd.org
Date:
Fri, 27 Feb 2026 01:13:59 +0100

Download raw body.

Thread
  • Thomas de Grivel:

    msdosfs: allocate more memory if possible and write recommended cluster sizes

This diff adds support for more buffer memory if available and also it
uses recommended cluster sizes for Windows and Linux compatiblity. It
reduces formatting of my 128Gb USB3 stick to under 1sec and still
works without too much memory.

Index: newfs_msdos.c
===================================================================
RCS file: /cvs/src/sbin/newfs_msdos/newfs_msdos.c,v
diff -u -p -r1.30 newfs_msdos.c
--- newfs_msdos.c       17 Sep 2025 16:07:57 -0000      1.30
+++ newfs_msdos.c       26 Feb 2026 23:47:56 -0000
@@ -243,12 +243,13 @@ main(int argc, char *argv[])
     struct bsxbpb *bsxbpb;
     struct bsx *bsx;
     struct de *de;
-    u_int8_t *img;
+    u_int8_t *img, *wbuf;
     const char *dtype, *bname;
     char *sname, *fname;
     ssize_t n;
+    size_t nbytes;
     time_t now;
-    u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
+    u_int fat, bss, rds, cls, dir, x, x1, x2, wbuf_nsec;
     int ch, fd, fd1;

     if (pledge("stdio rpath wpath disklabel", NULL) == -1)
@@ -490,15 +491,28 @@ main(int argc, char *argv[])
     if (fat != 32 && !bpb.rde)
        bpb.rde = DEFRDE;
     rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
-    if (!bpb.spc)
-       for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
-            bpb.spc < MAXSPC &&
-            bpb.res +
-            howmany((RESFTE + maxcls(fat)) * (fat / BPN),
-                    bpb.bps * NPB) * bpb.nft +
-            rds +
-            (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
-            bpb.spc <<= 1);
+    if (!bpb.spc) {
+       if (fat == 32) {
+           /* Match Microsoft recommended cluster sizes */
+           if (bpb.bsec <= 16777216)   /* <= 8GB */
+               bpb.spc = 8;            /* 4KB */
+           else if (bpb.bsec <= 33554432) /* <= 16GB */
+               bpb.spc = 16;           /* 8KB */
+           else if (bpb.bsec <= 67108864) /* <= 32GB */
+               bpb.spc = 32;           /* 16KB */
+           else
+               bpb.spc = 64;           /* 32KB */
+       } else
+           for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK,
+                    bpb.bps);
+                bpb.spc < MAXSPC &&
+                bpb.res +
+                howmany((RESFTE + maxcls(fat)) * (fat / BPN),
+                        bpb.bps * NPB) * bpb.nft +
+                rds +
+                (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
+                bpb.spc <<= 1);
+    }
     if (fat != 32 && bpb.bspf > MAXU16)
        errx(1, "too many sectors/FAT for FAT12/16");
     x1 = bpb.res + rds;
@@ -553,112 +567,191 @@ main(int argc, char *argv[])
        if ((tm = localtime(&now)) == NULL)
                errx(1, "Invalid time");

-       if (!(img = malloc(bpb.bps)))
-           err(1, NULL);
        dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
-       for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
-           x = lsn;
-           if (opt_B &&
-               fat == 32 && bpb.bkbs != MAXU16 &&
-               bss <= bpb.bkbs && x >= bpb.bkbs) {
-               x -= bpb.bkbs;
-               if (!x && lseek(fd1, 0, SEEK_SET))
-                   err(1, "%s", bname);
-           }
-           if (opt_B && x < bss) {
-               if ((n = read(fd1, img, bpb.bps)) == -1)
+       wbuf_nsec = dir + (fat == 32 ? bpb.spc : rds);
+       nbytes = (size_t)wbuf_nsec * bpb.bps;
+       if (!(wbuf = calloc(wbuf_nsec, bpb.bps)))
+           err(1, NULL);
+
+       /* Fill boot sector */
+       img = wbuf;
+       if (opt_B) {
+           for (x = 0; x < bss; x++) {
+               if ((n = read(fd1, wbuf + (size_t)x * bpb.bps,
+                   bpb.bps)) == -1)
                    err(1, "%s", bname);
                if (n != bpb.bps)
                    errx(1, "%s: can't read sector %u", bname, x);
-           } else
-               memset(img, 0, bpb.bps);
-           if (!lsn ||
-             (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
-               x1 = sizeof(struct bs);
-               bsbpb = (struct bsbpb *)(img + x1);
-               mk2(bsbpb->bps, bpb.bps);
-               mk1(bsbpb->spc, bpb.spc);
-               mk2(bsbpb->res, bpb.res);
-               mk1(bsbpb->nft, bpb.nft);
-               mk2(bsbpb->rde, bpb.rde);
-               mk2(bsbpb->sec, bpb.sec);
-               mk1(bsbpb->mid, bpb.mid);
-               mk2(bsbpb->spf, bpb.spf);
-               mk2(bsbpb->spt, bpb.spt);
-               mk2(bsbpb->hds, bpb.hds);
-               mk4(bsbpb->hid, bpb.hid);
-               mk4(bsbpb->bsec, bpb.bsec);
-               x1 += sizeof(struct bsbpb);
-               if (fat == 32) {
-                   bsxbpb = (struct bsxbpb *)(img + x1);
-                   mk4(bsxbpb->bspf, bpb.bspf);
-                   mk2(bsxbpb->xflg, 0);
-                   mk2(bsxbpb->vers, 0);
-                   mk4(bsxbpb->rdcl, bpb.rdcl);
-                   mk2(bsxbpb->infs, bpb.infs);
-                   mk2(bsxbpb->bkbs, bpb.bkbs);
-                   x1 += sizeof(struct bsxbpb);
-               }
-               bsx = (struct bsx *)(img + x1);
-               mk1(bsx->sig, 0x29);
-               if (Iflag)
-                   x = opt_I;
-               else
-                   x = (((u_int)(1 + tm->tm_mon) << 8 |
-                         (u_int)tm->tm_mday) +
-                        ((u_int)tm->tm_sec << 8 |
-                         (u_int)(tv.tv_usec / 10))) << 16 |
-                       ((u_int)(1900 + tm->tm_year) +
-                        ((u_int)tm->tm_hour << 8 |
-                         (u_int)tm->tm_min));
-               mk4(bsx->volid, x);
-               mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
-               snprintf(buf, sizeof buf, "FAT%u", fat);
-               setstr(bsx->type, buf, sizeof(bsx->type));
-               if (!opt_B) {
-                   x1 += sizeof(struct bsx);
-                   bs = (struct bs *)img;
-                   mk1(bs->jmp[0], 0xeb);
-                   mk1(bs->jmp[1], x1 - 2);
-                   mk1(bs->jmp[2], 0x90);
-                   setstr(bs->oem, opt_O ? opt_O : "BSD  4.4",
-                          sizeof(bs->oem));
-                   memcpy(img + x1, bootcode, sizeof(bootcode));
-                   mk2(img + MINBPS - 2, DOSMAGIC);
+           }
+       }
+       x1 = sizeof(struct bs);
+       bsbpb = (struct bsbpb *)(img + x1);
+       mk2(bsbpb->bps, bpb.bps);
+       mk1(bsbpb->spc, bpb.spc);
+       mk2(bsbpb->res, bpb.res);
+       mk1(bsbpb->nft, bpb.nft);
+       mk2(bsbpb->rde, bpb.rde);
+       mk2(bsbpb->sec, bpb.sec);
+       mk1(bsbpb->mid, bpb.mid);
+       mk2(bsbpb->spf, bpb.spf);
+       mk2(bsbpb->spt, bpb.spt);
+       mk2(bsbpb->hds, bpb.hds);
+       mk4(bsbpb->hid, bpb.hid);
+       mk4(bsbpb->bsec, bpb.bsec);
+       x1 += sizeof(struct bsbpb);
+       if (fat == 32) {
+           bsxbpb = (struct bsxbpb *)(img + x1);
+           mk4(bsxbpb->bspf, bpb.bspf);
+           mk2(bsxbpb->xflg, 0);
+           mk2(bsxbpb->vers, 0);
+           mk4(bsxbpb->rdcl, bpb.rdcl);
+           mk2(bsxbpb->infs, bpb.infs);
+           mk2(bsxbpb->bkbs, bpb.bkbs);
+           x1 += sizeof(struct bsxbpb);
+       }
+       bsx = (struct bsx *)(img + x1);
+       mk1(bsx->sig, 0x29);
+       if (Iflag)
+           x = opt_I;
+       else
+           x = (((u_int)(1 + tm->tm_mon) << 8 |
+                 (u_int)tm->tm_mday) +
+                ((u_int)tm->tm_sec << 8 |
+                 (u_int)(tv.tv_usec / 10))) << 16 |
+               ((u_int)(1900 + tm->tm_year) +
+                ((u_int)tm->tm_hour << 8 |
+                 (u_int)tm->tm_min));
+       mk4(bsx->volid, x);
+       mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
+       snprintf(buf, sizeof buf, "FAT%u", fat);
+       setstr(bsx->type, buf, sizeof(bsx->type));
+       if (!opt_B) {
+           x1 += sizeof(struct bsx);
+           bs = (struct bs *)img;
+           mk1(bs->jmp[0], 0xeb);
+           mk1(bs->jmp[1], x1 - 2);
+           mk1(bs->jmp[2], 0x90);
+           setstr(bs->oem, opt_O ? opt_O : "BSD  4.4",
+                  sizeof(bs->oem));
+           memcpy(img + x1, bootcode, sizeof(bootcode));
+           mk2(img + MINBPS - 2, DOSMAGIC);
+       }
+
+       /* Fill backup boot sector (FAT32) */
+       if (fat == 32 && bpb.bkbs != MAXU16) {
+           img = wbuf + (size_t)bpb.bkbs * bpb.bps;
+           if (opt_B) {
+               if (lseek(fd1, 0, SEEK_SET))
+                   err(1, "%s", bname);
+               for (x = 0; x < bss; x++) {
+                   if ((n = read(fd1, img + (size_t)x * bpb.bps,
+                       bpb.bps)) == -1)
+                       err(1, "%s", bname);
+                   if (n != bpb.bps)
+                       errx(1, "%s: can't read sector %u", bname, x);
                }
-           } else if (fat == 32 && bpb.infs != MAXU16 &&
-                      (lsn == bpb.infs ||
-                       (bpb.bkbs != MAXU16 &&
-                        lsn == bpb.bkbs + bpb.infs))) {
+           }
+           x1 = sizeof(struct bs);
+           bsbpb = (struct bsbpb *)(img + x1);
+           mk2(bsbpb->bps, bpb.bps);
+           mk1(bsbpb->spc, bpb.spc);
+           mk2(bsbpb->res, bpb.res);
+           mk1(bsbpb->nft, bpb.nft);
+           mk2(bsbpb->rde, bpb.rde);
+           mk2(bsbpb->sec, bpb.sec);
+           mk1(bsbpb->mid, bpb.mid);
+           mk2(bsbpb->spf, bpb.spf);
+           mk2(bsbpb->spt, bpb.spt);
+           mk2(bsbpb->hds, bpb.hds);
+           mk4(bsbpb->hid, bpb.hid);
+           mk4(bsbpb->bsec, bpb.bsec);
+           x1 += sizeof(struct bsbpb);
+           bsxbpb = (struct bsxbpb *)(img + x1);
+           mk4(bsxbpb->bspf, bpb.bspf);
+           mk2(bsxbpb->xflg, 0);
+           mk2(bsxbpb->vers, 0);
+           mk4(bsxbpb->rdcl, bpb.rdcl);
+           mk2(bsxbpb->infs, bpb.infs);
+           mk2(bsxbpb->bkbs, bpb.bkbs);
+           x1 += sizeof(struct bsxbpb);
+           bsx = (struct bsx *)(img + x1);
+           mk1(bsx->sig, 0x29);
+           if (Iflag)
+               x = opt_I;
+           else
+               x = (((u_int)(1 + tm->tm_mon) << 8 |
+                     (u_int)tm->tm_mday) +
+                    ((u_int)tm->tm_sec << 8 |
+                     (u_int)(tv.tv_usec / 10))) << 16 |
+                   ((u_int)(1900 + tm->tm_year) +
+                    ((u_int)tm->tm_hour << 8 |
+                     (u_int)tm->tm_min));
+           mk4(bsx->volid, x);
+           mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
+           snprintf(buf, sizeof buf, "FAT%u", fat);
+           setstr(bsx->type, buf, sizeof(bsx->type));
+           if (!opt_B) {
+               x1 += sizeof(struct bsx);
+               bs = (struct bs *)img;
+               mk1(bs->jmp[0], 0xeb);
+               mk1(bs->jmp[1], x1 - 2);
+               mk1(bs->jmp[2], 0x90);
+               setstr(bs->oem, opt_O ? opt_O : "BSD  4.4",
+                      sizeof(bs->oem));
+               memcpy(img + x1, bootcode, sizeof(bootcode));
+               mk2(img + MINBPS - 2, DOSMAGIC);
+           }
+       }
+
+       /* Fill FSInfo sectors (FAT32) */
+       if (fat == 32 && bpb.infs != MAXU16) {
+           img = wbuf + (size_t)bpb.infs * bpb.bps;
+           mk4(img, 0x41615252);
+           mk4(img + MINBPS - 28, 0x61417272);
+           mk4(img + MINBPS - 24, 0xffffffff);
+           mk4(img + MINBPS - 20, 0xffffffff);
+           mk2(img + MINBPS - 2, DOSMAGIC);
+           if (bpb.bkbs != MAXU16) {
+               img = wbuf + (size_t)(bpb.bkbs + bpb.infs) * bpb.bps;
                mk4(img, 0x41615252);
                mk4(img + MINBPS - 28, 0x61417272);
                mk4(img + MINBPS - 24, 0xffffffff);
                mk4(img + MINBPS - 20, 0xffffffff);
                mk2(img + MINBPS - 2, DOSMAGIC);
-           } else if (lsn >= bpb.res && lsn < dir &&
-                      !((lsn - bpb.res) %
-                        (bpb.spf ? bpb.spf : bpb.bspf))) {
-               mk1(img[0], bpb.mid);
-               for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
-                   mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
-           } else if (lsn == dir && opt_L) {
-               de = (struct de *)img;
-               mklabel(de->namext, opt_L);
-               mk1(de->attr, 050);
-               x = (u_int)tm->tm_hour << 11 |
-                   (u_int)tm->tm_min << 5 |
-                   (u_int)tm->tm_sec >> 1;
-               mk2(de->time, x);
-               x = (u_int)(tm->tm_year - 80) << 9 |
-                   (u_int)(tm->tm_mon + 1) << 5 |
-                   (u_int)tm->tm_mday;
-               mk2(de->date, x);
            }
-           if ((n = write(fd, img, bpb.bps)) == -1)
-               err(1, "%s", fname);
-           if (n != bpb.bps)
-               errx(1, "%s: can't write sector %u", fname, lsn);
        }
+
+       /* Fill first sector of each FAT copy */
+       x2 = bpb.spf ? bpb.spf : bpb.bspf;
+       for (x = 0; x < bpb.nft; x++) {
+           img = wbuf + (size_t)(bpb.res + x * x2) * bpb.bps;
+           mk1(img[0], bpb.mid);
+           for (x1 = 1; x1 < fat * (fat == 32 ? 3 : 2) / 8; x1++)
+               mk1(img[x1], fat == 32 && x1 % 4 == 3 ? 0x0f : 0xff);
+       }
+
+       /* Fill volume label in root directory */
+       if (opt_L) {
+           img = wbuf + (size_t)dir * bpb.bps;
+           de = (struct de *)img;
+           mklabel(de->namext, opt_L);
+           mk1(de->attr, 050);
+           x = (u_int)tm->tm_hour << 11 |
+               (u_int)tm->tm_min << 5 |
+               (u_int)tm->tm_sec >> 1;
+           mk2(de->time, x);
+           x = (u_int)(tm->tm_year - 80) << 9 |
+               (u_int)(tm->tm_mon + 1) << 5 |
+               (u_int)tm->tm_mday;
+           mk2(de->date, x);
+       }
+
+       /* Write everything */
+       if ((n = write(fd, wbuf, nbytes)) == -1)
+           err(1, "%s", fname);
+       if ((size_t)n != nbytes)
+           errx(1, "%s: can't write", fname);
+       free(wbuf);
     }
     return 0;
 }