Update dosfstools

* Version 3.0.28
* Update filenames in source
* Remove unnecessary symlink to fsck
* Commit "Recode short filenames from DOS codepage (default 437)." has
  been reverted since we do not have access to iconv
* Commits cherry-picked on top of 3.0.28:
    - mkfs.fat: fix incorrect int type
    - Prevent out of bound array read in date_dos2unix()

Change-Id: I50310235c62ec2e6bc90afcd10f2814d3afb5113
diff --git a/dosfstools/src/boot.c b/dosfstools/src/boot.c
index bbaee04..0c0918f 100644
--- a/dosfstools/src/boot.c
+++ b/dosfstools/src/boot.c
@@ -2,6 +2,7 @@
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -16,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -24,16 +25,17 @@
  * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
 
 #include <stdio.h>
+#include <stdint.h>
 #include <string.h>
-#include <sys/types.h>
 #include <stdlib.h>
 #include <time.h>
 
 #include "common.h"
-#include "dosfsck.h"
+#include "fsck.fat.h"
 #include "fat.h"
 #include "io.h"
 #include "boot.h"
+#include "check.h"
 
 #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
     /* don't divide by zero */
@@ -43,8 +45,8 @@
 #define FAT16_THRESHOLD 65525
 
 static struct {
-    __u8 media;
-    char *descr;
+    uint8_t media;
+    const char *descr;
 } mediabytes[] = {
     {
     0xf0, "5.25\" or 3.5\" HD floppy"}, {
@@ -58,20 +60,11 @@
     0xfe, "5.25\" 160k floppy 1s/40tr/8sec"}, {
 0xff, "5.25\" 320k floppy 2s/40tr/8sec"},};
 
-#if defined __alpha || defined __arm || defined __arm__ || defined __ia64__ || defined __x86_64__ \
- || defined __ppc64__ || defined __bfin__ || defined __MICROBLAZE__
-/* Unaligned fields must first be copied byte-wise */
+/* Unaligned fields must first be accessed byte-wise */
 #define GET_UNALIGNED_W(f)			\
-    ({						\
-	unsigned short __v;			\
-	memcpy( &__v, &f, sizeof(__v) );	\
-	CF_LE_W( *(unsigned short *)&__v );	\
-    })
-#else
-#define GET_UNALIGNED_W(f) CF_LE_W( *(unsigned short *)&f )
-#endif
+    ( (uint16_t)f[0] | ((uint16_t)f[1]<<8) )
 
-static char *get_media_descr(unsigned char media)
+static const char *get_media_descr(unsigned char media)
 {
     int i;
 
@@ -96,14 +89,14 @@
 	/* On Atari, a 24 bit serial number is stored at offset 8 of the boot
 	 * sector */
 	printf("Serial number 0x%x\n",
-	       b->system_id[5] | (b->
-				  system_id[6] << 8) | (b->system_id[7] << 16));
+	       b->system_id[5] | (b->system_id[6] << 8) | (b->
+							   system_id[7] << 16));
     }
     printf("Media byte 0x%02x (%s)\n", b->media, get_media_descr(b->media));
     printf("%10d bytes per logical sector\n", GET_UNALIGNED_W(b->sector_size));
     printf("%10d bytes per cluster\n", fs->cluster_size);
-    printf("%10d reserved sector%s\n", CF_LE_W(b->reserved),
-	   CF_LE_W(b->reserved) == 1 ? "" : "s");
+    printf("%10d reserved sector%s\n", le16toh(b->reserved),
+	   le16toh(b->reserved) == 1 ? "" : "s");
     printf("First FAT starts at byte %llu (sector %llu)\n",
 	   (unsigned long long)fs->fat_start,
 	   (unsigned long long)fs->fat_start / lss);
@@ -117,21 +110,21 @@
 	printf("%10d root directory entries\n", fs->root_entries);
     } else {
 	printf("Root directory start at cluster %lu (arbitrary size)\n",
-	       fs->root_cluster);
+	       (unsigned long)fs->root_cluster);
     }
     printf("Data area starts at byte %llu (sector %llu)\n",
 	   (unsigned long long)fs->data_start,
 	   (unsigned long long)fs->data_start / lss);
-    printf("%10lu data clusters (%llu bytes)\n", fs->clusters,
+    printf("%10lu data clusters (%llu bytes)\n", (unsigned long)fs->clusters,
 	   (unsigned long long)fs->clusters * fs->cluster_size);
-    printf("%u sectors/track, %u heads\n", CF_LE_W(b->secs_track),
-	   CF_LE_W(b->heads));
+    printf("%u sectors/track, %u heads\n", le16toh(b->secs_track),
+	   le16toh(b->heads));
     printf("%10u hidden sectors\n", atari_format ?
 	   /* On Atari, the hidden field is only 16 bit wide and unused */
 	   (((unsigned char *)&b->hidden)[0] |
-	    ((unsigned char *)&b->hidden)[1] << 8) : CF_LE_L(b->hidden));
+	    ((unsigned char *)&b->hidden)[1] << 8) : le32toh(b->hidden));
     sectors = GET_UNALIGNED_W(b->sectors);
-    printf("%10u sectors total\n", sectors ? sectors : CF_LE_L(b->total_sect));
+    printf("%10u sectors total\n", sectors ? sectors : le32toh(b->total_sect));
 }
 
 static void check_backup_boot(DOS_FS * fs, struct boot_sector *b, int lss)
