sbin/newfs_msdos: Bring in -A/-T options from FreeBSD
authorTomohiro Kusumi <kusumi.tomohiro@gmail.com>
Sun, 8 Sep 2019 00:19:12 +0000 (09:19 +0900)
committerTomohiro Kusumi <kusumi.tomohiro@gmail.com>
Mon, 9 Sep 2019 02:22:48 +0000 (11:22 +0900)
Basically from FreeBSD/Git 284893ba and 8255b708.

sbin/newfs_msdos/Makefile
sbin/newfs_msdos/mkfs_msdos.c
sbin/newfs_msdos/mkfs_msdos.h
sbin/newfs_msdos/newfs_msdos.8
sbin/newfs_msdos/newfs_msdos.c

index 75b2462..b8153d0 100644 (file)
@@ -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
index bc12505..c5a7285 100644 (file)
@@ -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 <sys/param.h>
@@ -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;
index 11e945b..d94e770 100644 (file)
@@ -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;
index 8160bd8..f299817 100644 (file)
@@ -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
index b599ff5..c6d4a2b 100644 (file)
@@ -1,4 +1,6 @@
-/*
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 1998 Robert Nordier
  * All rights reserved.
  *
  * 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 <sys/param.h>
+#include <sys/stat.h>
 
 #include <err.h>
 #include <errno.h>
@@ -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);