341 lines
15 KiB
Diff
341 lines
15 KiB
Diff
From b29eb5be67e9e8a06908ee10f6c205cb609b1021 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali.rohar@gmail.com>
|
|
Date: Wed, 15 Aug 2018 15:15:06 +0200
|
|
Subject: [PATCH 1/7] mkfs.fat: Align total number of sectors to be multiple of
|
|
sectors per track
|
|
|
|
This requirement is needed by DOS systems and also by Linux mtools project.
|
|
Without proper alignment, mtools applications refuse to work on such
|
|
filesystem.
|
|
---
|
|
configure.ac | 2
|
|
src/mkfs.fat.c | 119 ++++++++++++++++++++++-------------------------
|
|
tests/Makefile.am | 3 -
|
|
tests/mkfs-fat32_4K.mkfs | 3 +
|
|
tests/mkfs-fat32_4K.xxd | 63 ++++++++++++++++++++++++
|
|
tests/referenceFAT32.xxd | 5 +
|
|
6 files changed, 132 insertions(+), 63 deletions(-)
|
|
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -16,7 +16,7 @@
|
|
|
|
AC_INIT([dosfstools], [4.1])
|
|
AC_SUBST([RELEASE_DATE], [2017-01-24])
|
|
-AM_INIT_AUTOMAKE([1.11 foreign subdir-objects parallel-tests])
|
|
+AM_INIT_AUTOMAKE([1.15.1 foreign subdir-objects parallel-tests])
|
|
|
|
AC_ARG_ENABLE([compat-symlinks],
|
|
[AS_HELP_STRING([--enable-compat-symlinks],
|
|
--- a/src/mkfs.fat.c
|
|
+++ b/src/mkfs.fat.c
|
|
@@ -7,6 +7,7 @@
|
|
Copyright (C) 1998-2005 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
|
|
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
|
|
Copyright (C) 2015-2016 Andreas Bombe <aeb@debian.org>
|
|
+ Copyright (C) 2018 Pali Rohár <pali.rohar@gmail.com>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
@@ -107,14 +108,26 @@ static inline int cdiv(int a, int b)
|
|
|
|
#define BOOT_SIGN 0xAA55 /* Boot sector magic number */
|
|
|
|
-#define MAX_CLUST_12 ((1 << 12) - 16)
|
|
-#define MAX_CLUST_16 ((1 << 16) - 16)
|
|
-#define MIN_CLUST_32 65529
|
|
+/* According to Microsoft FAT specification (fatgen103.doc) disk with
|
|
+ * 4085 clusters (or more) is FAT16, but Microsoft Windows FAT driver
|
|
+ * fastfat.sys detects disk with less then 4087 clusters as FAT12.
|
|
+ * Linux FAT drivers msdos.ko and vfat.ko detect disk with at least
|
|
+ * 4085 clusters as FAT16, therefore for compatibility reasons with
|
|
+ * both systems disallow formatting disks to 4085 or 4086 clusters. */
|
|
+#define MAX_CLUST_12 4084
|
|
+#define MIN_CLUST_16 4087
|
|
+
|
|
+/* According to Microsoft FAT specification (fatgen103.doc) disk with
|
|
+ * 65525 clusters (or more) is FAT32, but Microsoft Windows FAT driver
|
|
+ * fastfat.sys, Linux FAT drivers msdos.ko and vfat.ko detect disk as
|
|
+ * FAT32 when Sectors Per FAT (fat_length) is set to zero. And not by
|
|
+ * number of clusters. Still there is cluster upper limit for FAT16. */
|
|
+#define MAX_CLUST_16 65524
|
|
+#define MIN_CLUST_32 65525
|
|
+
|
|
/* M$ says the high 4 bits of a FAT32 FAT entry are reserved and don't belong
|
|
* to the cluster number. So the max. cluster# is based on 2^28 */
|
|
-#define MAX_CLUST_32 ((1 << 28) - 16)
|
|
-
|
|
-#define FAT12_THRESHOLD 4085
|
|
+#define MAX_CLUST_32 268435446
|
|
|
|
#define OLDGEMDOS_MAX_SECTORS 32765
|
|
#define GEMDOS_MAX_SECTORS 65531
|
|
@@ -588,13 +601,12 @@ static void establish_params(struct devi
|
|
* fs size <= 16G: 8k clusters
|
|
* fs size <= 32G: 16k clusters
|
|
* fs size > 32G: 32k clusters
|
|
- *
|
|
- * This only works correctly for 512 byte sectors!
|
|
*/
|
|
- uint32_t sz_mb = info->size / (1024 * 1024);
|
|
- cluster_size =
|
|
- sz_mb > 32 * 1024 ? 64 : sz_mb > 16 * 1024 ? 32 : sz_mb >
|
|
- 8 * 1024 ? 16 : sz_mb > 260 ? 8 : 1;
|
|
+ unsigned long long int sectors = info->size / sector_size;
|
|
+ cluster_size = sectors > 32*1024*1024*2 ? 64 :
|
|
+ sectors > 16*1024*1024*2 ? 32 :
|
|
+ sectors > 8*1024*1024*2 ? 16 :
|
|
+ sectors > 260*1024*2 ? 8 : 1;
|
|
}
|
|
|
|
if (info->geom_heads > 0) {
|
|
@@ -733,6 +745,9 @@ static void setup_tables(void)
|
|
(long long)(blocks * BLOCK_SIZE / sector_size) + orphaned_sectors;
|
|
}
|
|
|
|
+ /* Align number of sectors to be multiple of sectors per track, needed by DOS and mtools */
|
|
+ num_sectors = num_sectors / le16toh(bs.secs_track) * le16toh(bs.secs_track);
|
|
+
|
|
if (!atari_format) {
|
|
unsigned fatdata1216; /* Sectors for FATs + data area (FAT12/16) */
|
|
unsigned fatdata32; /* Sectors for FATs + data area (FAT32) */
|
|
@@ -781,13 +796,13 @@ static void setup_tables(void)
|
|
maxclust12 = (fatlength12 * 2 * sector_size) / 3;
|
|
if (maxclust12 > MAX_CLUST_12)
|
|
maxclust12 = MAX_CLUST_12;
|
|
- if (verbose >= 2)
|
|
- printf("FAT12: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
|
|
+ if (verbose >= 2 && (size_fat == 0 || size_fat == 12))
|
|
+ printf("Trying FAT12: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
|
|
clust12, fatlength12, maxclust12, MAX_CLUST_12);
|
|
- if (clust12 > maxclust12 - 2) {
|
|
+ if (clust12 > maxclust12) {
|
|
clust12 = 0;
|
|
- if (verbose >= 2)
|
|
- printf("FAT12: too much clusters\n");
|
|
+ if (verbose >= 2 && (size_fat == 0 || size_fat == 12))
|
|
+ printf("Trying FAT12: too much clusters\n");
|
|
}
|
|
|
|
clust16 = ((long long)fatdata1216 * sector_size + nr_fats * 4) /
|
|
@@ -801,20 +816,19 @@ static void setup_tables(void)
|
|
maxclust16 = (fatlength16 * sector_size) / 2;
|
|
if (maxclust16 > MAX_CLUST_16)
|
|
maxclust16 = MAX_CLUST_16;
|
|
- if (verbose >= 2)
|
|
- printf("FAT16: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
|
|
- clust16, fatlength16, maxclust16, MAX_CLUST_16);
|
|
- if (clust16 > maxclust16 - 2) {
|
|
- if (verbose >= 2)
|
|
- printf("FAT16: too much clusters\n");
|
|
+ if (verbose >= 2 && (size_fat == 0 || size_fat == 16))
|
|
+ printf("Trying FAT16: #clu=%u, fatlen=%u, maxclu=%u, limit=%u/%u\n",
|
|
+ clust16, fatlength16, maxclust16, MIN_CLUST_16, MAX_CLUST_16);
|
|
+ if (clust16 > maxclust16) {
|
|
+ if (verbose >= 2 && (size_fat == 0 || size_fat == 16))
|
|
+ printf("Trying FAT16: too much clusters\n");
|
|
clust16 = 0;
|
|
}
|
|
- /* The < 4078 avoids that the filesystem will be misdetected as having a
|
|
+ /* This avoids that the filesystem will be misdetected as having a
|
|
* 12 bit FAT. */
|
|
- if (clust16 < FAT12_THRESHOLD
|
|
- && !(size_fat_by_user && size_fat == 16)) {
|
|
- if (verbose >= 2)
|
|
- printf("FAT16: would be misdetected as FAT12\n");
|
|
+ if (clust16 && clust16 < MIN_CLUST_16) {
|
|
+ if (verbose >= 2 && (size_fat == 0 || size_fat == 16))
|
|
+ printf("Trying FAT16: not enough clusters, would be misdetected as FAT12\n");
|
|
clust16 = 0;
|
|
}
|
|
|
|
@@ -829,19 +843,20 @@ static void setup_tables(void)
|
|
maxclust32 = (fatlength32 * sector_size) / 4;
|
|
if (maxclust32 > MAX_CLUST_32)
|
|
maxclust32 = MAX_CLUST_32;
|
|
- if (clust32 && clust32 < MIN_CLUST_32
|
|
- && !(size_fat_by_user && size_fat == 32)) {
|
|
+ if (verbose >= 2 && (size_fat == 0 || size_fat == 32))
|
|
+ printf("Trying FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u/%u\n",
|
|
+ clust32, fatlength32, maxclust32, MIN_CLUST_32, MAX_CLUST_32);
|
|
+ if (clust32 > maxclust32) {
|
|
+ if (verbose >= 2 && (size_fat == 0 || size_fat == 32))
|
|
+ printf("Trying FAT32: too much clusters\n");
|
|
clust32 = 0;
|
|
- if (verbose >= 2)
|
|
- printf("FAT32: not enough clusters (%d)\n", MIN_CLUST_32);
|
|
}
|
|
- if (verbose >= 2)
|
|
- printf("FAT32: #clu=%u, fatlen=%u, maxclu=%u, limit=%u\n",
|
|
- clust32, fatlength32, maxclust32, MAX_CLUST_32);
|
|
- if (clust32 > maxclust32) {
|
|
+ /* When explicitely asked, allow to create FAT32 with less then MIN_CLUST_32 */
|
|
+ if (clust32 && clust32 < MIN_CLUST_32
|
|
+ && !(size_fat_by_user && size_fat == 32)) {
|
|
+ if (verbose >= 2 && (size_fat == 0 || size_fat == 32))
|
|
+ printf("Trying FAT32: not enough clusters\n");
|
|
clust32 = 0;
|
|
- if (verbose >= 2)
|
|
- printf("FAT32: too much clusters\n");
|
|
}
|
|
|
|
if ((clust12 && (size_fat == 0 || size_fat == 12)) ||
|
|
@@ -869,23 +884,6 @@ static void setup_tables(void)
|
|
break;
|
|
|
|
case 16:
|
|
- if (clust16 < FAT12_THRESHOLD) {
|
|
- if (size_fat_by_user) {
|
|
- fprintf(stderr, "WARNING: Not enough clusters for a "
|
|
- "16 bit FAT! The filesystem will be\n"
|
|
- "misinterpreted as having a 12 bit FAT without "
|
|
- "mount option \"fat=16\".\n");
|
|
- } else {
|
|
- fprintf(stderr, "This filesystem has an unfortunate size. "
|
|
- "A 12 bit FAT cannot provide\n"
|
|
- "enough clusters, but a 16 bit FAT takes up a little "
|
|
- "bit more space so that\n"
|
|
- "the total number of clusters becomes less than the "
|
|
- "threshold value for\n"
|
|
- "distinction between 12 and 16 bit FATs.\n");
|
|
- die("Make the filesystem a bit smaller manually.");
|
|
- }
|
|
- }
|
|
cluster_count = clust16;
|
|
fat_length = fatlength16;
|
|
bs.fat_length = htole16(fatlength16);
|
|
@@ -894,8 +892,7 @@ static void setup_tables(void)
|
|
|
|
case 32:
|
|
if (clust32 < MIN_CLUST_32)
|
|
- fprintf(stderr,
|
|
- "WARNING: Not enough clusters for a 32 bit FAT!\n");
|
|
+ fprintf(stderr, "WARNING: Number of clusters for 32 bit FAT is less then suggested minimum.\n");
|
|
cluster_count = clust32;
|
|
fat_length = fatlength32;
|
|
bs.fat_length = htole16(0);
|
|
@@ -1053,9 +1050,9 @@ static void setup_tables(void)
|
|
|
|
if (!cluster_count) {
|
|
if (sectors_per_cluster) /* If yes, die if we'd spec'd sectors per cluster */
|
|
- die("Too many clusters for filesystem - try more sectors per cluster");
|
|
+ die("Not enough or too many clusters for filesystem - try less or more sectors per cluster");
|
|
else
|
|
- die("Attempting to create a too large filesystem");
|
|
+ die("Attempting to create a too small or a too large filesystem");
|
|
}
|
|
fat_entries = cluster_count + 2;
|
|
|
|
@@ -1076,8 +1073,8 @@ static void setup_tables(void)
|
|
(le16toh(bs.secs_track) != 1) ? "s" : "");
|
|
printf("hidden sectors 0x%04x;\n", hidden_sectors);
|
|
printf("logical sector size is %d,\n", sector_size);
|
|
- printf("using 0x%02x media descriptor, with %d sectors;\n",
|
|
- (int)(bs.media), num_sectors);
|
|
+ printf("using 0x%02x media descriptor, with %u sectors;\n",
|
|
+ (int)(bs.media), (unsigned)num_sectors);
|
|
printf("drive number 0x%02x;\n", (int) (vi->drive_number));
|
|
printf("filesystem has %d %d-bit FAT%s and %d sector%s per cluster.\n",
|
|
(int)(bs.fats), size_fat, (bs.fats != 1) ? "s" : "",
|
|
--- a/tests/Makefile.am
|
|
+++ b/tests/Makefile.am
|
|
@@ -6,7 +6,6 @@ endif
|
|
|
|
TESTS = referenceFAT12.mkfs \
|
|
referenceFAT16.mkfs \
|
|
- referenceFAT32.mkfs \
|
|
check-bad_names.fsck \
|
|
check-chain_to_free_cluster.fsck \
|
|
check-chain_too_long.fsck \
|
|
@@ -28,6 +27,8 @@ dist_check_DATA = test-mkfs test-fsck
|
|
referenceFAT16.xxd \
|
|
referenceFAT32.mkfs \
|
|
referenceFAT32.xxd \
|
|
+ mkfs-fat32_4K.mkfs \
|
|
+ mkfs-fat32_4K.xxd \
|
|
check-bad_names.fsck \
|
|
check-chain_to_free_cluster.fsck \
|
|
check-chain_too_long.fsck \
|
|
--- /dev/null
|
|
+++ b/tests/mkfs-fat32_4K.mkfs
|
|
@@ -0,0 +1,3 @@
|
|
+ARGS="-n TEST4K -S 4096"
|
|
+SIZE=614400
|
|
+CMP_LIMIT=10M
|
|
--- /dev/null
|
|
+++ b/tests/mkfs-fat32_4K.xxd
|
|
@@ -0,0 +1,63 @@
|
|
+00000000: eb58 906d 6b66 732e 6661 7400 1001 2000 .X.mkfs.fat... .
|
|
+00000010: 0200 0000 00f8 0000 2000 0800 0000 0000 ........ .......
|
|
+00000020: 0058 0200 9600 0000 0000 0000 0200 0000 .X..............
|
|
+00000030: 0100 0600 0000 0000 0000 0000 0000 0000 ................
|
|
+00000040: 8000 29cd ab34 1254 4553 5434 4b20 2020 ..)..4.TEST4K
|
|
+00000050: 2020 4641 5433 3220 2020 0e1f be77 7cac FAT32 ...w|.
|
|
+00000060: 22c0 740b 56b4 0ebb 0700 cd10 5eeb f032 ".t.V.......^..2
|
|
+00000070: e4cd 16cd 19eb fe54 6869 7320 6973 206e .......This is n
|
|
+00000080: 6f74 2061 2062 6f6f 7461 626c 6520 6469 ot a bootable di
|
|
+00000090: 736b 2e20 2050 6c65 6173 6520 696e 7365 sk. Please inse
|
|
+000000a0: 7274 2061 2062 6f6f 7461 626c 6520 666c rt a bootable fl
|
|
+000000b0: 6f70 7079 2061 6e64 0d0a 7072 6573 7320 oppy and..press
|
|
+000000c0: 616e 7920 6b65 7920 746f 2074 7279 2061 any key to try a
|
|
+000000d0: 6761 696e 202e 2e2e 200d 0a00 0000 0000 gain ... .......
|
|
+000000e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
|
|
+00000200: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+00001000: 5252 6141 0000 0000 0000 0000 0000 0000 RRaA............
|
|
+00001010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+000011e0: 0000 0000 7272 4161 b356 0200 0200 0000 ....rrAa.V......
|
|
+000011f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
|
|
+00001200: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+00006000: eb58 906d 6b66 732e 6661 7400 1001 2000 .X.mkfs.fat... .
|
|
+00006010: 0200 0000 00f8 0000 2000 0800 0000 0000 ........ .......
|
|
+00006020: 0058 0200 9600 0000 0000 0000 0200 0000 .X..............
|
|
+00006030: 0100 0600 0000 0000 0000 0000 0000 0000 ................
|
|
+00006040: 8000 29cd ab34 1254 4553 5434 4b20 2020 ..)..4.TEST4K
|
|
+00006050: 2020 4641 5433 3220 2020 0e1f be77 7cac FAT32 ...w|.
|
|
+00006060: 22c0 740b 56b4 0ebb 0700 cd10 5eeb f032 ".t.V.......^..2
|
|
+00006070: e4cd 16cd 19eb fe54 6869 7320 6973 206e .......This is n
|
|
+00006080: 6f74 2061 2062 6f6f 7461 626c 6520 6469 ot a bootable di
|
|
+00006090: 736b 2e20 2050 6c65 6173 6520 696e 7365 sk. Please inse
|
|
+000060a0: 7274 2061 2062 6f6f 7461 626c 6520 666c rt a bootable fl
|
|
+000060b0: 6f70 7079 2061 6e64 0d0a 7072 6573 7320 oppy and..press
|
|
+000060c0: 616e 7920 6b65 7920 746f 2074 7279 2061 any key to try a
|
|
+000060d0: 6761 696e 202e 2e2e 200d 0a00 0000 0000 gain ... .......
|
|
+000060e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+000061f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
|
|
+00006200: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+00007000: 5252 6141 0000 0000 0000 0000 0000 0000 RRaA............
|
|
+00007010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+000071e0: 0000 0000 7272 4161 b356 0200 0200 0000 ....rrAa.V......
|
|
+000071f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
|
|
+00007200: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+00020000: f8ff ff0f ffff ff0f f8ff ff0f 0000 0000 ................
|
|
+00020010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+000b6000: f8ff ff0f ffff ff0f f8ff ff0f 0000 0000 ................
|
|
+000b6010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+0014c000: 5445 5354 344b 2020 2020 2008 0000 5a4b TEST4K ...ZK
|
|
+0014c010: 6e46 6e46 0000 5a4b 6e46 0000 0000 0000 nFnF..ZKnF......
|
|
+0014c020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+257ffff0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
--- a/tests/referenceFAT32.xxd
|
|
+++ b/tests/referenceFAT32.xxd
|
|
@@ -52,3 +52,8 @@
|
|
001f8020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
*
|
|
3e7ffff0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+001f8000: 5445 5354 4641 5433 3220 2008 0000 5a4b TESTFAT32 ...ZK
|
|
+001f8010: 6e46 6e46 0000 5a4b 6e46 0000 0000 0000 nFnF..ZKnF......
|
|
+001f8020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
|
+*
|
|
+3e7ffff0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|