@@ -140,7 +133,7 @@
 
     if (!fs->backupboot_start) {
 	printf("There is no backup boot sector.\n");
-	if (CF_LE_W(b->reserved) < 3) {
+	if (le16toh(b->reserved) < 3) {
 	    printf("And there is no space for creating one!\n");
 	    return;
 	}
@@ -152,15 +145,15 @@
 	    int bbs;
 	    /* The usual place for the backup boot sector is sector 6. Choose
 	     * that or the last reserved sector. */
-	    if (CF_LE_W(b->reserved) >= 7 && CF_LE_W(b->info_sector) != 6)
+	    if (le16toh(b->reserved) >= 7 && le16toh(b->info_sector) != 6)
 		bbs = 6;
 	    else {
-		bbs = CF_LE_W(b->reserved) - 1;
-		if (bbs == CF_LE_W(b->info_sector))
+		bbs = le16toh(b->reserved) - 1;
+		if (bbs == le16toh(b->info_sector))
 		    --bbs;	/* this is never 0, as we checked reserved >= 3! */
 	    }
 	    fs->backupboot_start = bbs * lss;
-	    b->backup_boot = CT_LE_W(bbs);
+	    b->backup_boot = htole16(bbs);
 	    fs_write(fs->backupboot_start, sizeof(*b), b);
 	    fs_write((loff_t) offsetof(struct boot_sector, backup_boot),
 		     sizeof(b->backup_boot), &b->backup_boot);
@@ -173,18 +166,18 @@
     fs_read(fs->backupboot_start, sizeof(b2), &b2);
     if (memcmp(b, &b2, sizeof(b2)) != 0) {
 	/* there are any differences */
-	__u8 *p, *q;
+	uint8_t *p, *q;
 	int i, pos, first = 1;
 	char buf[20];
 
 	printf("There are differences between boot sector and its backup.\n");
-	printf("Differences: (offset:original/backup)\n  ");
+	printf("This is mostly harmless. Differences: (offset:original/backup)\n  ");
 	pos = 2;
-	for (p = (__u8 *) b, q = (__u8 *) & b2, i = 0; i < sizeof(b2);
+	for (p = (uint8_t *) b, q = (uint8_t *) & b2, i = 0; i < sizeof(b2);
 	     ++p, ++q, ++i) {
 	    if (*p != *q) {
 		sprintf(buf, "%s%u:%02x/%02x", first ? "" : ", ",
-			(unsigned)(p - (__u8 *) b), *p, *q);
+			(unsigned)(p - (uint8_t *) b), *p, *q);
 		if (pos + strlen(buf) > 78)
 		    printf("\n  "), pos = 2;
 		printf("%s", buf);
@@ -214,11 +207,11 @@
 
 static void init_fsinfo(struct info_sector *i)
 {
-    i->magic = CT_LE_L(0x41615252);
-    i->signature = CT_LE_L(0x61417272);
-    i->free_clusters = CT_LE_L(-1);
-    i->next_cluster = CT_LE_L(2);
-    i->boot_sign = CT_LE_W(0xaa55);
+    i->magic = htole32(0x41615252);
+    i->signature = htole32(0x61417272);
+    i->free_clusters = htole32(-1);
+    i->next_cluster = htole32(2);
+    i->boot_sign = htole16(0xaa55);
 }
 
 static void read_fsinfo(DOS_FS * fs, struct boot_sector *b, int lss)
@@ -234,14 +227,14 @@
 	if (interactive && get_key("12", "?") == '1') {
 	    /* search for a free reserved sector (not boot sector and not
 	     * backup boot sector) */
-	    __u32 s;
-	    for (s = 1; s < CF_LE_W(b->reserved); ++s)
-		if (s != CF_LE_W(b->backup_boot))
+	    uint32_t s;
+	    for (s = 1; s < le16toh(b->reserved); ++s)
+		if (s != le16toh(b->backup_boot))
 		    break;
-	    if (s > 0 && s < CF_LE_W(b->reserved)) {
+	    if (s > 0 && s < le16toh(b->reserved)) {
 		init_fsinfo(&i);
 		fs_write((loff_t) s * lss, sizeof(i), &i);
-		b->info_sector = CT_LE_W(s);
+		b->info_sector = htole16(s);
 		fs_write((loff_t) offsetof(struct boot_sector, info_sector),
 			 sizeof(b->info_sector), &b->info_sector);
 		if (fs->backupboot_start)
@@ -257,24 +250,24 @@
 	    return;
     }
 
-    fs->fsinfo_start = CF_LE_W(b->info_sector) * lss;
+    fs->fsinfo_start = le16toh(b->info_sector) * lss;
     fs_read(fs->fsinfo_start, sizeof(i), &i);
 
-    if (i.magic != CT_LE_L(0x41615252) ||
-	i.signature != CT_LE_L(0x61417272) || i.boot_sign != CT_LE_W(0xaa55)) {
+    if (i.magic != htole32(0x41615252) ||
+	i.signature != htole32(0x61417272) || i.boot_sign != htole16(0xaa55)) {
 	printf("FSINFO sector has bad magic number(s):\n");
-	if (i.magic != CT_LE_L(0x41615252))
+	if (i.magic != htole32(0x41615252))
 	    printf("  Offset %llu: 0x%08x != expected 0x%08x\n",
 		   (unsigned long long)offsetof(struct info_sector, magic),
-		   CF_LE_L(i.magic), 0x41615252);
-	if (i.signature != CT_LE_L(0x61417272))
+		   le32toh(i.magic), 0x41615252);
+	if (i.signature != htole32(0x61417272))
 	    printf("  Offset %llu: 0x%08x != expected 0x%08x\n",
 		   (unsigned long long)offsetof(struct info_sector, signature),
-		   CF_LE_L(i.signature), 0x61417272);
-	if (i.boot_sign != CT_LE_W(0xaa55))
+		   le32toh(i.signature), 0x61417272);
+	if (i.boot_sign != htole16(0xaa55))
 	    printf("  Offset %llu: 0x%04x != expected 0x%04x\n",
 		   (unsigned long long)offsetof(struct info_sector, boot_sign),
-		   CF_LE_W(i.boot_sign), 0xaa55);
+		   le16toh(i.boot_sign), 0xaa55);
 	if (interactive)
 	    printf("1) Correct\n2) Don't correct (FSINFO invalid then)\n");
 	else
@@ -287,7 +280,45 @@
     }
 
     if (fs->fsinfo_start)
-	fs->free_clusters = CF_LE_L(i.free_clusters);
+	fs->free_clusters = le32toh(i.free_clusters);
+}
+
+static char print_fat_dirty_state(void)
+{
+    printf("Dirty bit is set. Fs was not properly unmounted and"
+	   " some data may be corrupt.\n");
+
+    if (interactive) {
+	printf("1) Remove dirty bit\n" "2) No action\n");
+	return get_key("12", "?");
+    } else
+	printf(" Automatically removing dirty bit.\n");
+    return '1';
+}
+
+static void check_fat_state_bit(DOS_FS * fs, void *b)
+{
+    if (fs->fat_bits == 32) {
+	struct boot_sector *b32 = b;
+
+	if (b32->reserved3 & FAT_STATE_DIRTY) {
+	    printf("0x41: ");
+	    if (print_fat_dirty_state() == '1') {
+		b32->reserved3 &= ~FAT_STATE_DIRTY;
+		fs_write(0, sizeof(*b32), b32);
+	    }
+	}
+    } else {
+	struct boot_sector_16 *b16 = b;
+
+	if (b16->reserved2 & FAT_STATE_DIRTY) {
+	    printf("0x25: ");
+	    if (print_fat_dirty_state() == '1') {
+		b16->reserved2 &= ~FAT_STATE_DIRTY;
+		fs_write(0, sizeof(*b16), b16);
+	    }
+	}
+    }
 }
 
 void read_boot(DOS_FS * fs)
@@ -317,16 +348,16 @@
 	die("Currently, only 1 or 2 FATs are supported, not %d.\n", b.fats);
     fs->nfats = b.fats;
     sectors = GET_UNALIGNED_W(b.sectors);
-    total_sectors = sectors ? sectors : CF_LE_L(b.total_sect);
+    total_sectors = sectors ? sectors : le32toh(b.total_sect);
     if (verbose)
 	printf("Checking we can access the last sector of the filesystem\n");
     /* Can't access last odd sector anyway, so round down */
     fs_test((loff_t) ((total_sectors & ~1) - 1) * (loff_t) logical_sector_size,
 	    logical_sector_size);
-    fat_length = CF_LE_W(b.fat_length) ?
-	CF_LE_W(b.fat_length) : CF_LE_L(b.fat32_length);
-    fs->fat_start = (loff_t) CF_LE_W(b.reserved) * logical_sector_size;
-    fs->root_start = ((loff_t) CF_LE_W(b.reserved) + b.fats * fat_length) *
+    fat_length = le16toh(b.fat_length) ?
+	le16toh(b.fat_length) : le32toh(b.fat32_length);
+    fs->fat_start = (loff_t) le16toh(b.reserved) * logical_sector_size;
+    fs->root_start = ((loff_t) le16toh(b.reserved) + b.fats * fat_length) *
 	logical_sector_size;
     fs->root_entries = GET_UNALIGNED_W(b.dir_entries);
     fs->data_start = fs->root_start + ROUND_TO_MULTIPLE(fs->root_entries <<
@@ -339,7 +370,7 @@
     fs->free_clusters = -1;	/* unknown */
     if (!b.fat_length && b.fat32_length) {
 	fs->fat_bits = 32;
-	fs->root_cluster = CF_LE_L(b.root_cluster);
+	fs->root_cluster = le32toh(b.root_cluster);
 	if (!fs->root_cluster && fs->root_entries)
 	    /* M$ hasn't specified this, but it looks reasonable: If
 	     * root_cluster is 0 but there is a separate root dir
@@ -360,9 +391,10 @@
 		   "  but has only %lu clusters, less than the required "
 		   "minimum of %d.\n"
 		   "  This may lead to problems on some systems.\n",
-		   fs->clusters, FAT16_THRESHOLD);
+		   (unsigned long)fs->clusters, FAT16_THRESHOLD);
 
-	fs->backupboot_start = CF_LE_W(b.backup_boot) * logical_sector_size;
+	check_fat_state_bit(fs, &b);
+	fs->backupboot_start = le16toh(b.backup_boot) * logical_sector_size;
 	check_backup_boot(fs, &b, logical_sector_size);
 
 	read_fsinfo(fs, &b, logical_sector_size);
@@ -372,6 +404,7 @@
 	fs->fat_bits = (fs->clusters >= FAT12_THRESHOLD) ? 16 : 12;
 	if (fs->clusters >= FAT16_THRESHOLD)
 	    die("Too many clusters (%lu) for FAT16 filesystem.", fs->clusters);
+	check_fat_state_bit(fs, &b);
     } else {
 	/* On Atari, things are more difficult: GEMDOS always uses 12bit FATs
 	 * on floppies, and always 16 bit on harddisks. */
@@ -392,7 +425,7 @@
     fs->eff_fat_bits = (fs->fat_bits == 32) ? 28 : fs->fat_bits;
     fs->fat_size = fat_length * logical_sector_size;
 
-    fs->label = calloc(12, sizeof(__u8));
+    fs->label = calloc(12, sizeof(uint8_t));
     if (fs->fat_bits == 12 || fs->fat_bits == 16) {
 	struct boot_sector_16 *b16 = (struct boot_sector_16 *)&b;
 	if (b16->extended_sig == 0x29)
@@ -407,8 +440,8 @@
     }
 
     if (fs->clusters >
-	((unsigned long long)fs->fat_size * 8 / fs->fat_bits) - 2)
-	die("File system has %d clusters but only space for %d FAT entries.",
+	((uint64_t)fs->fat_size * 8 / fs->fat_bits) - 2)
+	die("Filesystem has %d clusters but only space for %d FAT entries.",
 	    fs->clusters,
 	    ((unsigned long long)fs->fat_size * 8 / fs->fat_bits) - 2);
     if (!fs->root_entries && !fs->root_cluster)
@@ -430,34 +463,37 @@
 
 static void write_boot_label(DOS_FS * fs, char *label)
 {
-    struct boot_sector b;
-    struct boot_sector_16 *b16 = (struct boot_sector_16 *)&b;
-
-    fs_read(0, sizeof(b), &b);
     if (fs->fat_bits == 12 || fs->fat_bits == 16) {
-	if (b16->extended_sig != 0x29) {
-	    b16->extended_sig = 0x29;
-	    b16->serial = 0;
-	    memmove(b16->fs_type, fs->fat_bits == 12 ? "FAT12   " : "FAT16   ",
+	struct boot_sector_16 b16;
+
+	fs_read(0, sizeof(b16), &b16);
+	if (b16.extended_sig != 0x29) {
+	    b16.extended_sig = 0x29;
+	    b16.serial = 0;
+	    memmove(b16.fs_type, fs->fat_bits == 12 ? "FAT12   " : "FAT16   ",
 		    8);
 	}
-	memmove(b16->label, label, 11);
+	memmove(b16.label, label, 11);
+	fs_write(0, sizeof(b16), &b16);
     } else if (fs->fat_bits == 32) {
+	struct boot_sector b;
+
+	fs_read(0, sizeof(b), &b);
 	if (b.extended_sig != 0x29) {
 	    b.extended_sig = 0x29;
 	    b.serial = 0;
 	    memmove(b.fs_type, "FAT32   ", 8);
 	}
 	memmove(b.label, label, 11);
+	fs_write(0, sizeof(b), &b);
+	if (fs->backupboot_start)
+	    fs_write(fs->backupboot_start, sizeof(b), &b);
     }
-    fs_write(0, sizeof(b), &b);
-    if (fs->fat_bits == 32 && fs->backupboot_start)
-	fs_write(fs->backupboot_start, sizeof(b), &b);
 }
 
-static loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de)
+loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de)
 {
-    unsigned long cluster;
+    uint32_t cluster;
     loff_t offset;
     int i;
 
@@ -468,7 +504,7 @@
 	    offset = cluster_start(fs, cluster);
 	    for (i = 0; i * sizeof(DIR_ENT) < fs->cluster_size; i++) {
 		fs_read(offset, sizeof(DIR_ENT), de);
-		if (de->attr & ATTR_VOLUME)
+		if (de->attr != VFAT_LN_ATTR && de->attr & ATTR_VOLUME)
 		    return offset;
 		offset += sizeof(DIR_ENT);
 	    }
@@ -477,7 +513,7 @@
 	for (i = 0; i < fs->root_entries; i++) {
 	    offset = fs->root_start + i * sizeof(DIR_ENT);
 	    fs_read(offset, sizeof(DIR_ENT), de);
-	    if (de->attr & ATTR_VOLUME)
+	    if (de->attr != VFAT_LN_ATTR && de->attr & ATTR_VOLUME)
 		return offset;
 	}
     }
@@ -490,19 +526,33 @@
     time_t now = time(NULL);
     struct tm *mtime = localtime(&now);
     loff_t offset;
+    int created;
     DIR_ENT de;
 
+    created = 0;
     offset = find_volume_de(fs, &de);
-    if (offset == 0)
-	return;
-
+    if (offset == 0) {
+	created = 1;
+	offset = alloc_rootdir_entry(fs, &de, label);
+    }
     memcpy(de.name, label, 11);
-    de.time = CT_LE_W((unsigned short)((mtime->tm_sec >> 1) +
+    de.time = htole16((unsigned short)((mtime->tm_sec >> 1) +
 				       (mtime->tm_min << 5) +
 				       (mtime->tm_hour << 11)));
-    de.date = CT_LE_W((unsigned short)(mtime->tm_mday +
+    de.date = htole16((unsigned short)(mtime->tm_mday +
 				       ((mtime->tm_mon + 1) << 5) +
 				       ((mtime->tm_year - 80) << 9)));
+    if (created) {
+	de.attr = ATTR_VOLUME;
+	de.ctime_ms = 0;
+	de.ctime = de.time;
+	de.cdate = de.date;
+	de.adate = de.date;
+	de.starthi = 0;
+	de.start = 0;
+	de.size = 0;
+    }
+
     fs_write(offset, sizeof(DIR_ENT), &de);
 }
 
diff --git a/dosfstools/src/boot.h b/dosfstools/src/boot.h
index c9edfa3..d52e624 100644
--- a/dosfstools/src/boot.h
+++ b/dosfstools/src/boot.h
@@ -1,6 +1,7 @@
 /* boot.h - Read and analyze ia PC/MS-DOS boot sector
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -15,7 +16,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -24,6 +25,7 @@
 
 void read_boot(DOS_FS * fs);
 void write_label(DOS_FS * fs, char *label);
+loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de);
 
 /* Reads the boot sector from the currently open device and initializes *FS */
 
diff --git a/dosfstools/src/check.c b/dosfstools/src/check.c
index 3f175b0..bbb97e4 100644
--- a/dosfstools/src/check.c
+++ b/dosfstools/src/check.c
@@ -1,7 +1,8 @@
-/* check.c - Check and repair a PC/MS-DOS file system
+/* check.c - Check and repair a PC/MS-DOS filesystem
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -16,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -30,7 +31,7 @@
 #include <time.h>
 
 #include "common.h"
-#include "dosfsck.h"
+#include "fsck.fat.h"
 #include "io.h"
 #include "fat.h"
 #include "file.h"
@@ -41,8 +42,8 @@
 
 /* get start field of a dir entry */
 #define FSTART(p,fs) \
-  ((unsigned long)CF_LE_W(p->dir_ent.start) | \
-   (fs->fat_bits == 32 ? CF_LE_W(p->dir_ent.starthi) << 16 : 0))
+  ((uint32_t)le16toh(p->dir_ent.start) | \
+   (fs->fat_bits == 32 ? le16toh(p->dir_ent.starthi) << 16 : 0))
 
 #define MODIFY(p,i,v)					\
   do {							\
@@ -55,22 +56,22 @@
 
 #define MODIFY_START(p,v,fs)						\
   do {									\
-    unsigned long __v = (v);						\
+    uint32_t __v = (v);						\
     if (!p->offset) {							\
 	/* writing to fake entry for FAT32 root dir */			\
 	if (!__v) die("Oops, deleting FAT32 root dir!");		\
 	fs->root_cluster = __v;						\
-	p->dir_ent.start = CT_LE_W(__v&0xffff);				\
-	p->dir_ent.starthi = CT_LE_W(__v>>16);				\
-	__v = CT_LE_L(__v);						\
+	p->dir_ent.start = htole16(__v&0xffff);				\
+	p->dir_ent.starthi = htole16(__v>>16);				\
+	__v = htole32(__v);						\
 	fs_write((loff_t)offsetof(struct boot_sector,root_cluster),	\
 	         sizeof(((struct boot_sector *)0)->root_cluster),	\
 		 &__v);							\
     }									\
     else {								\
-	MODIFY(p,start,CT_LE_W((__v)&0xffff));				\
+	MODIFY(p,start,htole16((__v)&0xffff));				\
 	if (fs->fat_bits == 32)						\
-	    MODIFY(p,starthi,CT_LE_W((__v)>>16));			\
+	    MODIFY(p,starthi,htole16((__v)>>16));			\
     }									\
   } while(0)
 
@@ -82,7 +83,7 @@
     if (fs->root_cluster) {
 	DIR_ENT d2;
 	int i = 0, got = 0;
-	unsigned long clu_num, prev = 0;
+	uint32_t clu_num, prev = 0;
 	loff_t offset2;
 
 	clu_num = fs->root_cluster;
@@ -131,8 +132,8 @@
 	while (1) {
 	    char expanded[12];
 	    sprintf(expanded, pattern, curr_num);
-	    memcpy(de->name + 4, expanded, 4);
-	    memcpy(de->ext, expanded + 4, 3);
+	    memcpy(de->name, expanded, 8);
+	    memcpy(de->ext, expanded + 8, 3);
 	    clu_num = fs->root_cluster;
 	    i = 0;
 	    offset2 = cluster_start(fs, clu_num);
@@ -174,7 +175,10 @@
 	offset = fs->root_start + next_free * sizeof(DIR_ENT);
 	memset(de, 0, sizeof(DIR_ENT));
 	while (1) {
-	    sprintf((char *)de->name, pattern, curr_num);
+	    char expanded[12];
+	    sprintf(expanded, pattern, curr_num);
+	    memcpy(de->name, expanded, 8);
+	    memcpy(de->ext, expanded + 8, 3);
 	    for (scan = 0; scan < fs->root_entries; scan++)
 		if (scan != next_free &&
 		    !strncmp((const char *)root[scan].name,
@@ -220,18 +224,22 @@
     return path;
 }
 
-static int day_n[] =
-    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 };
-		  /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+static const int day_n[] =
+    {   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 };
+/*    Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec              */
 
 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
 
-time_t date_dos2unix(unsigned short time, unsigned short date)
+static time_t date_dos2unix(unsigned short time, unsigned short date)
 {
     int month, year;
     time_t secs;
 
     month = ((date >> 5) & 15) - 1;
+    if (month < 0) {
+	/* make sure that nothing bad happens if the month bits were zero */
+	month = 0;
+    }
     year = date >> 9;
     secs =
 	(time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
@@ -249,18 +257,19 @@
     time_t date;
 
     date =
-	date_dos2unix(CF_LE_W(file->dir_ent.time), CF_LE_W(file->dir_ent.date));
+	date_dos2unix(le16toh(file->dir_ent.time), le16toh(file->dir_ent.date));
     tm = localtime(&date);
     strftime(tmp, 99, "%H:%M:%S %b %d %Y", tm);
-    sprintf(temp, "  Size %u bytes, date %s", CF_LE_L(file->dir_ent.size), tmp);
+    sprintf(temp, "  Size %u bytes, date %s", le32toh(file->dir_ent.size), tmp);
     return temp;
 }
 
 static int bad_name(DOS_FILE * file)
 {
     int i, spc, suspicious = 0;
-    char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:";
-    unsigned char *name = file->dir_ent.name;
+    const char *bad_chars = atari_format ? "*?\\/:" : "*?<>|\"\\/:";
+    const unsigned char *name = file->dir_ent.name;
+    const unsigned char *ext = file->dir_ent.ext;
 
     /* Do not complain about (and auto-correct) the extended attribute files
      * of OS/2. */
@@ -268,6 +277,11 @@
 	strncmp((const char *)name, "WP ROOT  SF", 11) == 0)
 	return 0;
 
+    /* check if we have neither a long filename nor a short name */
+    if ((file->lfn == NULL) && (file->dir_ent.lcase & FAT_NO_83NAME)) {
+	return 1;
+    }
+
     /* don't complain about the dummy 11 bytes used by patched Linux
        kernels */
     if (file->dir_ent.lcase & FAT_NO_83NAME)
@@ -282,12 +296,12 @@
 	    return 1;
     }
 
-    for (i = 8; i < 11; i++) {
-	if (name[i] < ' ' || name[i] == 0x7f)
+    for (i = 0; i < 3; i++) {
+	if (ext[i] < ' ' || ext[i] == 0x7f)
 	    return 1;
-	if (name[i] > 0x7f)
+	if (ext[i] > 0x7f)
 	    ++suspicious;
-	if (strchr(bad_chars, name[i]))
+	if (strchr(bad_chars, ext[i]))
 	    return 1;
     }
 
@@ -302,11 +316,11 @@
     }
 
     spc = 0;
-    for (i = 8; i < 11; i++) {
-	if (name[i] == ' ')
+    for (i = 0; i < 3; i++) {
+	if (ext[i] == ' ')
 	    spc = 1;
 	else if (spc)
-	    /* non-space after a space not allowed, space terminates the name
+	    /* non-space after a space not allowed, space terminates the ext
 	     * part */
 	    return 1;
     }
@@ -340,7 +354,7 @@
 
 static void drop_file(DOS_FS * fs, DOS_FILE * file)
 {
-    unsigned long cluster;
+    uint32_t cluster;
 
     MODIFY(file, name[0], DELETED_FLAG);
     if (file->lfn)
@@ -351,13 +365,12 @@
     --n_files;
 }
 
-static void truncate_file(DOS_FS * fs, DOS_FILE * file, unsigned long clusters)
+static void truncate_file(DOS_FS * fs, DOS_FILE * file, uint32_t clusters)
 {
     int deleting;
-    unsigned long walk, next, prev;
+    uint32_t walk, next;
 
     walk = FSTART(file, fs);
-    prev = 0;
     if ((deleting = !clusters))
 	MODIFY_START(file, 0, fs);
     while (walk > 0 && walk != -1) {
@@ -366,7 +379,6 @@
 	    set_fat(fs, walk, 0);
 	else if ((deleting = !--clusters))
 	    set_fat(fs, walk, -1);
-	prev = walk;
 	walk = next;
     }
 }
@@ -374,7 +386,7 @@
 static void auto_rename(DOS_FILE * file)
 {
     DOS_FILE *first, *walk;
-    unsigned long int number;
+    uint32_t number;
 
     if (!file->offset)
 	return;			/* cannot rename FAT32 root dir */
@@ -382,7 +394,7 @@
     number = 0;
     while (1) {
 	char num[8];
-	sprintf(num, "%07lu", number);
+	sprintf(num, "%07lu", (unsigned long)number);
 	memcpy(file->dir_ent.name, "FSCK", 4);
 	memcpy(file->dir_ent.name + 4, num, 4);
 	memcpy(file->dir_ent.ext, num + 4, 3);
@@ -392,7 +404,16 @@
 			    (const char *)file->dir_ent.name, MSDOS_NAME))
 		break;
 	if (!walk) {
-	    fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
+	    if (file->dir_ent.lcase & FAT_NO_83NAME) {
+		/* as we only assign a new 8.3 filename, reset flag that 8.3 name is not
+		   present */
+		file->dir_ent.lcase &= ~FAT_NO_83NAME;
+		/* reset the attributes, only keep DIR and VOLUME */
+		file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME);
+		fs_write(file->offset, MSDOS_NAME + 2, file->dir_ent.name);
+	    } else {
+		fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
+	    }
 	    if (file->lfn)
 		lfn_fix_checksum(file->lfn_offset, file->offset,
 				 (const char *)file->dir_ent.name);
@@ -426,7 +447,16 @@
 	    walk[1] = 0;
 	    for (walk = name; *walk == ' ' || *walk == '\t'; walk++) ;
 	    if (file_cvt(walk, file->dir_ent.name)) {
-		fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
+		if (file->dir_ent.lcase & FAT_NO_83NAME) {
+		    /* as we only assign a new 8.3 filename, reset flag that 8.3 name is not
+		       present */
+		    file->dir_ent.lcase &= ~FAT_NO_83NAME;
+		    /* reset the attributes, only keep DIR and VOLUME */
+		    file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME);
+		    fs_write(file->offset, MSDOS_NAME + 2, file->dir_ent.name);
+		} else {
+		    fs_write(file->offset, MSDOS_NAME, file->dir_ent.name);
+		}
 		if (file->lfn)
 		    lfn_fix_checksum(file->lfn_offset, file->offset,
 				     (const char *)file->dir_ent.name);
@@ -438,7 +468,7 @@
 
 static int handle_dot(DOS_FS * fs, DOS_FILE * file, int dots)
 {
-    char *name;
+    const char *name;
 
     name =
 	strncmp((const char *)file->dir_ent.name, MSDOS_DOT,
@@ -462,7 +492,7 @@
 	    rename_file(file);
 	    return 0;
 	case '4':
-	    MODIFY(file, size, CT_LE_L(0));
+	    MODIFY(file, size, htole32(0));
 	    MODIFY(file, attr, file->dir_ent.attr | ATTR_DIR);
 	    break;
 	}
@@ -479,21 +509,21 @@
 {
     DOS_FILE *owner;
     int restart;
-    unsigned long expect, curr, this, clusters, prev, walk, clusters2;
+    uint32_t expect, curr, this, clusters, prev, walk, clusters2;
 
     if (file->dir_ent.attr & ATTR_DIR) {
-	if (CF_LE_L(file->dir_ent.size)) {
+	if (le32toh(file->dir_ent.size)) {
 	    printf("%s\n  Directory has non-zero size. Fixing it.\n",
 		   path_name(file));
-	    MODIFY(file, size, CT_LE_L(0));
+	    MODIFY(file, size, htole32(0));
 	}
 	if (file->parent
 	    && !strncmp((const char *)file->dir_ent.name, MSDOS_DOT,
 			MSDOS_NAME)) {
 	    expect = FSTART(file->parent, fs);
 	    if (FSTART(file, fs) != expect) {
-		printf("%s\n  Start (%ld) does not point to parent (%ld)\n",
-		       path_name(file), FSTART(file, fs), expect);
+		printf("%s\n  Start (%lu) does not point to parent (%lu)\n",
+		       path_name(file), (unsigned long)FSTART(file, fs), (long)expect);
 		MODIFY_START(file, expect, fs);
 	    }
 	    return 0;
@@ -507,7 +537,7 @@
 		expect = 0;
 	    if (FSTART(file, fs) != expect) {
 		printf("%s\n  Start (%lu) does not point to .. (%lu)\n",
-		       path_name(file), FSTART(file, fs), expect);
+		       path_name(file), (unsigned long)FSTART(file, fs), (unsigned long)expect);
 		MODIFY_START(file, expect, fs);
 	    }
 	    return 0;
@@ -519,12 +549,20 @@
 	    return 0;
 	}
     }
+    if (FSTART(file, fs) == 1) {
+	printf("%s\n  Bad start cluster 1. Truncating file.\n",
+	       path_name(file));
+	if (!file->offset)
+	    die("Bad FAT32 root directory! (bad start cluster 1)\n");
+	MODIFY_START(file, 0, fs);
+    }
     if (FSTART(file, fs) >= fs->clusters + 2) {
 	printf
 	    ("%s\n  Start cluster beyond limit (%lu > %lu). Truncating file.\n",
-	     path_name(file), FSTART(file, fs), fs->clusters + 1);
+	     path_name(file), (unsigned long)FSTART(file, fs), (unsigned long)(fs->clusters + 1));
 	if (!file->offset)
-	    die("Bad FAT32 root directory! (bad start cluster)\n");
+	    die("Bad FAT32 root directory! (start cluster beyond limit: %lu > %lu)\n",
+		(unsigned long)FSTART(file, fs), (unsigned long)(fs->clusters + 1));
 	MODIFY_START(file, 0, fs);
     }
     clusters = prev = 0;
@@ -535,7 +573,7 @@
 
 	if (!curEntry.value || bad_cluster(fs, curr)) {
 	    printf("%s\n  Contains a %s cluster (%lu). Assuming EOF.\n",
-		   path_name(file), curEntry.value ? "bad" : "free", curr);
+		   path_name(file), curEntry.value ? "bad" : "free", (unsigned long)curr);
 	    if (prev)
 		set_fat(fs, prev, -1);
 	    else if (!file->offset)
@@ -544,14 +582,14 @@
 		MODIFY_START(file, 0, fs);
 	    break;
 	}
-	if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) <=
-	    (unsigned long long)clusters * fs->cluster_size) {
+	if (!(file->dir_ent.attr & ATTR_DIR) && le32toh(file->dir_ent.size) <=
+	    (uint64_t)clusters * fs->cluster_size) {
 	    printf
-		("%s\n  File size is %u bytes, cluster chain length is > %llu "
+		("%s\n  File size is %u bytes, cluster chain length is > %lu "
 		 "bytes.\n  Truncating file to %u bytes.\n", path_name(file),
-		 CF_LE_L(file->dir_ent.size),
-		 (unsigned long long)clusters * fs->cluster_size,
-		 CF_LE_L(file->dir_ent.size));
+		 le32toh(file->dir_ent.size),
+		 (uint64_t)clusters * fs->cluster_size,
+		 le32toh(file->dir_ent.size));
 	    truncate_file(fs, file, clusters);
 	    break;
 	}
@@ -599,7 +637,7 @@
 			else
 			    MODIFY_START(owner, 0, fs);
 			MODIFY(owner, size,
-			       CT_LE_L((unsigned long long)clusters *
+			       htole32((uint64_t)clusters *
 				       fs->cluster_size));
 			if (restart)
 			    return 1;
@@ -628,16 +666,16 @@
 	clusters++;
 	prev = curr;
     }
-    if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) >
-	(unsigned long long)clusters * fs->cluster_size) {
+    if (!(file->dir_ent.attr & ATTR_DIR) && le32toh(file->dir_ent.size) >
+	(uint64_t)clusters * fs->cluster_size) {
 	printf
 	    ("%s\n  File size is %u bytes, cluster chain length is %llu bytes."
 	     "\n  Truncating file to %llu bytes.\n", path_name(file),
-	     CF_LE_L(file->dir_ent.size),
+	     le32toh(file->dir_ent.size),
 	     (unsigned long long)clusters * fs->cluster_size,
 	     (unsigned long long)clusters * fs->cluster_size);
 	MODIFY(file, size,
-	       CT_LE_L((unsigned long long)clusters * fs->cluster_size));
+	       htole32((uint64_t)clusters * fs->cluster_size));
     }
     return 0;
 }
@@ -807,10 +845,10 @@
 static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test)
 {
     DOS_FILE *owner;
-    unsigned long walk, prev, clusters, next_clu;
+    uint32_t walk, prev, clusters, next_clu;
 
     prev = clusters = 0;
-    for (walk = FSTART(file, fs); walk > 0 && walk < fs->clusters + 2;
+    for (walk = FSTART(file, fs); walk > 1 && walk < fs->clusters + 2;
 	 walk = next_clu) {
 	next_clu = next_cluster(fs, walk);
 
@@ -821,7 +859,7 @@
 	if ((owner = get_owner(fs, walk))) {
 	    if (owner == file) {
 		printf("%s\n  Circular cluster chain. Truncating to %lu "
-		       "cluster%s.\n", path_name(file), clusters,
+		       "cluster%s.\n", path_name(file), (unsigned long)clusters,
 		       clusters == 1 ? "" : "s");
 		if (prev)
 		    set_fat(fs, prev, -1);
@@ -840,7 +878,7 @@
 		clusters++;
 	    } else {
 		printf("%s\n  Cluster %lu (%lu) is unreadable. Skipping it.\n",
-		       path_name(file), clusters, walk);
+		       path_name(file), (unsigned long)clusters, (unsigned long)walk);
 		if (prev)
 		    set_fat(fs, prev, next_cluster(fs, walk));
 		else
@@ -851,7 +889,7 @@
 	set_owner(fs, walk, file);
     }
     /* Revert ownership (for now) */
-    for (walk = FSTART(file, fs); walk > 0 && walk < fs->clusters + 2;
+    for (walk = FSTART(file, fs); walk > 1 && walk < fs->clusters + 2;
 	 walk = next_cluster(fs, walk))
 	if (bad_cluster(fs, walk))
 	    break;
@@ -863,9 +901,9 @@
 
 static void undelete(DOS_FS * fs, DOS_FILE * file)
 {
-    unsigned long clusters, left, prev, walk;
+    uint32_t clusters, left, prev, walk;
 
-    clusters = left = (CF_LE_L(file->dir_ent.size) + fs->cluster_size - 1) /
+    clusters = left = (le32toh(file->dir_ent.size) + fs->cluster_size - 1) /
 	fs->cluster_size;
     prev = 0;
 
@@ -891,7 +929,7 @@
 	MODIFY_START(file, 0, fs);
     if (left)
 	printf("Warning: Did only undelete %lu of %lu cluster%s.\n",
-	       clusters - left, clusters, clusters == 1 ? "" : "s");
+	       (unsigned long)clusters - left, (unsigned long)clusters, clusters == 1 ? "" : "s");
 
 }
 
@@ -924,11 +962,11 @@
 	fs_read(offset, sizeof(DIR_ENT), &de);
     else {
 	/* Construct a DIR_ENT for the root directory */
+	memset(&de, 0, sizeof de);
 	memcpy(de.name, "           ", MSDOS_NAME);
 	de.attr = ATTR_DIR;
-	de.size = de.time = de.date = 0;
-	de.start = CT_LE_W(fs->root_cluster & 0xffff);
-	de.starthi = CT_LE_W((fs->root_cluster >> 16) & 0xffff);
+	de.start = htole16(fs->root_cluster & 0xffff);
+	de.starthi = htole16((fs->root_cluster >> 16) & 0xffff);
     }
     if ((type = file_type(cp, (char *)de.name)) != fdt_none) {
 	if (type == fdt_undelete && (de.attr & ATTR_DIR))
@@ -974,7 +1012,7 @@
 {
     DOS_FILE **chain;
     int i;
-    unsigned long clu_num;
+    uint32_t clu_num;
 
     chain = &this->first;
     i = 0;
diff --git a/dosfstools/src/check.h b/dosfstools/src/check.h
index 277c44b..fcb6bea 100644
--- a/dosfstools/src/check.h
+++ b/dosfstools/src/check.h
@@ -1,6 +1,7 @@
-/* check.h - Check and repair a PC/MS-DOS file system
+/* check.h - Check and repair a PC/MS-DOS filesystem
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -15,7 +16,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -33,7 +34,7 @@
 int scan_root(DOS_FS * fs);
 
 /* Scans the root directory and recurses into all subdirectories. See check.c
-   for all the details. Returns a non-zero integer if the file system has to
+   for all the details. Returns a non-zero integer if the filesystem has to
    be checked again. */
 
 #endif
diff --git a/dosfstools/src/common.c b/dosfstools/src/common.c
index 51605a2..9d11193 100644
--- a/dosfstools/src/common.c
+++ b/dosfstools/src/common.c
@@ -2,6 +2,7 @@
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -16,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -36,7 +37,7 @@
     struct _link *next;
 } LINK;
 
-void die(char *msg, ...)
+void die(const char *msg, ...)
 {
     va_list args;
 
@@ -47,7 +48,7 @@
     exit(1);
 }
 
-void pdie(char *msg, ...)
+void pdie(const char *msg, ...)
 {
     va_list args;
 
@@ -95,7 +96,7 @@
     return a < b ? a : b;
 }
 
-char get_key(char *valid, char *prompt)
+char get_key(const char *valid, const char *prompt)
 {
     int ch, okay;
 
diff --git a/dosfstools/src/common.h b/dosfstools/src/common.h
index 395eabb..c15efb5 100644
--- a/dosfstools/src/common.h
+++ b/dosfstools/src/common.h
@@ -1,6 +1,7 @@
 /* common.h - Common functions
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -15,20 +16,18 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
-#include <asm/types.h>
-
 #ifndef _COMMON_H
 #define _COMMON_H
 
-void die(char *msg, ...) __attribute((noreturn));
+void die(const char *msg, ...) __attribute((noreturn));
 
 /* Displays a prinf-style message and terminates the program. */
 
-void pdie(char *msg, ...) __attribute((noreturn));
+void pdie(const char *msg, ...) __attribute((noreturn));
 
 /* Like die, but appends an error message according to the state of errno. */
 
@@ -49,7 +48,7 @@
 
 /* Returns the smaller integer value of a and b. */
 
-char get_key(char *valid, char *prompt);
+char get_key(const char *valid, const char *prompt);
 
 /* Displays PROMPT and waits for user input. Only characters in VALID are
    accepted. Terminates the program on EOF. Returns the character. */
diff --git a/dosfstools/src/dosfsck.h b/dosfstools/src/dosfsck.h
deleted file mode 100644
index 6f53c72..0000000
--- a/dosfstools/src/dosfsck.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/* dosfsck.h  -  Common data structures and global variables
-
-   Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
-   Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
-
-   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
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-   On Debian systems, the complete text of the GNU General Public License
-   can be found in /usr/share/common-licenses/GPL-3 file.
-*/
-
-/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
- * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
-
-#ifndef _DOSFSCK_H
-#define _DOSFSCK_H
-
-#include <sys/types.h>
-#define _LINUX_STAT_H		/* hack to avoid inclusion of <linux/stat.h> */
-#define _LINUX_STRING_H_	/* hack to avoid inclusion of <linux/string.h> */
-#define _LINUX_FS_H		/* hack to avoid inclusion of <linux/fs.h> */
-
-#ifdef _USING_BIONIC_
-#include <sys/endian.h>
-#endif
-
-#include <asm/types.h>
-#include <asm/byteorder.h>
-
-#include <linux/msdos_fs.h>
-
-#undef CF_LE_W
-#undef CF_LE_L
-#undef CT_LE_W
-#undef CT_LE_L
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-#include <byteswap.h>
-#define CF_LE_W(v) bswap_16(v)
-#define CF_LE_L(v) bswap_32(v)
-#define CT_LE_W(v) CF_LE_W(v)
-#define CT_LE_L(v) CF_LE_L(v)
-#else
-#define CF_LE_W(v) (v)
-#define CF_LE_L(v) (v)
-#define CT_LE_W(v) (v)
-#define CT_LE_L(v) (v)
-#endif /* __BIG_ENDIAN */
-
-#define VFAT_LN_ATTR (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME)
-
-/* ++roman: Use own definition of boot sector structure -- the kernel headers'
- * name for it is msdos_boot_sector in 2.0 and fat_boot_sector in 2.1 ... */
-struct boot_sector {
-    __u8 ignored[3];		/* Boot strap short or near jump */
-    __u8 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) */
-
-    /* The following fields are only used by FAT32 */
-    __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 */
-    __u8 reserved2[12];		/* Unused */
-
-    __u8 drive_number;		/* Logical Drive Number */
-    __u8 reserved3;		/* Unused */
-
-    __u8 extended_sig;		/* Extended Signature (0x29) */
-    __u32 serial;		/* Serial number */
-    __u8 label[11];		/* FS label */
-    __u8 fs_type[8];		/* FS Type */
-
-    /* fill up to 512 bytes */
-    __u8 junk[422];
-} __attribute__ ((packed));
-
-struct boot_sector_16 {
-    __u8 ignored[3];		/* Boot strap short or near jump */
-    __u8 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) */
-
-    __u8 drive_number;		/* Logical Drive Number */
-    __u8 reserved2;		/* Unused */
-
-    __u8 extended_sig;		/* Extended Signature (0x29) */
-    __u32 serial;		/* Serial number */
-    __u8 label[11];		/* FS label */
-    __u8 fs_type[8];		/* FS Type */
-
-    /* fill up to 512 bytes */
-    __u8 junk[450];
-} __attribute__ ((packed));
-
-struct info_sector {
-    __u32 magic;		/* Magic for info sector ('RRaA') */
-    __u8 junk[0x1dc];
-    __u32 reserved1;		/* Nothing as far as I can tell */
-    __u32 signature;		/* 0x61417272 ('rrAa') */
-    __u32 free_clusters;	/* Free cluster count.  -1 if unknown */
-    __u32 next_cluster;		/* Most recently allocated cluster. */
-    __u32 reserved2[3];
-    __u16 reserved3;
-    __u16 boot_sign;
-};
-
-typedef struct {
-    __u8 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 cluster in FAT32 */
-    __u16 time, date, start;	/* time, date and first cluster */
-    __u32 size;			/* file size (in bytes) */
-} __attribute__ ((packed)) DIR_ENT;
-
-typedef struct _dos_file {
-    DIR_ENT dir_ent;
-    char *lfn;
-    loff_t offset;
-    loff_t lfn_offset;
-    struct _dos_file *parent;	/* parent directory */
-    struct _dos_file *next;	/* next entry */
-    struct _dos_file *first;	/* first entry (directory only) */
-} DOS_FILE;
-
-typedef struct {
-    unsigned long value;
-    unsigned long reserved;
-} FAT_ENTRY;
-
-typedef struct {
-    int nfats;
-    loff_t fat_start;
-    unsigned int fat_size;	/* unit is bytes */
-    unsigned int fat_bits;	/* size of a FAT entry */
-    unsigned int eff_fat_bits;	/* # of used bits in a FAT entry */
-    unsigned long root_cluster;	/* 0 for old-style root dir */
-    loff_t root_start;
-    unsigned int root_entries;
-    loff_t data_start;
-    unsigned int cluster_size;
-    unsigned long clusters;
-    loff_t fsinfo_start;	/* 0 if not present */
-    long free_clusters;
-    loff_t backupboot_start;	/* 0 if not present */
-    unsigned char *fat;
-    DOS_FILE **cluster_owner;
-    char *label;
-} DOS_FS;
-
-#ifndef offsetof
-#define offsetof(t,e)	((int)&(((t *)0)->e))
-#endif
-
-extern int interactive, rw, list, verbose, test, write_immed;
-extern int atari_format;
-extern unsigned n_files;
-extern void *mem_queue;
-extern unsigned retandroid;
-
-/* value to use as end-of-file marker */
-#define FAT_EOF(fs)	((atari_format ? 0xfff : 0xff8) | FAT_EXTD(fs))
-#define FAT_IS_EOF(fs,v) ((unsigned long)(v) >= (0xff8|FAT_EXTD(fs)))
-/* value to mark bad clusters */
-#define FAT_BAD(fs)	(0xff7 | FAT_EXTD(fs))
-/* range of values used for bad clusters */
-#define FAT_MIN_BAD(fs)	((atari_format ? 0xff0 : 0xff7) | FAT_EXTD(fs))
-#define FAT_MAX_BAD(fs)	((atari_format ? 0xff7 : 0xff7) | FAT_EXTD(fs))
-#define FAT_IS_BAD(fs,v) ((v) >= FAT_MIN_BAD(fs) && (v) <= FAT_MAX_BAD(fs))
-
-/* return -16 as a number with fs->fat_bits bits */
-#define FAT_EXTD(fs)	(((1 << fs->eff_fat_bits)-1) & ~0xf)
-
-/* marker for files with no 8.3 name */
-#define FAT_NO_83NAME 32
-
-#endif
diff --git a/dosfstools/src/fat.c b/dosfstools/src/fat.c
index 5a0dfb0..5a92f56 100644
--- a/dosfstools/src/fat.c
+++ b/dosfstools/src/fat.c
@@ -2,6 +2,7 @@
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -16,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -29,7 +30,7 @@
 #include <unistd.h>
 
 #include "common.h"
-#include "dosfsck.h"
+#include "fsck.fat.h"
 #include "io.h"
 #include "check.h"
 #include "fat.h"
@@ -42,7 +43,7 @@
  * @param[in]	cluster     Cluster of interest
  * @param[in]	fs          Information from the FAT boot sectors (bits per FAT entry)
  */
-void get_fat(FAT_ENTRY * entry, void *fat, unsigned long cluster, DOS_FS * fs)
+void get_fat(FAT_ENTRY * entry, void *fat, uint32_t cluster, DOS_FS * fs)
 {
     unsigned char *ptr;
 
@@ -53,13 +54,13 @@
 				(ptr[0] | ptr[1] << 8));
 	break;
     case 16:
-	entry->value = CF_LE_W(((unsigned short *)fat)[cluster]);
+	entry->value = le16toh(((unsigned short *)fat)[cluster]);
 	break;
     case 32:
 	/* According to M$, the high 4 bits of a FAT32 entry are reserved and
 	 * are not part of the cluster number. So we cut them off. */
 	{
-	    unsigned long e = CF_LE_L(((unsigned int *)fat)[cluster]);
+	    uint32_t e = le32toh(((unsigned int *)fat)[cluster]);
 	    entry->value = e & 0xfffffff;
 	    entry->reserved = e >> 28;
 	}
@@ -79,24 +80,34 @@
  */
 void read_fat(DOS_FS * fs)
 {
-    int eff_size;
-    unsigned long i;
+    int eff_size, alloc_size;
+    uint32_t i;
     void *first, *second = NULL;
     int first_ok, second_ok;
-    unsigned long total_num_clusters;
+    uint32_t total_num_clusters;
 
     /* Clean up from previous pass */
-    free(fs->fat);
-    free(fs->cluster_owner);
+    if (fs->fat)
+	free(fs->fat);
+    if (fs->cluster_owner)
+	free(fs->cluster_owner);
     fs->fat = NULL;
     fs->cluster_owner = NULL;
 
     total_num_clusters = fs->clusters + 2UL;
     eff_size = (total_num_clusters * fs->fat_bits + 7) / 8ULL;
-    first = alloc(eff_size);
+
+    if (fs->fat_bits != 12)
+	    alloc_size = eff_size;
+    else
+	    /* round up to an even number of FAT entries to avoid special
+	     * casing the last entry in get_fat() */
+	    alloc_size = (total_num_clusters * 12 + 23) / 24 * 3;
+
+    first = alloc(alloc_size);
     fs_read(fs->fat_start, eff_size, first);
     if (fs->nfats > 1) {
-	second = alloc(eff_size);
+	second = alloc(alloc_size);
 	fs_read(fs->fat_start + fs->fat_size, eff_size, second);
     }
     if (second && memcmp(first, second, eff_size) != 0) {
@@ -148,13 +159,13 @@
 	FAT_ENTRY curEntry;
 	get_fat(&curEntry, fs->fat, i, fs);
 	if (curEntry.value == 1) {
-	    printf("Cluster %ld out of range (1). Setting to EOF.\n", i - 2);
+	    printf("Cluster %ld out of range (1). Setting to EOF.\n", (long)(i - 2));
 	    set_fat(fs, i, -1);
 	}
 	if (curEntry.value >= fs->clusters + 2 &&
 	    (curEntry.value < FAT_MIN_BAD(fs))) {
 	    printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
-		   i - 2, curEntry.value, fs->clusters + 2 - 1);
+		   (long)(i - 2), (long)curEntry.value, (long)(fs->clusters + 2 - 1));
 	    set_fat(fs, i, -1);
 	}
     }
@@ -173,13 +184,13 @@
  *				  -1 == end-of-chain
  *				  -2 == bad cluster
  */
-void set_fat(DOS_FS * fs, unsigned long cluster, unsigned long new)
+void set_fat(DOS_FS * fs, uint32_t cluster, int32_t new)
 {
     unsigned char *data = NULL;
     int size;
     loff_t offs;
 
-    if ((long)new == -1)
+    if (new == -1)
 	new = FAT_EOF(fs);
     else if ((long)new == -2)
 	new = FAT_BAD(fs);
@@ -204,7 +215,7 @@
     case 16:
 	data = fs->fat + cluster * 2;
 	offs = fs->fat_start + cluster * 2;
-	*(unsigned short *)data = CT_LE_W(new);
+	*(unsigned short *)data = htole16(new);
 	size = 2;
 	break;
     case 32:
@@ -216,7 +227,7 @@
 	    offs = fs->fat_start + cluster * 4;
 	    /* According to M$, the high 4 bits of a FAT32 entry are reserved and
 	     * are not part of the cluster number. So we never touch them. */
-	    *(unsigned long *)data = CT_LE_L((new & 0xfffffff) |
+	    *(uint32_t *)data = htole32((new & 0xfffffff) |
 					     (curEntry.reserved << 28));
 	    size = 4;
 	}
@@ -230,7 +241,7 @@
     }
 }
 
-int bad_cluster(DOS_FS * fs, unsigned long cluster)
+int bad_cluster(DOS_FS * fs, uint32_t cluster)
 {
     FAT_ENTRY curEntry;
     get_fat(&curEntry, fs->fat, cluster, fs);
@@ -248,9 +259,9 @@
  * @return  -1              'cluster' is at the end of the chain
  * @return  Other values    Next cluster in this chain
  */
-unsigned long next_cluster(DOS_FS * fs, unsigned long cluster)
+uint32_t next_cluster(DOS_FS * fs, uint32_t cluster)
 {
-    unsigned long value;
+    uint32_t value;
     FAT_ENTRY curEntry;
 
     get_fat(&curEntry, fs->fat, cluster, fs);
@@ -261,10 +272,10 @@
     return FAT_IS_EOF(fs, value) ? -1 : value;
 }
 
-loff_t cluster_start(DOS_FS * fs, unsigned long cluster)
+loff_t cluster_start(DOS_FS * fs, uint32_t cluster)
 {
     return fs->data_start + ((loff_t) cluster -
-			     2) * (unsigned long long)fs->cluster_size;
+			     2) * (uint64_t)fs->cluster_size;
 }
 
 /**
@@ -276,7 +287,7 @@
  * @param[in]	    owner       Information on dentry that owns this cluster
  *                              (may be NULL)
  */
-void set_owner(DOS_FS * fs, unsigned long cluster, DOS_FILE * owner)
+void set_owner(DOS_FS * fs, uint32_t cluster, DOS_FILE * owner)
 {
     if (fs->cluster_owner == NULL)
 	die("Internal error: attempt to set owner in non-existent table");
@@ -287,7 +298,7 @@
     fs->cluster_owner[cluster] = owner;
 }
 
-DOS_FILE *get_owner(DOS_FS * fs, unsigned long cluster)
+DOS_FILE *get_owner(DOS_FS * fs, uint32_t cluster)
 {
     if (fs->cluster_owner == NULL)
 	return NULL;
@@ -297,7 +308,7 @@
 
 void fix_bad(DOS_FS * fs)
 {
-    unsigned long i;
+    uint32_t i;
 
     if (verbose)
 	printf("Checking for bad clusters.\n");
@@ -307,7 +318,7 @@
 
 	if (!get_owner(fs, i) && !FAT_IS_BAD(fs, curEntry.value))
 	    if (!fs_test(cluster_start(fs, i), fs->cluster_size)) {
-		printf("Cluster %lu is unreadable.\n", i);
+		printf("Cluster %lu is unreadable.\n", (unsigned long)i);
 		set_fat(fs, i, -2);
 	    }
     }
@@ -316,7 +327,7 @@
 void reclaim_free(DOS_FS * fs)
 {
     int reclaimed;
-    unsigned long i;
+    uint32_t i;
 
     if (verbose)
 	printf("Checking for unused clusters.\n");
@@ -332,7 +343,7 @@
 	}
     }
     if (reclaimed)
-	printf("Reclaimed %d unused cluster%s (%llu bytes).\n", reclaimed,
+	printf("Reclaimed %d unused cluster%s (%llu bytes).\n", (int)reclaimed,
 	       reclaimed == 1 ? "" : "s",
 	       (unsigned long long)reclaimed * fs->cluster_size);
 }
@@ -347,11 +358,11 @@
  *				   clusters link to it.
  * @param[in]	    start_cluster  Where to start scanning for orphans
  */
-static void tag_free(DOS_FS * fs, DOS_FILE * owner, unsigned long *num_refs,
-		     unsigned long start_cluster)
+static void tag_free(DOS_FS * fs, DOS_FILE * owner, uint32_t *num_refs,
+		     uint32_t start_cluster)
 {
     int prev;
-    unsigned long i, walk;
+    uint32_t i, walk;
 
     if (start_cluster == 0)
 	start_cluster = 2;
@@ -400,16 +411,16 @@
     DOS_FILE orphan;
     int reclaimed, files;
     int changed = 0;
-    unsigned long i, next, walk;
-    unsigned long *num_refs = NULL;	/* Only for orphaned clusters */
-    unsigned long total_num_clusters;
+    uint32_t i, next, walk;
+    uint32_t *num_refs = NULL;	/* Only for orphaned clusters */
+    uint32_t total_num_clusters;
 
     if (verbose)
 	printf("Reclaiming unconnected clusters.\n");
 
     total_num_clusters = fs->clusters + 2UL;
-    num_refs = alloc(total_num_clusters * sizeof(unsigned long));
-    memset(num_refs, 0, (total_num_clusters * sizeof(unsigned long)));
+    num_refs = alloc(total_num_clusters * sizeof(uint32_t));
+    memset(num_refs, 0, (total_num_clusters * sizeof(uint32_t)));
 
     /* Guarantee that all orphan chains (except cycles) end cleanly
      * with an end-of-chain mark.
@@ -454,7 +465,7 @@
 		    die("Internal error: num_refs going below zero");
 		set_fat(fs, i, -1);
 		changed = curEntry.value;
-		printf("Broke cycle at cluster %lu in free chain.\n", i);
+		printf("Broke cycle at cluster %lu in free chain.\n", (unsigned long)i);
 
 		/* If we've created a new chain head,
 		 * tag_free() can claim it
@@ -474,13 +485,13 @@
 	    DIR_ENT de;
 	    loff_t offset;
 	    files++;
-	    offset = alloc_rootdir_entry(fs, &de, "FSCK%04d");
-	    de.start = CT_LE_W(i & 0xffff);
+	    offset = alloc_rootdir_entry(fs, &de, "FSCK%04dREC");
+	    de.start = htole16(i & 0xffff);
 	    if (fs->fat_bits == 32)
-		de.starthi = CT_LE_W(i >> 16);
+		de.starthi = htole16(i >> 16);
 	    for (walk = i; walk > 0 && walk != -1;
 		 walk = next_cluster(fs, walk)) {
-		de.size = CT_LE_L(CF_LE_L(de.size) + fs->cluster_size);
+		de.size = htole32(le32toh(de.size) + fs->cluster_size);
 		reclaimed++;
 	    }
 	    fs_write(offset, sizeof(DIR_ENT), &de);
@@ -494,10 +505,10 @@
     free(num_refs);
 }
 
-unsigned long update_free(DOS_FS * fs)
+uint32_t update_free(DOS_FS * fs)
 {
-    unsigned long i;
-    unsigned long free = 0;
+    uint32_t i;
+    uint32_t free = 0;
     int do_set = 0;
 
     for (i = 2; i < fs->clusters + 2; i++) {
@@ -516,7 +527,7 @@
     if (fs->free_clusters != 0xFFFFFFFF) {
 	if (free != fs->free_clusters) {
 	    printf("Free cluster summary wrong (%ld vs. really %ld)\n",
-		   fs->free_clusters, free);
+		   (long)fs->free_clusters, (long)free);
 	    if (interactive)
 		printf("1) Correct\n2) Don't correct\n");
 	    else
@@ -525,7 +536,7 @@
 		do_set = 1;
 	}
     } else {
-	printf("Free cluster summary uninitialized (should be %ld)\n", free);
+	printf("Free cluster summary uninitialized (should be %ld)\n", (long)free);
 	if (rw) {
 	    if (interactive)
 		printf("1) Set it\n2) Leave it uninitialized\n");
@@ -537,7 +548,7 @@
     }
 
     if (do_set) {
-	unsigned long le_free = CT_LE_L(free);
+	uint32_t le_free = htole32(free);
 	fs->free_clusters = free;
 	fs_write(fs->fsinfo_start + offsetof(struct info_sector, free_clusters),
 		 sizeof(le_free), &le_free);
diff --git a/dosfstools/src/fat.h b/dosfstools/src/fat.h
index 13ac1b3..b50ed4a 100644
--- a/dosfstools/src/fat.h
+++ b/dosfstools/src/fat.h
@@ -1,6 +1,7 @@
 /* fat.h - Read/write access to the FAT
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -15,7 +16,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   THe complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -24,41 +25,41 @@
 
 void read_fat(DOS_FS * fs);
 
-/* Loads the FAT of the file system described by FS. Initializes the FAT,
+/* Loads the FAT of the filesystem described by FS. Initializes the FAT,
    replaces broken FATs and rejects invalid cluster entries. */
 
-void get_fat(FAT_ENTRY * entry, void *fat, unsigned long cluster, DOS_FS * fs);
+void get_fat(FAT_ENTRY * entry, void *fat, uint32_t cluster, DOS_FS * fs);
 
 /* Retrieve the FAT entry (next chained cluster) for CLUSTER. */
 
-void set_fat(DOS_FS * fs, unsigned long cluster, unsigned long new);
+void set_fat(DOS_FS * fs, uint32_t cluster, int32_t new);
 
 /* Changes the value of the CLUSTERth cluster of the FAT of FS to NEW. Special
    values of NEW are -1 (EOF, 0xff8 or 0xfff8) and -2 (bad sector, 0xff7 or
    0xfff7) */
 
-int bad_cluster(DOS_FS * fs, unsigned long cluster);
+int bad_cluster(DOS_FS * fs, uint32_t cluster);
 
 /* Returns a non-zero integer if the CLUSTERth cluster is marked as bad or zero
    otherwise. */
 
-unsigned long next_cluster(DOS_FS * fs, unsigned long cluster);
+uint32_t next_cluster(DOS_FS * fs, uint32_t cluster);
 
 /* Returns the number of the cluster following CLUSTER, or -1 if this is the
    last cluster of the respective cluster chain. CLUSTER must not be a bad
    cluster. */
 
-loff_t cluster_start(DOS_FS * fs, unsigned long cluster);
+loff_t cluster_start(DOS_FS * fs, uint32_t cluster);
 
 /* Returns the byte offset of CLUSTER, relative to the respective device. */
 
-void set_owner(DOS_FS * fs, unsigned long cluster, DOS_FILE * owner);
+void set_owner(DOS_FS * fs, uint32_t cluster, DOS_FILE * owner);
 
 /* Sets the owner pointer of the respective cluster to OWNER. If OWNER was NULL
    before, it can be set to NULL or any non-NULL value. Otherwise, only NULL is
    accepted as the new value. */
 
-DOS_FILE *get_owner(DOS_FS * fs, unsigned long cluster);
+DOS_FILE *get_owner(DOS_FS * fs, uint32_t cluster);
 
 /* Returns the owner of the repective cluster or NULL if the cluster has no
    owner. */
@@ -77,7 +78,7 @@
    for them in the root directory. Also tries to fix all inconsistencies (e.g.
    loops, shared clusters, etc.) in the process. */
 
-unsigned long update_free(DOS_FS * fs);
+uint32_t update_free(DOS_FS * fs);
 
 /* Updates free cluster count in FSINFO sector. */
 
diff --git a/dosfstools/src/dosfslabel.c b/dosfstools/src/fatlabel.c
similarity index 71%
rename from dosfstools/src/dosfslabel.c
rename to dosfstools/src/fatlabel.c
index 5e2d282..1484ba5 100644
--- a/dosfstools/src/dosfslabel.c
+++ b/dosfstools/src/fatlabel.c
@@ -1,8 +1,9 @@
-/* dosfslabel.c - User interface
+/* fatlabel.c - User interface
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
    Copyright (C) 2007 Red Hat, Inc.
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -17,7 +18,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -29,13 +30,10 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <getopt.h>
-
-#ifdef _USING_BIONIC_
-#include <linux/fs.h>
-#endif
+#include <ctype.h>
 
 #include "common.h"
-#include "dosfsck.h"
+#include "fsck.fat.h"
 #include "io.h"
 #include "boot.h"
 #include "fat.h"
@@ -52,7 +50,7 @@
     FILE *f = error ? stderr : stdout;
     int status = error ? 1 : 0;
 
-    fprintf(f, "usage: dosfslabel device [label]\n");
+    fprintf(f, "usage: fatlabel device [label]\n");
     exit(status);
 }
 
@@ -86,11 +84,16 @@
 
 int main(int argc, char *argv[])
 {
-    DOS_FS fs;
+    DOS_FS fs = { 0 };
     rw = 0;
 
+    int i;
+
     char *device = NULL;
-    char *label = NULL;
+    char label[12] = { 0 };
+
+    loff_t offset;
+    DIR_ENT de;
 
     check_atari();
 
@@ -100,25 +103,38 @@
     if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
 	usage(0);
     else if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
-	printf("dosfslabel " VERSION ", " VERSION_DATE ", FAT32, LFN\n");
+	printf("fatlabel " VERSION " (" VERSION_DATE ")\n");
 	exit(0);
     }
 
     device = argv[1];
     if (argc == 3) {
-	label = argv[2];
-	if (strlen(label) > 11) {
+	strncpy(label, argv[2], 11);
+	if (strlen(argv[2]) > 11) {
 	    fprintf(stderr,
-		    "dosfslabel: labels can be no longer than 11 characters\n");
+		    "fatlabel: labels can be no longer than 11 characters\n");
 	    exit(1);
 	}
+	for (i = 0; label[i] && i < 11; i++)
+	    /* don't know if here should be more strict !uppercase(label[i]) */
+	    if (islower(label[i])) {
+		fprintf(stderr,
+			"fatlabel: warning - lowercase labels might not work properly with DOS or Windows\n");
+		break;
+	    }
 	rw = 1;
     }
 
     fs_open(device, rw);
     read_boot(&fs);
+    if (fs.fat_bits == 32)
+	read_fat(&fs);
     if (!rw) {
-	fprintf(stdout, "%s\n", fs.label);
+	offset = find_volume_de(&fs, &de);
+	if (offset == 0)
+	    fprintf(stdout, "%s\n", fs.label);
+	else
+	    fprintf(stdout, "%.8s%.3s\n", de.name, de.ext);
 	exit(0);
     }
 
diff --git a/dosfstools/src/file.c b/dosfstools/src/file.c
index a73b73f..dffcec1 100644
--- a/dosfstools/src/file.c
+++ b/dosfstools/src/file.c
@@ -2,6 +2,7 @@
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -16,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -29,16 +30,9 @@
 #include <ctype.h>
 #include <unistd.h>
 
-#define _LINUX_STAT_H		/* hack to avoid inclusion of <linux/stat.h> */
-#define _LINUX_STRING_H_	/* hack to avoid inclusion of <linux/string.h> */
-#define _LINUX_FS_H		/* hack to avoid inclusion of <linux/fs.h> */
-
-#include <asm/types.h>
-
-#include <linux/msdos_fs.h>
-
 #include "common.h"
 #include "file.h"
+#include "msdos_fs.h"
 
 FDSC *fp_root = NULL;
 
diff --git a/dosfstools/src/file.h b/dosfstools/src/file.h
index 40bd58a..eaaf356 100644
--- a/dosfstools/src/file.h
+++ b/dosfstools/src/file.h
@@ -1,6 +1,7 @@
 /* file.h - Additional file attributes
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -15,13 +16,15 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
 #ifndef _FILE_H
 #define _FILE_H
 
+#include "msdos_fs.h"
+
 typedef enum { fdt_none, fdt_drop, fdt_undelete } FD_TYPE;
 
 typedef struct _fptr {
diff --git a/dosfstools/src/dosfsck.c b/dosfstools/src/fsck.fat.c
similarity index 75%
rename from dosfstools/src/dosfsck.c
rename to dosfstools/src/fsck.fat.c
index a7a59e1..2bc3dc2 100644
--- a/dosfstools/src/dosfsck.c
+++ b/dosfstools/src/fsck.fat.c
@@ -1,7 +1,8 @@
-/* dosfsck.c - User interface
+/* fsck.fat.c - User interface
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -16,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -33,7 +34,7 @@
 #include <getopt.h>
 
 #include "common.h"
-#include "dosfsck.h"
+#include "fsck.fat.h"
 #include "io.h"
 #include "boot.h"
 #include "fat.h"
@@ -41,40 +42,31 @@
 #include "check.h"
 
 int interactive = 0, rw = 0, list = 0, test = 0, verbose = 0, write_immed = 0;
-int atari_format = 0;
+int atari_format = 0, boot_only = 0;
 unsigned n_files = 0;
 void *mem_queue = NULL;
 
-#ifdef USE_ANDROID_RETVALS
-unsigned retandroid = 1;
-#else
-unsigned retandroid = 0;
-#endif
-
 static void usage(char *name)
 {
-    fprintf(stderr, "usage: %s [-aAflrtvVwy] [-d path -d ...] "
+    fprintf(stderr, "usage: %s [-aAbflrtvVwy] [-d path -d ...] "
 	    "[-u path -u ...]\n%15sdevice\n", name, "");
-    fprintf(stderr, "  -a       automatically repair the file system\n");
-    fprintf(stderr, "  -A       toggle Atari file system format\n");
+    fprintf(stderr, "  -a       automatically repair the filesystem\n");
+    fprintf(stderr, "  -A       toggle Atari filesystem format\n");
+    fprintf(stderr, "  -b       make read-only boot sector check\n");
     fprintf(stderr, "  -d path  drop that file\n");
-    fprintf(stderr, "  -f       ignored\n");
+    fprintf(stderr, "  -f       salvage unused chains to files\n");
     fprintf(stderr, "  -l       list path names\n");
     fprintf(stderr,
 	    "  -n       no-op, check non-interactively without changing\n");
     fprintf(stderr, "  -p       same as -a, for compat with other *fsck\n");
-    fprintf(stderr, "  -r       interactively repair the file system\n");
+    fprintf(stderr, "  -r       interactively repair the filesystem (default)\n");
     fprintf(stderr, "  -t       test for bad clusters\n");
     fprintf(stderr, "  -u path  try to undelete that (non-directory) file\n");
     fprintf(stderr, "  -v       verbose mode\n");
     fprintf(stderr, "  -V       perform a verification pass\n");
     fprintf(stderr, "  -w       write changes to disk immediately\n");
     fprintf(stderr, "  -y       same as -a, for compat with other *fsck\n");
-	if (retandroid) {
-		exit(1);
-	} else {
-    	exit(2);
-	}
+    exit(2);
 }
 
 /*
@@ -109,15 +101,14 @@
 {
     DOS_FS fs;
     int salvage_files, verify, c;
-    unsigned n_files_check = 0, n_files_verify = 0;
-    unsigned long free_clusters;
+    uint32_t free_clusters = 0;
 
     memset(&fs, 0, sizeof(fs));
-    rw = salvage_files = verify = 0;
-    interactive = 1;
+    salvage_files = verify = 0;
+    rw = interactive = 1;
     check_atari();
 
-    while ((c = getopt(argc, argv, "Aad:flnprtu:vVwy")) != EOF)
+    while ((c = getopt(argc, argv, "Aad:bflnprtu:vVwy")) != -1)
 	switch (c) {
 	case 'A':		/* toggle Atari format */
 	    atari_format = !atari_format;
@@ -129,6 +120,11 @@
 	    interactive = 0;
 	    salvage_files = 1;
 	    break;
+	case 'b':
+	    rw = 0;
+	    interactive = 0;
+	    boot_only = 1;
+	    break;
 	case 'd':
 	    file_add(optarg, fdt_drop);
 	    break;
@@ -154,7 +150,6 @@
 	    break;
 	case 'v':
 	    verbose = 1;
-	    printf("dosfsck " VERSION " (" VERSION_DATE ")\n");
 	    break;
 	case 'V':
 	    verify = 1;
@@ -166,33 +161,32 @@
 	    usage(argv[0]);
 	}
     if ((test || write_immed) && !rw) {
-	fprintf(stderr, "-t and -w require -a or -r\n");
-	if (retandroid) {
-		exit(1);
-	} else {
-		exit(2);
-	}
+	fprintf(stderr, "-t and -w can not be used in read only mode\n");
+	exit(2);
     }
     if (optind != argc - 1)
 	usage(argv[0]);
 
-    printf("dosfsck " VERSION ", " VERSION_DATE ", FAT32, LFN\n");
+    printf("fsck.fat " VERSION " (" VERSION_DATE ")\n");
     fs_open(argv[optind], rw);
+
     read_boot(&fs);
+    if (boot_only)
+	goto exit;
+
     if (verify)
 	printf("Starting check/repair pass.\n");
     while (read_fat(&fs), scan_root(&fs))
 	qfree(&mem_queue);
     if (test)
 	fix_bad(&fs);
-    if (salvage_files && 0)
+    if (salvage_files)
 	reclaim_file(&fs);
     else
 	reclaim_free(&fs);
     free_clusters = update_free(&fs);
     file_unused();
     qfree(&mem_queue);
-    n_files_check = n_files;
     if (verify) {
 	n_files = 0;
 	printf("Starting verification pass.\n");
@@ -200,9 +194,9 @@
 	scan_root(&fs);
 	reclaim_free(&fs);
 	qfree(&mem_queue);
-	n_files_verify = n_files;
     }
 
+exit:
     if (fs_changed()) {
 	if (rw) {
 	    if (interactive)
@@ -210,15 +204,12 @@
 	    else
 		printf("Performing changes.\n");
 	} else
-	    printf("Leaving file system unchanged.\n");
+	    printf("Leaving filesystem unchanged.\n");
     }
 
-    printf("%s: %u files, %lu/%lu clusters\n", argv[optind],
-	   n_files, fs.clusters - free_clusters, fs.clusters);
+    if (!boot_only)
+	printf("%s: %u files, %lu/%lu clusters\n", argv[optind],
+	       n_files, (unsigned long)fs.clusters - free_clusters, (unsigned long)fs.clusters);
 
-	if (retandroid) {
-		return fs_close(rw) ? 4 : 0;
-	} else {
-    	return fs_close(rw) ? 1 : 0;
-	}
+    return fs_close(rw) ? 1 : 0;
 }
diff --git a/dosfstools/src/fsck.fat.h b/dosfstools/src/fsck.fat.h
new file mode 100644
index 0000000..e5f6178
--- /dev/null
+++ b/dosfstools/src/fsck.fat.h
@@ -0,0 +1,191 @@
+/* fsck.fat.h  -  Common data structures and global variables
+
+   Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
+   Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
+
+   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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+   The complete text of the GNU General Public License
+   can be found in /usr/share/common-licenses/GPL-3 file.
+*/
+
+/* FAT32, VFAT, Atari format support, and various fixes additions May 1998
+ * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
+
+#ifndef _DOSFSCK_H
+#define _DOSFSCK_H
+
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <endian.h>
+
+#include "msdos_fs.h"
+
+#define VFAT_LN_ATTR (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME)
+
+#define FAT_STATE_DIRTY 0x01
+
+/* ++roman: Use own definition of boot sector structure -- the kernel headers'
+ * name for it is msdos_boot_sector in 2.0 and fat_boot_sector in 2.1 ... */
+struct boot_sector {
+    uint8_t ignored[3];		/* Boot strap short or near jump */
+    uint8_t system_id[8];	/* Name - can be used to special case
+				   partition manager volumes */
+    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) */
+
+    /* The following fields are only used by FAT32 */
+    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 */
+    uint8_t reserved2[12];	/* Unused */
+
+    uint8_t drive_number;	/* Logical Drive Number */
+    uint8_t reserved3;		/* Unused */
+
+    uint8_t extended_sig;	/* Extended Signature (0x29) */
+    uint32_t serial;		/* Serial number */
+    uint8_t label[11];		/* FS label */
+    uint8_t fs_type[8];		/* FS Type */
+
+    /* fill up to 512 bytes */
+    uint8_t junk[422];
+} __attribute__ ((packed));
+
+struct boot_sector_16 {
+    uint8_t ignored[3];		/* Boot strap short or near jump */
+    uint8_t system_id[8];	/* Name - can be used to special case
+				   partition manager volumes */
+    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) */
+
+    uint8_t drive_number;	/* Logical Drive Number */
+    uint8_t reserved2;		/* Unused */
+
+    uint8_t extended_sig;	/* Extended Signature (0x29) */
+    uint32_t serial;		/* Serial number */
+    uint8_t label[11];		/* FS label */
+    uint8_t fs_type[8];		/* FS Type */
+
+    /* fill up to 512 bytes */
+    uint8_t junk[450];
+} __attribute__ ((packed));
+
+struct info_sector {
+    uint32_t magic;		/* Magic for info sector ('RRaA') */
+    uint8_t junk[0x1dc];
+    uint32_t reserved1;		/* Nothing as far as I can tell */
+    uint32_t signature;		/* 0x61417272 ('rrAa') */
+    uint32_t free_clusters;	/* Free cluster count.  -1 if unknown */
+    uint32_t next_cluster;	/* Most recently allocated cluster. */
+    uint32_t reserved2[3];
+    uint16_t reserved3;
+    uint16_t boot_sign;
+};
+
+typedef struct {
+    uint8_t name[8], ext[3];	/* name and extension */
+    uint8_t attr;		/* attribute bits */
+    uint8_t lcase;		/* Case for base and extension */
+    uint8_t ctime_ms;		/* Creation time, milliseconds */
+    uint16_t ctime;		/* Creation time */
+    uint16_t cdate;		/* Creation date */
+    uint16_t adate;		/* Last access date */
+    uint16_t starthi;		/* High 16 bits of cluster in FAT32 */
+    uint16_t time, date, start;	/* time, date and first cluster */
+    uint32_t size;		/* file size (in bytes) */
+} __attribute__ ((packed)) DIR_ENT;
+
+typedef struct _dos_file {
+    DIR_ENT dir_ent;
+    char *lfn;
+    loff_t offset;
+    loff_t lfn_offset;
+    struct _dos_file *parent;	/* parent directory */
+    struct _dos_file *next;	/* next entry */
+    struct _dos_file *first;	/* first entry (directory only) */
+} DOS_FILE;
+
+typedef struct {
+    uint32_t value;
+    uint32_t reserved;
+} FAT_ENTRY;
+
+typedef struct {
+    int nfats;
+    loff_t fat_start;
+    unsigned int fat_size;	/* unit is bytes */
+    unsigned int fat_bits;	/* size of a FAT entry */
+    unsigned int eff_fat_bits;	/* # of used bits in a FAT entry */
+    uint32_t root_cluster;	/* 0 for old-style root dir */
+    loff_t root_start;
+    unsigned int root_entries;
+    loff_t data_start;
+    unsigned int cluster_size;
+    uint32_t clusters;
+    loff_t fsinfo_start;	/* 0 if not present */
+    long free_clusters;
+    loff_t backupboot_start;	/* 0 if not present */
+    unsigned char *fat;
+    DOS_FILE **cluster_owner;
+    char *label;
+} DOS_FS;
+
+extern int interactive, rw, list, verbose, test, write_immed;
+extern int atari_format;
+extern unsigned n_files;
+extern void *mem_queue;
+
+/* value to use as end-of-file marker */
+#define FAT_EOF(fs)	((atari_format ? 0xfff : 0xff8) | FAT_EXTD(fs))
+#define FAT_IS_EOF(fs,v) ((uint32_t)(v) >= (0xff8|FAT_EXTD(fs)))
+/* value to mark bad clusters */
+#define FAT_BAD(fs)	(0xff7 | FAT_EXTD(fs))
+/* range of values used for bad clusters */
+#define FAT_MIN_BAD(fs)	((atari_format ? 0xff0 : 0xff7) | FAT_EXTD(fs))
+#define FAT_MAX_BAD(fs)	((atari_format ? 0xff7 : 0xff7) | FAT_EXTD(fs))
+#define FAT_IS_BAD(fs,v) ((v) >= FAT_MIN_BAD(fs) && (v) <= FAT_MAX_BAD(fs))
+
+/* return -16 as a number with fs->fat_bits bits */
+#define FAT_EXTD(fs)	(((1 << fs->eff_fat_bits)-1) & ~0xf)
+
+/* marker for files with no 8.3 name */
+#define FAT_NO_83NAME 32
+
+#endif
diff --git a/dosfstools/src/io.c b/dosfstools/src/io.c
index a703c2d..450432c 100644
--- a/dosfstools/src/io.c
+++ b/dosfstools/src/io.c
@@ -2,6 +2,7 @@
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -16,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -30,7 +31,6 @@
  * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
 
 #define _LARGEFILE64_SOURCE
-#include <sys/types.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -41,7 +41,7 @@
 #include <fcntl.h>
 #include <linux/fd.h>
 
-#include "dosfsck.h"
+#include "fsck.fat.h"
 #include "common.h"
 #include "io.h"
 
@@ -132,9 +132,11 @@
 	if (walk->pos < pos + size && walk->pos + walk->size > pos) {
 	    if (walk->pos < pos)
 		memcpy(data, (char *)walk->data + pos - walk->pos, min(size,
-								       walk->size
-								       - pos +
-								       walk->pos));
+								       walk->
+								       size -
+								       pos +
+								       walk->
+								       pos));
 	    else
 		memcpy((char *)data + walk->pos - pos, walk->data,
 		       min(walk->size, size + pos - walk->pos));
@@ -220,7 +222,7 @@
 	    changes = next;
 	}
     if (close(fd) < 0)
-	pdie("closing file system");
+	pdie("closing filesystem");
     return changed || did_change;
 }
 
diff --git a/dosfstools/src/io.h b/dosfstools/src/io.h
index 2db4ea7..d23d07e 100644
--- a/dosfstools/src/io.h
+++ b/dosfstools/src/io.h
@@ -2,6 +2,7 @@
 
    Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -16,7 +17,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -26,7 +27,7 @@
 #ifndef _IO_H
 #define _IO_H
 
-#include <sys/types.h>		/* for loff_t */
+#include <fcntl.h>		/* for loff_t */
 
 loff_t llseek(int fd, loff_t offset, int whence);
 
@@ -34,7 +35,7 @@
 
 void fs_open(char *path, int rw);
 
-/* Opens the file system PATH. If RW is zero, the file system is opened
+/* Opens the filesystem PATH. If RW is zero, the filesystem is opened
    read-only, otherwise, it is opened read-write. */
 
 void fs_read(loff_t pos, int size, void *data);
@@ -55,13 +56,13 @@
 
 int fs_close(int write);
 
-/* Closes the file system, performs all pending changes if WRITE is non-zero
+/* Closes the filesystem, performs all pending changes if WRITE is non-zero
    and removes the list of changes. Returns a non-zero integer if the file
    system has been changed since the last fs_open, zero otherwise. */
 
 int fs_changed(void);
 
-/* Determines whether the file system has changed. See fs_close. */
+/* Determines whether the filesystem has changed. See fs_close. */
 
 extern unsigned device_no;
 
diff --git a/dosfstools/src/lfn.c b/dosfstools/src/lfn.c
index 736491c..2601172 100644
--- a/dosfstools/src/lfn.c
+++ b/dosfstools/src/lfn.c
@@ -1,6 +1,7 @@
 /* lfn.c - Functions for handling VFAT long filenames
 
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -15,11 +16,12 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
 #include <stdio.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>
@@ -27,19 +29,19 @@
 
 #include "common.h"
 #include "io.h"
-#include "dosfsck.h"
+#include "fsck.fat.h"
 #include "lfn.h"
 #include "file.h"
 
 typedef struct {
-    __u8 id;			/* sequence number for slot */
-    __u8 name0_4[10];		/* first 5 characters in name */
-    __u8 attr;			/* attribute byte */
-    __u8 reserved;		/* always 0 */
-    __u8 alias_checksum;	/* checksum for 8.3 alias */
-    __u8 name5_10[12];		/* 6 more characters in name */
-    __u16 start;		/* starting cluster number, 0 in long slots */
-    __u8 name11_12[4];		/* last 2 characters in name */
+    uint8_t id;			/* sequence number for slot */
+    uint8_t name0_4[10];	/* first 5 characters in name */
+    uint8_t attr;		/* attribute byte */
+    uint8_t reserved;		/* always 0 */
+    uint8_t alias_checksum;	/* checksum for 8.3 alias */
+    uint8_t name5_10[12];	/* 6 more characters in name */
+    uint16_t start;		/* starting cluster number, 0 in long slots */
+    uint8_t name11_12[4];	/* last 2 characters in name */
 } LFN_ENT;
 
 #define LFN_ID_START	0x40
@@ -85,6 +87,22 @@
 	(cnv_unicode( lfn_unicode+(lfn_slot*CHARS_PER_LFN*2),	\
 		      lfn_parts*CHARS_PER_LFN, 0 ))
 
+#define BYTES_TO_WCHAR(cl,ch) ((wchar_t)((unsigned)(cl) + ((unsigned)(ch) << 8)))
+static size_t mbslen(wchar_t x)
+{
+    wchar_t wstr[] = { x, 0 };
+    return wcstombs(NULL, wstr, 0);
+}
+
+static size_t wctombs(char *dest, wchar_t x)
+{
+    wchar_t wstr[] = { x, 0 };
+    size_t size = wcstombs(NULL, wstr, 0);
+    if (size != (size_t) - 1)
+	size = wcstombs(dest, wstr, size + 1);
+    return size;
+}
+
 /* This function converts an unicode string to a normal ASCII string, assuming
  * ISO-8859-1 charset. Characters not in 8859-1 are converted to the same
  * escape notation as used by the kernel, i.e. the uuencode-like ":xxx" */
@@ -93,10 +111,13 @@
     const unsigned char *up;
     unsigned char *out, *cp;
     int len, val;
+    size_t x;
 
     for (len = 0, up = uni; (up - uni) / 2 < maxlen && (up[0] || up[1]);
 	 up += 2) {
-	if (UNICODE_CONVERTABLE(up[0], up[1]))
+	if ((x = mbslen(BYTES_TO_WCHAR(up[0], up[1]))) != (size_t) - 1)
+	    len += x;
+	else if (UNICODE_CONVERTABLE(up[0], up[1]))
 	    ++len;
 	else
 	    len += 4;
@@ -104,7 +125,10 @@
     cp = out = use_q ? qalloc(&mem_queue, len + 1) : alloc(len + 1);
 
     for (up = uni; (up - uni) / 2 < maxlen && (up[0] || up[1]); up += 2) {
-	if (UNICODE_CONVERTABLE(up[0], up[1]))
+	if ((x =
+	     wctombs((char *)cp, BYTES_TO_WCHAR(up[0], up[1]))) != (size_t) - 1)
+	    cp += x;
+	else if (UNICODE_CONVERTABLE(up[0], up[1]))
 	    *cp++ = up[0];
 	else {
 	    /* here the same escape notation is used as in the Linux kernel */
@@ -150,7 +174,7 @@
 void lfn_fix_checksum(loff_t from, loff_t to, const char *short_name)
 {
     int i;
-    __u8 sum;
+    uint8_t sum;
     for (sum = 0, i = 0; i < 11; i++)
 	sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + short_name[i];
 
@@ -366,7 +390,7 @@
 		     sizeof(lfn->reserved), &lfn->reserved);
 	}
     }
-    if (lfn->start != CT_LE_W(0)) {
+    if (lfn->start != htole16(0)) {
 	printf("Start cluster field in VFAT long filename slot is not 0 "
 	       "(but 0x%04x).\n", lfn->start);
 	if (interactive)
@@ -374,7 +398,7 @@
 	else
 	    printf("Auto-setting to 0.\n");
 	if (!interactive || get_key("12", "?") == '1') {
-	    lfn->start = CT_LE_W(0);
+	    lfn->start = htole16(0);
 	    fs_write(dir_offset + offsetof(LFN_ENT, start),
 		     sizeof(lfn->start), &lfn->start);
 	}
@@ -386,7 +410,7 @@
 char *lfn_get(DIR_ENT * de, loff_t * lfn_offset)
 {
     char *lfn;
-    __u8 sum;
+    uint8_t sum;
     int i;
 
     *lfn_offset = 0;
@@ -430,7 +454,7 @@
 	    return NULL;
 	case '3':
 	    for (i = 0; i < lfn_parts; ++i) {
-		__u8 id = (lfn_parts - i) | (i == 0 ? LFN_ID_START : 0);
+		uint8_t id = (lfn_parts - i) | (i == 0 ? LFN_ID_START : 0);
 		fs_write(lfn_offsets[i] + offsetof(LFN_ENT, id),
 			 sizeof(id), &id);
 	    }
@@ -440,8 +464,10 @@
 	}
     }
 
-    for (sum = 0, i = 0; i < 11; i++)
+    for (sum = 0, i = 0; i < 8; i++)
 	sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->name[i];
+    for (i = 0; i < 3; i++)
+	sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + de->ext[i];
     if (sum != lfn_checksum) {
 	/* checksum doesn't match, long name doesn't apply to this alias */
 	/* Causes: 1) alias renamed */
diff --git a/dosfstools/src/lfn.h b/dosfstools/src/lfn.h
index 2ea44a7..e5c3991 100644
--- a/dosfstools/src/lfn.h
+++ b/dosfstools/src/lfn.h
@@ -1,6 +1,7 @@
 /* lfn.h - Functions for handling VFAT long filenames
 
    Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -15,7 +16,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
diff --git a/dosfstools/src/mkdosfs.c b/dosfstools/src/mkfs.fat.c
similarity index 82%
rename from dosfstools/src/mkdosfs.c
rename to dosfstools/src/mkfs.fat.c
index 9873bef..dddbe24 100644
--- a/dosfstools/src/mkdosfs.c
+++ b/dosfstools/src/mkfs.fat.c
@@ -1,10 +1,11 @@
-/* mkdosfs.c - utility to create FAT/MS-DOS filesystems
+/* mkfs.fat.c - utility to create FAT/MS-DOS filesystems
 
    Copyright (C) 1991 Linus Torvalds <torvalds@klaava.helsinki.fi>
    Copyright (C) 1992-1993 Remy Card <card@masi.ibp.fr>
    Copyright (C) 1993-1994 David Hudson <dave@humbug.demon.co.uk>
    Copyright (C) 1998 H. Peter Anvin <hpa@zytor.com>
    Copyright (C) 1998-2005 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -19,7 +20,7 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
@@ -27,7 +28,7 @@
    under Linux.  A lot of the basic structure of this program has been
    borrowed from Remy Card's "mke2fs" code.
 
-   As far as possible the aim here is to make the "mkdosfs" command
+   As far as possible the aim here is to make the "mkfs.fat" command
    look almost identical to the other Linux filesystem make utilties,
    eg bad blocks are still specified as blocks, not sectors, but when
    it comes down to it, DOS is tied to the idea of a sector (512 bytes
@@ -47,11 +48,8 @@
 
 #include <fcntl.h>
 #include <linux/hdreg.h>
-#if defined(_USING_BIONIC_)
-#include <linux/fs.h>
-#else
 #include <sys/mount.h>
-#endif
+#include <linux/fs.h>
 #include <linux/fd.h>
 #include <endian.h>
 #include <mntent.h>
@@ -62,43 +60,19 @@
 #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>
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-
-#include <asm/byteorder.h>
-#ifdef __le16_to_cpu
-/* ++roman: 2.1 kernel headers define these function, they're probably more
- * efficient then coding the swaps machine-independently. */
-#define CF_LE_W	__le16_to_cpu
-#define CF_LE_L	__le32_to_cpu
-#define CT_LE_W	__cpu_to_le16
-#define CT_LE_L	__cpu_to_le32
-#else
-#define CF_LE_W(v) ((((v) & 0xff) << 8) | (((v) >> 8) & 0xff))
-#define CF_LE_L(v) (((unsigned)(v)>>24) | (((unsigned)(v)>>8)&0xff00) | \
-               (((unsigned)(v)<<8)&0xff0000) | ((unsigned)(v)<<24))
-#define CT_LE_W(v) CF_LE_W(v)
-#define CT_LE_L(v) CF_LE_L(v)
-#endif /* defined(__le16_to_cpu) */
-
-#else
-
-#define CF_LE_W(v) (v)
-#define CF_LE_L(v) (v)
-#define CT_LE_W(v) (v)
-#define CT_LE_L(v) (v)
-
-#endif /* __BIG_ENDIAN */
+#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 */
-#define llseek lseek64
+#define llseek lseek
 
 /* Constant definitions */
 
@@ -109,6 +83,8 @@
 #define HARD_SECTOR_SIZE   512
 #define SECTORS_PER_BLOCK ( BLOCK_SIZE / HARD_SECTOR_SIZE )
 
+#define NO_NAME "NO NAME    "
+
 /* Macro definitions */
 
 /* Report a failure message and return a failure error code */
@@ -121,26 +97,11 @@
 
 /* Compute ceil(a/b) */
 
-inline int cdiv(int a, int b)
+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
@@ -172,80 +133,67 @@
  * 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 */
@@ -274,16 +222,15 @@
 
 /* Global variables - the root of all evil :-) - see these and weep! */
 
-static char *program_name = "mkdosfs";	/* 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[] = "           ";	/* Volume name */
-static unsigned long long blocks;	/* Number of blocks in filesystem */
+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 */
 static int sector_size_set = 0;	/* User selected sector size */
 static int backup_boot = 0;	/* Sector# of backup boot sector */
@@ -307,9 +254,16 @@
 static int root_dir_entries = 0;	/* Number of root directory entries */
 static char *blank_sector;	/* Blank sector - all zeros */
 static int hidden_sectors = 0;	/* Number of hidden sectors */
+static int hidden_sectors_by_user = 0;	/* -h option invoked */
+static int drive_number_option = 0;	/* drive number */
+static int drive_number_by_user = 0;	/* drive number option invoked */
+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 */
 
@@ -321,7 +275,7 @@
 static void check_blocks(void);
 static void get_list_blocks(char *filename);
 static int valid_offset(int fd, loff_t offset);
-static unsigned long long count_blocks(char *filename, int *remainder);
+static uint64_t count_blocks(char *filename, int *remainder);
 static void check_mount(char *device_name);
 static void establish_params(int device_num, int size);
 static void setup_tables(void);
@@ -416,6 +370,8 @@
 
 static void alarm_intr(int alnum)
 {
+    (void)alnum;
+
     if (currently_testing >= blocks)
 	return;
 
@@ -474,7 +430,7 @@
 {
     int i;
     FILE *listfile;
-    unsigned long blockno;
+    long blockno;
 
     listfile = fopen(filename, "r");
     if (listfile == (FILE *) NULL)
@@ -508,8 +464,7 @@
 
 /* Given a filename, look to see how many blocks of BLOCK_SIZE are present, returning the answer */
 
-static unsigned long long count_blocks(char *filename, int *remainder)
-
+static uint64_t count_blocks(char *filename, int *remainder)
 {
     loff_t high, low;
     int fd;
@@ -535,15 +490,14 @@
     }
 
     close(fd);
-    *remainder = (low%BLOCK_SIZE)/sector_size;
-    return(low / BLOCK_SIZE);
+    *remainder = (low % BLOCK_SIZE) / sector_size;
+    return (low / BLOCK_SIZE);
 }
 
 /* Check to see if the specified device is currently mounted - abort if it is */
 
 static void check_mount(char *device_name)
 {
-#if ! defined(_USING_BIONIC_)
     FILE *f;
     struct mntent *mnt;
 
@@ -551,9 +505,8 @@
 	return;
     while ((mnt = getmntent(f)) != NULL)
 	if (strcmp(device_name, mnt->mnt_fsname) == 0)
-	    die("%s contains a mounted file system.");
+	    die("%s contains a mounted filesystem.");
     endmntent(f);
-#endif
 }
 
 /* Establish the geometry and media parameters for the device */
@@ -603,8 +556,8 @@
 	    if (ioctl(dev, FDGETPRM, &param))	/*  Can we get the diskette geometry? */
 		die("unable to get diskette geometry for '%s'");
 	}
-	bs.secs_track = CT_LE_W(param.sect);	/*  Set up the geometry information */
-	bs.heads = CT_LE_W(param.head);
+	bs.secs_track = htole16(param.sect);	/*  Set up the geometry information */
+	bs.heads = htole16(param.head);
 	switch (param.size) {	/*  Set up the media descriptor byte */
 	case 720:		/* 5.25", 2, 9, 40 - 360K */
 	    bs.media = (char)0xfd;
@@ -649,32 +602,32 @@
 
 	switch (loop_size) {	/* Assuming the loop device -> floppy later */
 	case 720:		/* 5.25", 2, 9, 40 - 360K */
-	    bs.secs_track = CF_LE_W(9);
-	    bs.heads = CF_LE_W(2);
+	    bs.secs_track = le16toh(9);
+	    bs.heads = le16toh(2);
 	    bs.media = (char)0xfd;
 	    bs.cluster_size = (char)2;
 	    def_root_dir_entries = 112;
 	    break;
 
 	case 1440:		/* 3.5", 2, 9, 80 - 720K */
-	    bs.secs_track = CF_LE_W(9);
-	    bs.heads = CF_LE_W(2);
+	    bs.secs_track = le16toh(9);
+	    bs.heads = le16toh(2);
 	    bs.media = (char)0xf9;
 	    bs.cluster_size = (char)2;
 	    def_root_dir_entries = 112;
 	    break;
 
 	case 2400:		/* 5.25", 2, 15, 80 - 1200K */
-	    bs.secs_track = CF_LE_W(15);
-	    bs.heads = CF_LE_W(2);
+	    bs.secs_track = le16toh(15);
+	    bs.heads = le16toh(2);
 	    bs.media = (char)0xf9;
 	    bs.cluster_size = (char)(atari_format ? 2 : 1);
 	    def_root_dir_entries = 224;
 	    break;
 
 	case 5760:		/* 3.5", 2, 36, 80 - 2880K */
-	    bs.secs_track = CF_LE_W(36);
-	    bs.heads = CF_LE_W(2);
+	    bs.secs_track = le16toh(36);
+	    bs.heads = le16toh(2);
 	    bs.media = (char)0xf0;
 	    bs.cluster_size = (char)2;
 	    bs.dir_entries[0] = (char)224;
@@ -682,8 +635,8 @@
 	    break;
 
 	case 2880:		/* 3.5", 2, 18, 80 - 1440K */
-	    bs.secs_track = CF_LE_W(18);
-	    bs.heads = CF_LE_W(2);
+	    bs.secs_track = le16toh(18);
+	    bs.heads = le16toh(2);
 	    bs.media = (char)0xf0;
 	    bs.cluster_size = (char)(atari_format ? 2 : 1);
 	    def_root_dir_entries = 224;
@@ -692,8 +645,8 @@
 	default:		/* Anything else: default hd setup */
 	    printf("Loop device does not match a floppy size, using "
 		   "default hd params\n");
-	    bs.secs_track = CT_LE_W(32);	/* these are fake values... */
-	    bs.heads = CT_LE_W(64);
+	    bs.secs_track = htole16(32);	/* these are fake values... */
+	    bs.heads = htole16(64);
 	    goto def_hd_params;
 	}
     } else
@@ -704,11 +657,13 @@
 	if (ioctl(dev, HDIO_GETGEO, &geometry) || geometry.sectors == 0
 	    || geometry.heads == 0) {
 	    printf("unable to get drive geometry, using default 255/63\n");
-	    bs.secs_track = CT_LE_W(63);
-	    bs.heads = CT_LE_W(255);
+	    bs.secs_track = htole16(63);
+	    bs.heads = htole16(255);
 	} else {
-	    bs.secs_track = CT_LE_W(geometry.sectors);	/* Set up the geometry information */
-	    bs.heads = CT_LE_W(geometry.heads);
+	    bs.secs_track = htole16(geometry.sectors);	/* Set up the geometry information */
+	    bs.heads = htole16(geometry.heads);
+	    if (!hidden_sectors_by_user)
+		hidden_sectors = htole32(geometry.start);
 	}
 def_hd_params:
 	bs.media = (char)0xf8;	/* Set up the media descriptor for a hard drive */
@@ -721,16 +676,17 @@
 	    /* For FAT32, try to do the same as M$'s format command
 	     * (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 >   16G: 16k clusters
+	     * fs size <=   8G:   4k clusters
+	     * fs size <=  16G:   8k clusters
+	     * fs size <=  32G:  16k clusters
+	     * fs size >   32G:  32k clusters
 	     */
-	    unsigned long sz_mb =
+	    uint32_t sz_mb =
 		(blocks + (1 << (20 - BLOCK_SIZE_BITS)) - 1) >> (20 -
 								 BLOCK_SIZE_BITS);
 	    bs.cluster_size =
-		sz_mb > 16 * 1024 ? 32 : sz_mb > 8 * 1024 ? 16 : sz_mb >
-		260 ? 8 : 1;
+		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 */
 	    bs.cluster_size = (char)4;
@@ -763,15 +719,28 @@
     struct msdos_volume_info *vi =
 	(size_fat == 32 ? &bs.fat32.vi : &bs.oldfat.vi);
 
-    if (atari_format)
+    if (atari_format) {
 	/* On Atari, the first few bytes of the boot sector are assigned
 	 * differently: The jump code is only 2 bytes (and m68k machine code
 	 * :-), then 6 bytes filler (ignored), then 3 byte serial number. */
-	memcpy(bs.system_id - 1, "mkdosf", 6);
-    else
-	strcpy((char *)bs.system_id, "mkdosfs");
+	bs.boot_jump[2] = 'm';
+	memcpy((char *)bs.system_id, "kdosf", strlen("kdosf"));
+    } else
+	memcpy((char *)bs.system_id, "mkfs.fat", strlen("mkfs.fat"));
     if (sectors_per_cluster)
 	bs.cluster_size = (char)sectors_per_cluster;
+
+    if (fat_media_byte)
+	bs.media = (char) fat_media_byte;
+
+    if (bs.media == 0xf8)
+	vi->drive_number=0x80;
+    else
+	vi->drive_number=0x00;
+
+    if (drive_number_by_user)
+	vi->drive_number= (char) drive_number_option;
+
     if (size_fat == 32) {
 	/* Under FAT32, the root dir is in a cluster chain, and this is
 	 * signalled by bs.dir_entries being 0. */
@@ -810,7 +779,7 @@
 	} else {
 	    memcpy(bs.oldfat.boot_code, dummy_boot_code, BOOTCODE_SIZE);
 	}
-	bs.boot_sign = CT_LE_W(BOOT_SIGN);
+	bs.boot_sign = htole16(BOOT_SIGN);
     } else {
 	memcpy(bs.boot_jump, dummy_boot_jump_m68k, 2);
     }
@@ -824,21 +793,22 @@
 	if (size_fat == 32 && reserved_sectors < 2)
 	    die("On FAT32 at least 2 reserved sectors are needed.");
     }
-    bs.reserved = CT_LE_W(reserved_sectors);
+    bs.reserved = htole16(reserved_sectors);
     if (verbose >= 2)
 	printf("Using %d reserved sectors\n", reserved_sectors);
     bs.fats = (char)nr_fats;
     if (!atari_format || size_fat == 32)
-	bs.hidden = CT_LE_L(hidden_sectors);
+	bs.hidden = htole32(hidden_sectors);
     else {
 	/* In Atari format, hidden is a 16 bit field */
-	__u16 hidden = CT_LE_W(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);
     }
 
-    num_sectors = (long long)(blocks *BLOCK_SIZE / sector_size)+orphaned_sectors;
+    num_sectors =
+	(long long)(blocks * BLOCK_SIZE / sector_size) + orphaned_sectors;
 
     if (!atari_format) {
 	unsigned fatdata1216;	/* Sectors for FATs + data area (FAT12/16) */
@@ -867,8 +837,7 @@
 	    maxclustsize = 128;
 
 	do {
-	    fatdata32 = num_sectors
-		- align_object(reserved_sectors, bs.cluster_size);
+	    fatdata32 = num_sectors - reserved_sectors;
 	    fatdata1216 = fatdata32
 		- align_object(root_dir_sectors, bs.cluster_size);
 
@@ -930,7 +899,6 @@
 	    clust32 = ((long long)fatdata32 * sector_size + nr_fats * 8) /
 		((int)bs.cluster_size * sector_size + nr_fats * 4);
 	    fatlength32 = cdiv((clust32 + 2) * 4, sector_size);
-	    fatlength32 = align_object(fatlength32, bs.cluster_size);
 	    /* Need to recalculate number of clusters, since the unused parts of the
 	     * FATS and data area together could make up space for an additional,
 	     * not really present cluster. */
@@ -973,7 +941,7 @@
 	case 12:
 	    cluster_count = clust12;
 	    fat_length = fatlength12;
-	    bs.fat_length = CT_LE_W(fatlength12);
+	    bs.fat_length = htole16(fatlength12);
 	    memcpy(vi->fs_type, MSDOS_FAT12_SIGN, 8);
 	    break;
 
@@ -992,12 +960,12 @@
 			    "the total number of clusters becomes less than the "
 			    "threshold value for\n"
 			    "distinction between 12 and 16 bit FATs.\n");
-		    die("Make the file system a bit smaller manually.");
+		    die("Make the filesystem a bit smaller manually.");
 		}
 	    }
 	    cluster_count = clust16;
 	    fat_length = fatlength16;
-	    bs.fat_length = CT_LE_W(fatlength16);
+	    bs.fat_length = htole16(fatlength16);
 	    memcpy(vi->fs_type, MSDOS_FAT16_SIGN, 8);
 	    break;
 
@@ -1007,8 +975,8 @@
 			"WARNING: Not enough clusters for a 32 bit FAT!\n");
 	    cluster_count = clust32;
 	    fat_length = fatlength32;
