From 83751b8f5f204c52058a11caed4b2d0e7023b41f Mon Sep 17 00:00:00 2001 From: Tomohiro Kusumi Date: Sun, 8 Sep 2019 09:19:12 +0900 Subject: [PATCH] sbin/newfs_msdos: Bring in -A/-T options from FreeBSD Basically from FreeBSD/Git 284893ba and 8255b708. --- sbin/newfs_msdos/Makefile | 2 +- sbin/newfs_msdos/mkfs_msdos.c | 138 +++++++++++++++++++++------------ sbin/newfs_msdos/mkfs_msdos.h | 5 +- sbin/newfs_msdos/newfs_msdos.8 | 16 +++- sbin/newfs_msdos/newfs_msdos.c | 37 ++++++++- 5 files changed, 141 insertions(+), 57 deletions(-) diff --git a/sbin/newfs_msdos/Makefile b/sbin/newfs_msdos/Makefile index 75b2462588..b8153d0938 100644 --- a/sbin/newfs_msdos/Makefile +++ b/sbin/newfs_msdos/Makefile @@ -1,4 +1,4 @@ -# $FreeBSD: head/sbin/newfs_msdos/Makefile 298107 2016-04-16 07:45:30Z gjb $ +# $FreeBSD$ PROG= newfs_msdos SRCS= newfs_msdos.c mkfs_msdos.c diff --git a/sbin/newfs_msdos/mkfs_msdos.c b/sbin/newfs_msdos/mkfs_msdos.c index bc12505126..c5a7285c54 100644 --- a/sbin/newfs_msdos/mkfs_msdos.c +++ b/sbin/newfs_msdos/mkfs_msdos.c @@ -23,8 +23,6 @@ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/sbin/newfs_msdos/mkfs_msdos.c 305075 2016-08-30 18:01:26Z imp $ */ #include @@ -241,6 +239,8 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) ssize_t n; time_t now; u_int fat, bss, rds, cls, dir, lsn, x, x1, x2; + u_int extra_res, alignment, saved_x, attempts=0; + bool set_res, set_spf, set_spc; int fd, fd1, rv; struct msdos_options o = *op; @@ -486,50 +486,83 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) if (bpb.bpbBackup != MAXU16 && x <= bpb.bpbBackup) x = bpb.bpbBackup + 1; } - if (!bpb.bpbResSectors) - bpb.bpbResSectors = fat == 32 ? - MAX(x, MAX(16384 / bpb.bpbBytesPerSec, 4)) : x; - else if (bpb.bpbResSectors < x) { - warnx("too few reserved sectors (need %d have %d)", x, - bpb.bpbResSectors); - goto done; - } - if (fat != 32 && !bpb.bpbRootDirEnts) - bpb.bpbRootDirEnts = DEFRDE; - rds = howmany(bpb.bpbRootDirEnts, bpb.bpbBytesPerSec / sizeof(struct de)); - if (!bpb.bpbSecPerClust) - for (bpb.bpbSecPerClust = howmany(fat == 16 ? DEFBLK16 : - DEFBLK, bpb.bpbBytesPerSec); - bpb.bpbSecPerClust < MAXSPC && - bpb.bpbResSectors + - howmany((RESFTE + maxcls(fat)) * (fat / BPN), - bpb.bpbBytesPerSec * NPB) * - bpb.bpbFATs + - rds + - (uint64_t) (maxcls(fat) + 1) * - bpb.bpbSecPerClust <= bpb.bpbHugeSectors; - bpb.bpbSecPerClust <<= 1) - continue; - if (fat != 32 && bpb.bpbBigFATsecs > MAXU16) { - warnx("too many sectors/FAT for FAT12/16"); - goto done; - } - x1 = bpb.bpbResSectors + rds; - x = bpb.bpbBigFATsecs ? bpb.bpbBigFATsecs : 1; - if (x1 + (uint64_t)x * bpb.bpbFATs > bpb.bpbHugeSectors) { - warnx("meta data exceeds file system size"); - goto done; - } - x1 += x * bpb.bpbFATs; - x = (uint64_t)(bpb.bpbHugeSectors - x1) * bpb.bpbBytesPerSec * NPB / - (bpb.bpbSecPerClust * bpb.bpbBytesPerSec * NPB + fat / - BPN * bpb.bpbFATs); - x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), - bpb.bpbBytesPerSec * NPB); - if (!bpb.bpbBigFATsecs) { - bpb.bpbBigFATsecs = x2; - x1 += (bpb.bpbBigFATsecs - 1) * bpb.bpbFATs; - } + + extra_res = 0; + alignment = 0; + set_res = (bpb.bpbResSectors == 0); + set_spf = (bpb.bpbBigFATsecs == 0); + set_spc = (bpb.bpbSecPerClust == 0); + saved_x = x; + + /* + * Attempt to align the root directory to cluster if o.align is set. + * This is done by padding with reserved blocks. Note that this can + * cause other factors to change, which can in turn change the alignment. + * This should take at most 2 iterations, as increasing the reserved + * amount may cause the FAT size to decrease by 1, requiring another + * bpbFATs reserved blocks. If bpbSecPerClust changes, it will + * be half of its previous size, and thus will not throw off alignment. + */ + do { + x = saved_x; + if (set_res) + bpb.bpbResSectors = ((fat == 32) ? + MAX(x, MAX(16384 / bpb.bpbBytesPerSec, 4)) : x) + extra_res; + else if (bpb.bpbResSectors < x) { + warnx("too few reserved sectors (need %d have %d)", x, + bpb.bpbResSectors); + goto done; + } + if (fat != 32 && !bpb.bpbRootDirEnts) + bpb.bpbRootDirEnts = DEFRDE; + rds = howmany(bpb.bpbRootDirEnts, + bpb.bpbBytesPerSec / sizeof(struct de)); + if (set_spc) { + for (bpb.bpbSecPerClust = howmany(fat == 16 ? DEFBLK16 : + DEFBLK, bpb.bpbBytesPerSec); + bpb.bpbSecPerClust < MAXSPC && (bpb.bpbResSectors + + howmany((RESFTE + maxcls(fat)) * (fat / BPN), + bpb.bpbBytesPerSec * NPB) * bpb.bpbFATs + + rds + + (u_int64_t) (maxcls(fat) + 1) * bpb.bpbSecPerClust) <= + bpb.bpbHugeSectors; + bpb.bpbSecPerClust <<= 1) + continue; + + } + if (fat != 32 && bpb.bpbBigFATsecs > MAXU16) { + warnx("too many sectors/FAT for FAT12/16"); + goto done; + } + x1 = bpb.bpbResSectors + rds; + x = bpb.bpbBigFATsecs ? bpb.bpbBigFATsecs : 1; + if (x1 + (u_int64_t)x * bpb.bpbFATs > bpb.bpbHugeSectors) { + warnx("meta data exceeds file system size"); + goto done; + } + x1 += x * bpb.bpbFATs; + x = (u_int64_t)(bpb.bpbHugeSectors - x1) * bpb.bpbBytesPerSec * NPB / + (bpb.bpbSecPerClust * bpb.bpbBytesPerSec * NPB + + fat / BPN * bpb.bpbFATs); + x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), + bpb.bpbBytesPerSec * NPB); + if (set_spf) { + if (bpb.bpbBigFATsecs == 0) + bpb.bpbBigFATsecs = x2; + x1 += (bpb.bpbBigFATsecs - 1) * bpb.bpbFATs; + } + if (set_res) { + /* attempt to align root directory */ + alignment = (bpb.bpbResSectors + bpb.bpbBigFATsecs * bpb.bpbFATs) % + bpb.bpbSecPerClust; + if (o.align) + extra_res += bpb.bpbSecPerClust - alignment; + } + attempts++; + } while (o.align && alignment != 0 && attempts < 2); + if (o.align && alignment != 0) + warnx("warning: Alignment failed."); + cls = (bpb.bpbHugeSectors - x1) / bpb.bpbSecPerClust; x = (uint64_t)bpb.bpbBigFATsecs * bpb.bpbBytesPerSec * NPB / (fat / BPN) - RESFTE; @@ -567,9 +600,16 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) } print_bpb(&bpb); if (!o.no_create) { - gettimeofday(&tv, NULL); - now = tv.tv_sec; - tm = localtime(&now); + if (o.timestamp_set) { + tv.tv_sec = now = o.timestamp; + tv.tv_usec = 0; + tm = gmtime(&now); + } else { + gettimeofday(&tv, NULL); + now = tv.tv_sec; + tm = localtime(&now); + } + if (!(img = malloc(bpb.bpbBytesPerSec))) { warn(NULL); goto done; diff --git a/sbin/newfs_msdos/mkfs_msdos.h b/sbin/newfs_msdos/mkfs_msdos.h index 11e945b207..d94e77052f 100644 --- a/sbin/newfs_msdos/mkfs_msdos.h +++ b/sbin/newfs_msdos/mkfs_msdos.h @@ -1,4 +1,4 @@ -/* $FreeBSD: head/sbin/newfs_msdos/mkfs_msdos.h 291218 2015-11-23 18:56:10Z emaste $ */ +/* $FreeBSD$ */ /* $NetBSD: mkfs_msdos.h,v 1.3 2015/10/16 17:38:17 christos Exp $ */ /*- @@ -35,6 +35,7 @@ #define ALLOPTS \ AOPT('@', off_t, offset, 0, "Offset in device") \ +AOPT('A', bool, align, -2, "Attempt to cluster align root directory") \ AOPT('B', const char *, bootstrap, -1, "Bootstrap file") \ AOPT('C', off_t, create_size, 0, "Create file") \ AOPT('F', uint8_t, fat_type, 12, "FAT type (12, 16, or 32)") \ @@ -43,6 +44,7 @@ AOPT('L', const char *, volume_label, -1, "Volume Label") \ AOPT('N', bool, no_create, -2, "Don't create filesystem, print params only") \ AOPT('O', const char *, OEM_string, -1, "OEM string") \ AOPT('S', uint16_t, bytes_per_sector, 1, "Bytes per sector") \ +AOPT('T', time_t, timestamp, 0, "Timestamp") \ AOPT('a', uint32_t, sectors_per_fat, 1, "Sectors per FAT") \ AOPT('b', uint32_t, block_size, 1, "Block size") \ AOPT('c', uint8_t, sectors_per_cluster, 1, "Sectors per cluster") \ @@ -62,6 +64,7 @@ struct msdos_options { #define AOPT(_opt, _type, _name, _min, _desc) _type _name; ALLOPTS #undef AOPT + uint32_t timestamp_set:1; uint32_t volume_id_set:1; uint32_t media_descriptor_set:1; uint32_t hidden_sectors_set:1; diff --git a/sbin/newfs_msdos/newfs_msdos.8 b/sbin/newfs_msdos/newfs_msdos.8 index 8160bd8d03..f299817175 100644 --- a/sbin/newfs_msdos/newfs_msdos.8 +++ b/sbin/newfs_msdos/newfs_msdos.8 @@ -23,9 +23,9 @@ .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: head/sbin/newfs_msdos/newfs_msdos.8 287396 2015-09-02 14:08:43Z trasz $ +.\" $FreeBSD$ .\" -.Dd December 9, 2016 +.Dd September 9, 2019 .Dt NEWFS_MSDOS 8 .Os .Sh NAME @@ -35,6 +35,7 @@ .Nm .Op Fl N .Op Fl @ Ar offset +.Op Fl A .Op Fl B Ar boot .Op Fl C Ar create-size .Op Fl F Ar FAT-type @@ -42,6 +43,7 @@ .Op Fl L Ar label .Op Fl O Ar OEM .Op Fl S Ar sector-size +.Op Fl T Ar timestamp .Op Fl a Ar FAT-size .Op Fl b Ar block-size .Op Fl c Ar cluster-size @@ -90,6 +92,8 @@ Build the filesystem at the specified offset in bytes in the device or file. A suffix s, k, m, g (lower or upper case) appended to the offset specifies that the number is in sectors, kilobytes, megabytes or gigabytes, respectively. +.It Fl A +Attempt to cluster align root directory, useful for SD card. .It Fl B Ar boot Get bootstrap from file. .It Fl C Ar create-size @@ -117,6 +121,14 @@ The default is Number of bytes per sector. Acceptable values are powers of 2 in the range 512 through 32768, inclusive. +.It Fl T Ar timestamp +Create the filesystem as though the current time is +.Ar timestamp . +The default filesystem volume ID is derived from the time. +.Ar timestamp +can be a pathname (where the timestamp is derived from +that file) or an integer value interpreted +as the number of seconds since the Epoch. .It Fl a Ar FAT-size Number of sectors per FAT. .It Fl b Ar block-size diff --git a/sbin/newfs_msdos/newfs_msdos.c b/sbin/newfs_msdos/newfs_msdos.c index b599ff5032..c6d4a2bc50 100644 --- a/sbin/newfs_msdos/newfs_msdos.c +++ b/sbin/newfs_msdos/newfs_msdos.c @@ -1,4 +1,6 @@ -/* +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 1998 Robert Nordier * All rights reserved. * @@ -23,11 +25,10 @@ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $FreeBSD: head/sbin/newfs_msdos/newfs_msdos.c 291385 2015-11-27 14:40:21Z emaste $ */ #include +#include #include #include @@ -48,13 +49,30 @@ static u_int argtou(const char *, u_int, u_int, const char *); static off_t argtooff(const char *, const char *); static void usage(void); +static time_t +get_tstamp(const char *b) +{ + struct stat st; + char *eb; + long long l; + + if (stat(b, &st) != -1) + return (time_t)st.st_mtime; + + errno = 0; + l = strtoll(b, &eb, 0); + if (b == eb || *eb || errno) + errx(EXIT_FAILURE, "Can't parse timestamp '%s'", b); + return (time_t)l; +} + /* * Construct a FAT12, FAT16, or FAT32 file system. */ int main(int argc, char *argv[]) { - static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:"; + static const char opts[] = "@:NAB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:T:u:"; struct msdos_options o; const char *fname, *dtype; char buf[MAXPATHLEN]; @@ -70,6 +88,9 @@ main(int argc, char *argv[]) case 'N': o.no_create = 1; break; + case 'A': + o.align = true; + break; case 'B': o.bootstrap = optarg; break; @@ -139,6 +160,10 @@ main(int argc, char *argv[]) case 's': o.size = argto4(optarg, 1, "file system size"); break; + case 'T': + o.timestamp_set = 1; + o.timestamp = get_tstamp(optarg); + break; case 'u': o.sectors_per_track = argto2(optarg, 1, "sectors/track"); break; @@ -149,6 +174,10 @@ main(int argc, char *argv[]) argv += optind; if (argc < 1 || argc > 2) usage(); + if (o.align) { + if (o.hidden_sectors_set) + errx(1, "align (-A) is incompatible with -r"); + } fname = *argv++; if (!o.create_size && !strchr(fname, '/')) { snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); -- 2.41.0