From: Thomas de Grivel 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 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; }