-	    bs.fat_length = CT_LE_W(0);
-	    bs.fat32.fat32_length = CT_LE_L(fatlength32);
+	    bs.fat_length = htole16(0);
+	    bs.fat32.fat32_length = htole32(fatlength32);
 	    memcpy(vi->fs_type, MSDOS_FAT32_SIGN, 8);
 	    root_dir_entries = 0;
 	    break;
@@ -1017,10 +985,6 @@
 	    die("FAT not 12, 16 or 32 bits");
 	}
 
-	/* Adjust the reserved number of sectors for alignment */
-	reserved_sectors = align_object(reserved_sectors, bs.cluster_size);
-	bs.reserved = CT_LE_W(reserved_sectors);
-
 	/* Adjust the number of root directory entries to help enforce alignment */
 	if (align_structures) {
 	    root_dir_entries = align_object(root_dir_sectors, bs.cluster_size)
@@ -1030,7 +994,7 @@
 	unsigned clusters, maxclust, fatdata;
 
 	/* GEMDOS always uses a 12 bit FAT on floppies, and always a 16 bit FAT on
-	 * hard disks. So use 12 bit if the size of the file system suggests that
+	 * hard disks. So use 12 bit if the size of the filesystem suggests that
 	 * this fs is for a floppy disk, if the user hasn't explicitly requested a
 	 * size.
 	 */
@@ -1102,10 +1066,10 @@
 
 	cluster_count = clusters;
 	if (size_fat != 32)
-	    bs.fat_length = CT_LE_W(fat_length);
+	    bs.fat_length = htole16(fat_length);
 	else {
 	    bs.fat_length = 0;
-	    bs.fat32.fat32_length = CT_LE_L(fat_length);
+	    bs.fat32.fat32_length = htole32(fat_length);
 	}
     }
 
