summaryrefslogtreecommitdiff
path: root/src/mkfs.fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mkfs.fat.c')
-rw-r--r--src/mkfs.fat.c235
1 files changed, 119 insertions, 116 deletions
diff --git a/src/mkfs.fat.c b/src/mkfs.fat.c
index 604b7d0..b38d116 100644
--- a/src/mkfs.fat.c
+++ b/src/mkfs.fat.c
@@ -60,15 +60,15 @@
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>
#include <stdint.h>
#include <endian.h>
+#include <getopt.h>
-#include <asm/types.h>
+#include "msdos_fs.h"
/* In earlier versions, an own llseek() was used, but glibc lseek() is
* sufficient (or even better :) for 64 bit offsets in the meantime */
@@ -102,21 +102,6 @@ static inline int cdiv(int a, int b)
return (a + b - 1) / b;
}
-/* MS-DOS filesystem structures -- I included them here instead of
- including linux/msdos_fs.h since that doesn't include some fields we
- need */
-
-#define ATTR_RO 1 /* read-only */
-#define ATTR_HIDDEN 2 /* hidden */
-#define ATTR_SYS 4 /* system */
-#define ATTR_VOLUME 8 /* volume label */
-#define ATTR_DIR 16 /* directory */
-#define ATTR_ARCH 32 /* archived */
-
-#define ATTR_NONE 0 /* no attribute bits */
-#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN)
- /* attribute bits that are copied "as is" */
-
/* FAT values */
#define FAT_EOF (atari_format ? 0x0fffffff : 0x0ffffff8)
#define FAT_BAD 0x0ffffff7
@@ -148,80 +133,67 @@ static inline int cdiv(int a, int b)
* alignments */
struct msdos_volume_info {
- __u8 drive_number; /* BIOS drive number */
- __u8 RESERVED; /* Unused */
- __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */
- __u8 volume_id[4]; /* Volume ID number */
- __u8 volume_label[11]; /* Volume label */
- __u8 fs_type[8]; /* Typically FAT12 or FAT16 */
+ uint8_t drive_number; /* BIOS drive number */
+ uint8_t RESERVED; /* Unused */
+ uint8_t ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */
+ uint8_t volume_id[4]; /* Volume ID number */
+ uint8_t volume_label[11]; /* Volume label */
+ uint8_t fs_type[8]; /* Typically FAT12 or FAT16 */
} __attribute__ ((packed));
struct msdos_boot_sector {
- __u8 boot_jump[3]; /* Boot strap short or near jump */
- __u8 system_id[8]; /* Name - can be used to special case
+ uint8_t boot_jump[3]; /* Boot strap short or near jump */
+ uint8_t system_id[8]; /* Name - can be used to special case
partition manager volumes */
- __u8 sector_size[2]; /* bytes per logical sector */
- __u8 cluster_size; /* sectors/cluster */
- __u16 reserved; /* reserved sectors */
- __u8 fats; /* number of FATs */
- __u8 dir_entries[2]; /* root directory entries */
- __u8 sectors[2]; /* number of sectors */
- __u8 media; /* media code (unused) */
- __u16 fat_length; /* sectors/FAT */
- __u16 secs_track; /* sectors per track */
- __u16 heads; /* number of heads */
- __u32 hidden; /* hidden sectors (unused) */
- __u32 total_sect; /* number of sectors (if sectors == 0) */
+ uint8_t sector_size[2]; /* bytes per logical sector */
+ uint8_t cluster_size; /* sectors/cluster */
+ uint16_t reserved; /* reserved sectors */
+ uint8_t fats; /* number of FATs */
+ uint8_t dir_entries[2]; /* root directory entries */
+ uint8_t sectors[2]; /* number of sectors */
+ uint8_t media; /* media code (unused) */
+ uint16_t fat_length; /* sectors/FAT */
+ uint16_t secs_track; /* sectors per track */
+ uint16_t heads; /* number of heads */
+ uint32_t hidden; /* hidden sectors (unused) */
+ uint32_t total_sect; /* number of sectors (if sectors == 0) */
union {
struct {
struct msdos_volume_info vi;
- __u8 boot_code[BOOTCODE_SIZE];
+ uint8_t boot_code[BOOTCODE_SIZE];
} __attribute__ ((packed)) _oldfat;
struct {
- __u32 fat32_length; /* sectors/FAT */
- __u16 flags; /* bit 8: fat mirroring, low 4: active fat */
- __u8 version[2]; /* major, minor filesystem version */
- __u32 root_cluster; /* first cluster in root directory */
- __u16 info_sector; /* filesystem info sector */
- __u16 backup_boot; /* backup boot sector */
- __u16 reserved2[6]; /* Unused */
+ uint32_t fat32_length; /* sectors/FAT */
+ uint16_t flags; /* bit 8: fat mirroring, low 4: active fat */
+ uint8_t version[2]; /* major, minor filesystem version */
+ uint32_t root_cluster; /* first cluster in root directory */
+ uint16_t info_sector; /* filesystem info sector */
+ uint16_t backup_boot; /* backup boot sector */
+ uint16_t reserved2[6]; /* Unused */
struct msdos_volume_info vi;
- __u8 boot_code[BOOTCODE_FAT32_SIZE];
+ uint8_t boot_code[BOOTCODE_FAT32_SIZE];
} __attribute__ ((packed)) _fat32;
} __attribute__ ((packed)) fstype;
- __u16 boot_sign;
+ uint16_t boot_sign;
} __attribute__ ((packed));
#define fat32 fstype._fat32
#define oldfat fstype._oldfat
struct fat32_fsinfo {
- __u32 reserved1; /* Nothing as far as I can tell */
- __u32 signature; /* 0x61417272L */
- __u32 free_clusters; /* Free cluster count. -1 if unknown */
- __u32 next_cluster; /* Most recently allocated cluster.
+ uint32_t reserved1; /* Nothing as far as I can tell */
+ uint32_t signature; /* 0x61417272L */
+ uint32_t free_clusters; /* Free cluster count. -1 if unknown */
+ uint32_t next_cluster; /* Most recently allocated cluster.
* Unused under Linux. */
- __u32 reserved2[4];
+ uint32_t reserved2[4];
};
-struct msdos_dir_entry {
- char name[8], ext[3]; /* name and extension */
- __u8 attr; /* attribute bits */
- __u8 lcase; /* Case for base and extension */
- __u8 ctime_ms; /* Creation time, milliseconds */
- __u16 ctime; /* Creation time */
- __u16 cdate; /* Creation date */
- __u16 adate; /* Last access date */
- __u16 starthi; /* high 16 bits of first cl. (FAT32) */
- __u16 time, date, start; /* time, date and first cluster */
- __u32 size; /* file size (in bytes) */
-} __attribute__ ((packed));
-
/* The "boot code" we put into the filesystem... it writes a message and
tells the user to try again */
-char dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 };
+unsigned char dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 };
-char dummy_boot_jump_m68k[2] = { 0x60, 0x1c };
+unsigned char dummy_boot_jump_m68k[2] = { 0x60, 0x1c };
#define MSG_OFFSET_OFFSET 3
char dummy_boot_code[BOOTCODE_SIZE] = "\x0e" /* push cs */
@@ -250,14 +222,13 @@ char dummy_boot_code[BOOTCODE_SIZE] = "\x0e" /* push cs */
/* Global variables - the root of all evil :-) - see these and weep! */
-static char *program_name = "mkfs.fat"; /* Name of the program */
+static const char *program_name = "mkfs.fat"; /* Name of the program */
static char *device_name = NULL; /* Name of the device on which to create the filesystem */
static int atari_format = 0; /* Use Atari variation of MS-DOS FS format */
static int check = FALSE; /* Default to no readablity checking */
static int verbose = 0; /* Default to verbose mode off */
static long volume_id; /* Volume ID number */
static time_t create_time; /* Creation time */
-static struct timeval create_timeval; /* Creation time */
static char volume_name[] = NO_NAME; /* Volume name */
static uint64_t blocks; /* Number of blocks in filesystem */
static int sector_size = 512; /* Size of a logical sector */
@@ -290,6 +261,9 @@ static int fat_media_byte = 0; /* media byte in header and starting FAT */
static int malloc_entire_fat = FALSE; /* Whether we should malloc() the entire FAT or not */
static int align_structures = TRUE; /* Whether to enforce alignment */
static int orphaned_sectors = 0; /* Sectors that exist in the last block of filesystem */
+static int invariant = 0; /* Whether to set normally randomized or
+ current time based values to
+ constants */
/* Function prototype definitions */
@@ -700,17 +674,18 @@ def_hd_params:
}
if (size_fat == 32) {
/* For FAT32, try to do the same as M$'s format command
- * (http://technet.microsoft.com/en-us/library/cc938438.aspx):
- * fs size < 8G: 4k clusters
- * fs size < 16G: 8k clusters
- * fs size < 32G: 16k clusters
- * fs size >= 32G: 32k clusters
+ * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20):
+ * fs size <= 260M: 0.5k clusters
+ * fs size <= 8G: 4k clusters
+ * fs size <= 16G: 8k clusters
+ * fs size <= 32G: 16k clusters
+ * fs size > 32G: 32k clusters
*/
uint32_t sz_mb =
(blocks + (1 << (20 - BLOCK_SIZE_BITS)) - 1) >> (20 -
BLOCK_SIZE_BITS);
bs.cluster_size =
- sz_mb >= 32 * 1024 ? 64 : sz_mb >= 16 * 1024 ? 32 : sz_mb >=
+ sz_mb > 32 * 1024 ? 64 : sz_mb > 16 * 1024 ? 32 : sz_mb >
8 * 1024 ? 16 : sz_mb > 260 ? 8 : 1;
} else {
/* FAT12 and FAT16: start at 4 sectors per cluster */
@@ -826,7 +801,7 @@ static void setup_tables(void)
bs.hidden = htole32(hidden_sectors);
else {
/* In Atari format, hidden is a 16 bit field */
- __u16 hidden = htole16(hidden_sectors);
+ uint16_t hidden = htole16(hidden_sectors);
if (hidden_sectors & ~0xffff)
die("#hidden doesn't fit in 16bit field of Atari format\n");
memcpy(&bs.hidden, &hidden, 2);
@@ -1239,7 +1214,10 @@ static void setup_tables(void)
memcpy(de->name, volume_name, 8);
memcpy(de->ext, volume_name + 8, 3);
de->attr = ATTR_VOLUME;
- ctime = localtime(&create_time);
+ if (!invariant)
+ ctime = localtime(&create_time);
+ else
+ ctime = gmtime(&create_time);
de->time = htole16((unsigned short)((ctime->tm_sec >> 1) +
(ctime->tm_min << 5) +
(ctime->tm_hour << 11)));
@@ -1247,7 +1225,7 @@ static void setup_tables(void)
htole16((unsigned short)(ctime->tm_mday +
((ctime->tm_mon + 1) << 5) +
((ctime->tm_year - 80) << 9)));
- de->ctime_ms = 0;
+ de->ctime_cs = 0;
de->ctime = de->time;
de->cdate = de->date;
de->adate = de->date;
@@ -1279,7 +1257,7 @@ static void setup_tables(void)
info->next_cluster = htole32(2);
/* Info sector also must have boot sign */
- *(__u16 *) (info_sector + 0x1fe) = htole16(BOOT_SIGN);
+ *(uint16_t *) (info_sector + 0x1fe) = htole16(BOOT_SIGN);
}
if (!(blank_sector = malloc(sector_size)))
@@ -1357,17 +1335,20 @@ static void write_tables(void)
free(fat); /* Free up the fat table space reserved during setup_tables */
}
-/* Report the command usage and return a failure error code */
+/* Report the command usage and exit with the given error code */
-static void usage(void)
+static void usage(int exitval)
{
- fatal_error("\
+ fprintf(stderr, "\
Usage: mkfs.fat [-a][-A][-c][-C][-v][-I][-l bad-block-file][-b backup-boot-sector]\n\
[-m boot-msg-file][-n volume-name][-i volume-id]\n\
[-s sectors-per-cluster][-S logical-sector-size][-f number-of-FATs]\n\
[-h hidden-sectors][-F fat-size][-r root-dir-entries][-R reserved-sectors]\n\
[-M FAT-media-byte][-D drive_number]\n\
+ [--invariant]\n\
+ [--help]\n\
/dev/name [blocks]\n");
+ exit(exitval);
}
/*
@@ -1412,6 +1393,15 @@ int main(int argc, char **argv)
int create = 0;
uint64_t cblocks = 0;
int min_sector_size;
+ int bad_block_count = 0;
+ struct timeval create_timeval;
+
+ enum {OPT_HELP=1000, OPT_INVARIANT,};
+ const struct option long_options[] = {
+ {"help", no_argument, NULL, OPT_HELP},
+ {"invariant", no_argument, NULL, OPT_INVARIANT},
+ {0,}
+ };
if (argc && *argv) { /* What's the program name? */
char *p;
@@ -1427,7 +1417,8 @@ int main(int argc, char **argv)
printf("mkfs.fat " VERSION " (" VERSION_DATE ")\n");
- while ((c = getopt(argc, argv, "aAb:cCf:D:F:Ii:l:m:M:n:r:R:s:S:h:v")) != EOF)
+ while ((c = getopt_long(argc, argv, "aAb:cCf:D:F:Ii:l:m:M:n:r:R:s:S:h:v",
+ long_options, NULL)) != -1)
/* Scan the command line for options */
switch (c) {
case 'A': /* toggle Atari format */
@@ -1442,7 +1433,7 @@ int main(int argc, char **argv)
backup_boot = (int)strtol(optarg, &tmp, 0);
if (*tmp || backup_boot < 2 || backup_boot > 0xffff) {
printf("Bad location for backup boot sector : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1459,7 +1450,7 @@ int main(int argc, char **argv)
drive_number_option = (int) strtol (optarg, &tmp, 0);
if (*tmp || (drive_number_option != 0 && drive_number_option != 0x80)) {
printf ("Drive number must be 0 or 0x80: %s\n", optarg);
- usage ();
+ usage(1);
}
drive_number_by_user=1;
break;
@@ -1468,7 +1459,7 @@ int main(int argc, char **argv)
nr_fats = (int)strtol(optarg, &tmp, 0);
if (*tmp || nr_fats < 1 || nr_fats > 4) {
printf("Bad number of FATs : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1476,7 +1467,7 @@ int main(int argc, char **argv)
size_fat = (int)strtol(optarg, &tmp, 0);
if (*tmp || (size_fat != 12 && size_fat != 16 && size_fat != 32)) {
printf("Bad FAT type : %s\n", optarg);
- usage();
+ usage(1);
}
size_fat_by_user = 1;
break;
@@ -1485,7 +1476,7 @@ int main(int argc, char **argv)
hidden_sectors = (int)strtol(optarg, &tmp, 0);
if (*tmp || hidden_sectors < 0) {
printf("Bad number of hidden sectors : %s\n", optarg);
- usage();
+ usage(1);
}
hidden_sectors_by_user = 1;
break;
@@ -1498,7 +1489,7 @@ int main(int argc, char **argv)
volume_id = strtoul(optarg, &tmp, 16);
if (*tmp) {
printf("Volume ID must be a hexadecimal number\n");
- usage();
+ usage(1);
}
break;
@@ -1568,10 +1559,14 @@ int main(int argc, char **argv)
break;
case 'M': /* M : FAT Media byte */
- fat_media_byte = (int) strtol (optarg, &tmp, 0);
- if (*tmp || fat_media_byte < 248 || fat_media_byte > 255) {
- printf ("FAT Media byte must be between 0xF8 and 0xFF : %s\n", optarg);
- usage ();
+ fat_media_byte = (int)strtol(optarg, &tmp, 0);
+ if (*tmp) {
+ printf("Bad number for media descriptor : %s\n", optarg);
+ usage(1);
+ }
+ if (fat_media_byte != 0xf0 && (fat_media_byte < 0xf8 || fat_media_byte > 0xff)) {
+ printf("FAT Media byte must either be between 0xF8 and 0xFF or be 0xF0 : %s\n", optarg);
+ usage(1);
}
break;
@@ -1591,7 +1586,7 @@ int main(int argc, char **argv)
root_dir_entries = (int)strtol(optarg, &tmp, 0);
if (*tmp || root_dir_entries < 16 || root_dir_entries > 32768) {
printf("Bad number of root directory entries : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1599,7 +1594,7 @@ int main(int argc, char **argv)
reserved_sectors = (int)strtol(optarg, &tmp, 0);
if (*tmp || reserved_sectors < 1 || reserved_sectors > 0xffff) {
printf("Bad number of reserved sectors : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1612,7 +1607,7 @@ int main(int argc, char **argv)
&& sectors_per_cluster != 64
&& sectors_per_cluster != 128)) {
printf("Bad number of sectors per cluster : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1623,7 +1618,7 @@ int main(int argc, char **argv)
sector_size != 8192 && sector_size != 16384 &&
sector_size != 32768)) {
printf("Bad logical sector size : %s\n", optarg);
- usage();
+ usage(1);
}
sector_size_set = 1;
break;
@@ -1632,16 +1627,26 @@ int main(int argc, char **argv)
++verbose;
break;
+ case OPT_HELP:
+ usage(0);
+ break;
+
+ case OPT_INVARIANT:
+ invariant = 1;
+ volume_id = 0x1234abcd;
+ create_time = 1426325213;
+ break;
+
default:
printf("Unknown option: %c\n", c);
- usage();
+ usage(1);
}
if (optind < argc) {
device_name = argv[optind]; /* Determine the number of blocks in the FS */
if (!device_name) {
printf("No device specified.\n");
- usage();
+ usage(1);
}
if (!create)
@@ -1653,18 +1658,19 @@ int main(int argc, char **argv)
fprintf(stderr, "Warning: block count mismatch: ");
fprintf(stderr, "found %llu but assuming %llu.\n", (unsigned long long)cblocks, (unsigned long long)blocks);
}
+ if (*tmp)
+ bad_block_count = 1;
} else if (optind == argc - 1) { /* Or use value found */
if (create)
die("Need intended size with -C.");
blocks = cblocks;
- tmp = "";
} else {
fprintf(stderr, "No device specified!\n");
- usage();
+ usage(1);
}
- if (*tmp) {
+ if (bad_block_count) {
printf("Bad block count : %s\n", argv[optind + 1]);
- usage();
+ usage(1);
}
if (check && listfile) /* Auto and specified bad block handling are mutually */
@@ -1679,20 +1685,17 @@ int main(int argc, char **argv)
exit(1); /* The error exit code is 1! */
}
} else {
- loff_t offset = blocks * BLOCK_SIZE - 1;
- char null = 0;
/* create the file */
- dev = open(device_name, O_EXCL | O_RDWR | O_CREAT | O_TRUNC, 0666);
- if (dev < 0)
- die("unable to create %s");
- /* seek to the intended end-1, and write one byte. this creates a
- * sparse-as-possible file of appropriate size. */
- if (llseek(dev, offset, SEEK_SET) != offset)
- die("seek failed");
- if (write(dev, &null, 1) < 0)
- die("write failed");
- if (llseek(dev, 0, SEEK_SET) != 0)
- die("seek failed");
+ dev = open(device_name, O_EXCL | O_RDWR | O_CREAT, 0666);
+ if (dev < 0) {
+ if (errno == EEXIST)
+ die("file %s already exists");
+ else
+ die("unable to create %s");
+ }
+ /* expand to desired size */
+ if (ftruncate(dev, blocks * BLOCK_SIZE))
+ die("unable to resize %s");
}
if (fstat(dev, &statbuf) < 0)