@@ -1117,11 +1081,11 @@
 
     if (size_fat == 32) {
 	/* set up additional FAT32 fields */
-	bs.fat32.flags = CT_LE_W(0);
+	bs.fat32.flags = htole16(0);
 	bs.fat32.version[0] = 0;
 	bs.fat32.version[1] = 0;
-	bs.fat32.root_cluster = CT_LE_L(2);
-	bs.fat32.info_sector = CT_LE_W(1);
+	bs.fat32.root_cluster = htole32(2);
+	bs.fat32.info_sector = htole16(1);
 	if (!backup_boot)
 	    backup_boot = (reserved_sectors >= 7) ? 6 :
 		(reserved_sectors >= 2) ? reserved_sectors - 1 : 0;
@@ -1134,7 +1098,7 @@
 	if (verbose >= 2)
 	    printf("Using sector %d as backup boot sector (0 = none)\n",
 		   backup_boot);
-	bs.fat32.backup_boot = CT_LE_W(backup_boot);
+	bs.fat32.backup_boot = htole16(backup_boot);
 	memset(&bs.fat32.reserved2, 0, sizeof(bs.fat32.reserved2));
     }
 
@@ -1149,12 +1113,12 @@
     if (num_sectors >= 65536) {
 	bs.sectors[0] = (char)0;
 	bs.sectors[1] = (char)0;
-	bs.total_sect = CT_LE_L(num_sectors);
+	bs.total_sect = htole32(num_sectors);
     } else {
 	bs.sectors[0] = (char)(num_sectors & 0x00ff);
 	bs.sectors[1] = (char)((num_sectors & 0xff00) >> 8);
 	if (!atari_format)
-	    bs.total_sect = CT_LE_L(0);
+	    bs.total_sect = htole32(0);
     }
 
     if (!atari_format)
@@ -1162,9 +1126,9 @@
 
     if (!cluster_count) {
 	if (sectors_per_cluster)	/* If yes, die if we'd spec'd sectors per cluster */
-	    die("Too many clusters for file system - try more sectors per cluster");
+	    die("Too many clusters for filesystem - try more sectors per cluster");
 	else
-	    die("Attempting to create a too large file system");
+	    die("Attempting to create a too large filesystem");
     }
 
     /* The two following vars are in hard sectors, i.e. 512 byte sectors! */
@@ -1173,18 +1137,20 @@
     start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) /
 	SECTORS_PER_BLOCK;
 
-    if (blocks < start_data_block + 32)	/* Arbitrary undersize file system! */
-	die("Too few blocks for viable file system");
+    if (blocks < start_data_block + 32)	/* Arbitrary undersize filesystem! */
+	die("Too few blocks for viable filesystem");
 
     if (verbose) {
 	printf("%s has %d head%s and %d sector%s per track,\n",
-	       device_name, CF_LE_W(bs.heads),
-	       (CF_LE_W(bs.heads) != 1) ? "s" : "", CF_LE_W(bs.secs_track),
-	       (CF_LE_W(bs.secs_track) != 1) ? "s" : "");
+	       device_name, le16toh(bs.heads),
+	       (le16toh(bs.heads) != 1) ? "s" : "", le16toh(bs.secs_track),
+	       (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("file system has %d %d-bit FAT%s and %d sector%s per cluster.\n",
+	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" : "",
 	       (int)(bs.cluster_size), (bs.cluster_size != 1) ? "s" : "");
 	printf("FAT size is %d sector%s, and provides %d cluster%s.\n",
@@ -1204,7 +1170,7 @@
 	}
 	printf("Volume ID is %08lx, ", volume_id &
 	       (atari_format ? 0x00ffffff : 0xffffffff));
-	if (strcmp(volume_name, "           "))
+	if (strcmp(volume_name, NO_NAME))
 	    printf("volume label %s.\n", volume_name);
 	else
 	    printf("no volume label.\n");
@@ -1243,26 +1209,29 @@
     }
 
     memset(root_dir, 0, size_root_dir);
-    if (memcmp(volume_name, "           ", 11)) {
+    if (memcmp(volume_name, NO_NAME, 11)) {
 	struct msdos_dir_entry *de = &root_dir[0];
 	memcpy(de->name, volume_name, 8);
 	memcpy(de->ext, volume_name + 8, 3);
 	de->attr = ATTR_VOLUME;
-	ctime = localtime(&create_time);
-	de->time = CT_LE_W((unsigned short)((ctime->tm_sec >> 1) +
+	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)));
 	de->date =
-	    CT_LE_W((unsigned short)(ctime->tm_mday +
+	    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;
-	de->starthi = CT_LE_W(0);
-	de->start = CT_LE_W(0);
-	de->size = CT_LE_L(0);
+	de->starthi = htole16(0);
+	de->start = htole16(0);
+	de->size = htole32(0);
     }
 
     if (size_fat == 32) {
@@ -1282,13 +1251,13 @@
 	info_sector[3] = 'A';
 
 	/* Magic for fsinfo structure */
-	info->signature = CT_LE_L(0x61417272);
+	info->signature = htole32(0x61417272);
 	/* We've allocated cluster 2 for the root dir. */
-	info->free_clusters = CT_LE_L(cluster_count - 1);
-	info->next_cluster = CT_LE_L(2);
+	info->free_clusters = htole32(cluster_count - 1);
+	info->next_cluster = htole32(2);
 
 	/* Info sector also must have boot sign */
-	*(__u16 *) (info_sector + 0x1fe) = CT_LE_W(BOOT_SIGN);
+	*(uint16_t *) (info_sector + 0x1fe) = htole16(BOOT_SIGN);
     }
 
     if (!(blank_sector = malloc(sector_size)))
@@ -1326,7 +1295,7 @@
     int fat_length;
 
     fat_length = (size_fat == 32) ?
-	CF_LE_L(bs.fat32.fat32_length) : CF_LE_W(bs.fat_length);
+	le32toh(bs.fat32.fat32_length) : le16toh(bs.fat_length);
 
     seekto(0, "start of device");
     /* clear all reserved sectors */
@@ -1337,7 +1306,7 @@
     writebuf((char *)&bs, sizeof(struct msdos_boot_sector), "boot sector");
     /* on FAT32, write the info sector and backup boot sector */
     if (size_fat == 32) {
-	seekto(CF_LE_W(bs.fat32.info_sector) * sector_size, "info sector");
+	seekto(le16toh(bs.fat32.info_sector) * sector_size, "info sector");
 	writebuf(info_sector, 512, "info sector");
 	if (backup_boot != 0) {
 	    seekto(backup_boot * sector_size, "backup boot sector");
@@ -1366,16 +1335,20 @@
     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 */
 
-void usage(void)
+static void usage(int exitval)
 {
-    fatal_error("\
-Usage: mkdosfs [-a][-A][-c][-C][-v][-I][-l bad-block-file][-b backup-boot-sector]\n\
+    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);
 }
 
 /*
@@ -1418,8 +1391,17 @@
     struct stat statbuf;
     int i = 0, pos, ch;
     int create = 0;
-    unsigned long long cblocks = 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;
@@ -1430,12 +1412,13 @@
 
     gettimeofday(&create_timeval, NULL);
     create_time = create_timeval.tv_sec;
-    volume_id = (u_int32_t) ((create_timeval.tv_sec << 20) | create_timeval.tv_usec);	/* Default volume ID = creation time, fudged for more uniqueness */
+    volume_id = (uint32_t) ((create_timeval.tv_sec << 20) | create_timeval.tv_usec);	/* Default volume ID = creation time, fudged for more uniqueness */
     check_atari();
 
-    printf("%s " VERSION " (" VERSION_DATE ")\n", program_name);
+    printf("mkfs.fat " VERSION " (" VERSION_DATE ")\n");
 
-    while ((c = getopt(argc, argv, "aAb:cCf:F:Ii:l: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 */
@@ -1450,7 +1433,7 @@
 	    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;
 
@@ -1463,11 +1446,20 @@
 	    create = TRUE;
 	    break;
 
+	case 'D':		/* D : Choose Drive Number */
+	    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(1);
+	    }
+	    drive_number_by_user=1;
+	    break;
+
 	case 'f':		/* f : Choose number of FATs */
 	    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;
 
@@ -1475,7 +1467,7 @@
 	    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;
@@ -1484,8 +1476,9 @@
 	    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;
 
 	case 'I':
@@ -1496,7 +1489,7 @@
 	    volume_id = strtoul(optarg, &tmp, 16);
 	    if (*tmp) {
 		printf("Volume ID must be a hexadecimal number\n");
-		usage();
+		usage(1);
 	    }
 	    break;
 
@@ -1565,15 +1558,35 @@
 	    }
 	    break;
 
+	case 'M':		/* M : FAT Media byte */
+	    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;
+
 	case 'n':		/* n : Volume name */
 	    sprintf(volume_name, "%-11.11s", optarg);
+	    for (i = 0; volume_name[i] && i < 11; i++)
+		/* don't know if here should be more strict !uppercase(label[i]) */
+		if (islower(volume_name[i])) {
+		    fprintf(stderr,
+		            "mkfs.fat: warning - lowercase labels might not work properly with DOS or Windows\n");
+		    break;
+		}
+
 	    break;
 
 	case 'r':		/* r : Root directory entries */
 	    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;
 
@@ -1581,7 +1594,7 @@
 	    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;
 
@@ -1594,7 +1607,7 @@
 			 && sectors_per_cluster != 64
 			 && sectors_per_cluster != 128)) {
 		printf("Bad number of sectors per cluster : %s\n", optarg);
-		usage();
+		usage(1);
 	    }
 	    break;
 
@@ -1605,7 +1618,7 @@
 			 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;
@@ -1614,16 +1627,26 @@
 	    ++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)
@@ -1633,20 +1656,21 @@
 	blocks = strtoull(argv[optind + 1], &tmp, 0);
 	if (!create && blocks != cblocks) {
 	    fprintf(stderr, "Warning: block count mismatch: ");
-	    fprintf(stderr, "found %llu but assuming %llu.\n", cblocks, blocks);
+	    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 */
@@ -1661,20 +1685,17 @@
 	    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)
@@ -1690,10 +1711,10 @@
 	 * the 'superfloppy' format.  As I don't know how to find out if
 	 * this is a MO disk I introduce a -I (ignore) switch.  -Joey
 	 */
-	if (!ignore_full_disk && ((statbuf.st_rdev & 0xff3f) == 0x0300 ||	/* hda, hdb */
-				  (statbuf.st_rdev & 0xff0f) == 0x0800 ||	/* sd */
-				  (statbuf.st_rdev & 0xff3f) == 0x0d00 ||	/* xd */
-				  (statbuf.st_rdev & 0xff3f) == 0x1600)	/* hdc, hdd */
+	if (!ignore_full_disk && ((statbuf.st_rdev & 0xffffff3f) == 0x0300 ||	/* hda, hdb */
+				  (statbuf.st_rdev & 0xffffff0f) == 0x0800 ||	/* sd */
+				  (statbuf.st_rdev & 0xffffff3f) == 0x0d00 ||	/* xd */
+				  (statbuf.st_rdev & 0xffffff3f) == 0x1600)	/* hdc, hdd */
 	)
 	die("Device partition expected, not making filesystem on entire device '%s' (use -I to override)");
 
@@ -1720,14 +1741,14 @@
     establish_params(statbuf.st_rdev, statbuf.st_size);
     /* Establish the media parameters */
 
-    setup_tables();		/* Establish the file system tables */
+    setup_tables();		/* Establish the filesystem tables */
 
     if (check)			/* Determine any bad block locations and mark them */
 	check_blocks();
     else if (listfile)
 	get_list_blocks(listfile);
 
-    write_tables();		/* Write the file system tables away! */
+    write_tables();		/* Write the filesystem tables away! */
 
     exit(0);			/* Terminate with no errors! */
 }
diff --git a/dosfstools/src/msdos_fs.h b/dosfstools/src/msdos_fs.h
new file mode 100644
index 0000000..54b2a34
--- /dev/null
+++ b/dosfstools/src/msdos_fs.h
@@ -0,0 +1,61 @@
+/* msdos_fs.h - MS-DOS filesystem constants/structures
+
+   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
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+   The complete text of the GNU General Public License
+   can be found in /usr/share/common-licenses/GPL-3 file.
+*/
+
+#ifndef _MSDOS_FS_H
+#define _MSDOS_FS_H
+
+#include <stdint.h>
+
+#define SECTOR_SIZE 512		/* sector size (bytes) */
+#define MSDOS_DPS (SECTOR_SIZE / sizeof(struct msdos_dir_entry))
+#define MSDOS_DPS_BITS 4	/* log2(MSDOS_DPS) */
+#define MSDOS_DIR_BITS 5	/* log2(sizeof(struct msdos_dir_entry)) */
+
+#define ATTR_NONE 0	/* no attribute bits */
+#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 */
+
+/* attribute bits that are copied "as is" */
+#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN)
+
+#define DELETED_FLAG 0xe5	/* marks file as deleted when in name[0] */
+#define IS_FREE(n) (!*(n) || *(n) == DELETED_FLAG)
+
+#define MSDOS_NAME 11			/* maximum name length */
+#define MSDOS_DOT ".          "		/* ".", padded to MSDOS_NAME chars */
+#define MSDOS_DOTDOT "..         "	/* "..", padded to MSDOS_NAME chars */
+
+struct msdos_dir_entry {
+    uint8_t name[8], ext[3];	/* name and extension */
+    uint8_t attr;		/* attribute bits */
+    uint8_t lcase;		/* Case for base and extension */
+    uint8_t ctime_cs;		/* Creation time, centiseconds (0-199) */
+    uint16_t ctime;		/* Creation time */
+    uint16_t cdate;		/* Creation date */
+    uint16_t adate;		/* Last access date */
+    uint16_t starthi;		/* High 16 bits of cluster in FAT32 */
+    uint16_t time, date, start;	/* time, date and first cluster */
+    uint32_t size;		/* file size (in bytes) */
+} __attribute__ ((packed));
+
+#endif /* _MSDOS_FS_H */
diff --git a/dosfstools/src/version.h b/dosfstools/src/version.h
index 6379103..f0716d3 100644
--- a/dosfstools/src/version.h
+++ b/dosfstools/src/version.h
@@ -1,6 +1,7 @@
 /* version.h
 
    Copyright (C) 1998-2005 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+   Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
 
    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
@@ -15,14 +16,14 @@
    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-   On Debian systems, the complete text of the GNU General Public License
+   The complete text of the GNU General Public License
    can be found in /usr/share/common-licenses/GPL-3 file.
 */
 
 #ifndef _version_h
 #define _version_h
 
-#define VERSION "3.0.12"
-#define VERSION_DATE "29 Oct 2011"
+#define VERSION "3.0.28"
+#define VERSION_DATE "2015-05-16"
 
 #endif