summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/boot.c20
-rw-r--r--src/check.c73
-rw-r--r--src/common.c6
-rw-r--r--src/common.h8
-rw-r--r--src/fat.c14
-rw-r--r--src/file.c9
-rw-r--r--src/file.h2
-rw-r--r--src/fsck.fat.c10
-rw-r--r--src/fsck.fat.h156
-rw-r--r--src/io.c1
-rw-r--r--src/lfn.c23
-rw-r--r--src/mkfs.fat.c235
-rw-r--r--src/msdos_fs.h61
-rw-r--r--src/version.h4
14 files changed, 339 insertions, 283 deletions
diff --git a/src/boot.c b/src/boot.c
index 5b3825c..0c0918f 100644
--- a/src/boot.c
+++ b/src/boot.c
@@ -25,8 +25,8 @@
* 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>
@@ -45,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"}, {
@@ -62,9 +62,9 @@ static struct {
/* Unaligned fields must first be accessed byte-wise */
#define GET_UNALIGNED_W(f) \
- ( (__u16)f[0] | ((__u16)f[1]<<8) )
+ ( (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;
@@ -166,18 +166,18 @@ static void check_backup_boot(DOS_FS * fs, struct boot_sector *b, int lss)
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("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);
@@ -227,7 +227,7 @@ static void read_fsinfo(DOS_FS * fs, struct boot_sector *b, int lss)
if (interactive && get_key("12", "?") == '1') {
/* search for a free reserved sector (not boot sector and not
* backup boot sector) */
- __u32 s;
+ uint32_t s;
for (s = 1; s < le16toh(b->reserved); ++s)
if (s != le16toh(b->backup_boot))
break;
@@ -425,7 +425,7 @@ void read_boot(DOS_FS * fs)
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)
diff --git a/src/check.c b/src/check.c
index e8aaf92..d8b9d72 100644
--- a/src/check.c
+++ b/src/check.c
@@ -273,11 +273,10 @@ static int bad_name(DOS_FILE * file)
strncmp((const char *)name, "WP ROOT SF", 11) == 0)
return 0;
- /* PATCH ED+DL */
- /* 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;
- }
+ /* 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 */
@@ -401,20 +400,16 @@ static void auto_rename(DOS_FILE * file)
(const char *)file->dir_ent.name, MSDOS_NAME))
break;
if (!walk) {
- /* PATCH ED+DL */
- 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 */
- file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME); /* only keep the DIR and VOLUME attributes */
- fs_write(file->offset, MSDOS_NAME+2, file->dir_ent.name);
- }
- else
- {
- 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);
@@ -448,20 +443,16 @@ static void rename_file(DOS_FILE * file)
walk[1] = 0;
for (walk = name; *walk == ' ' || *walk == '\t'; walk++) ;
if (file_cvt(walk, file->dir_ent.name)) {
- /* PATCH ED+DL */
- 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 */
- file->dir_ent.attr &= ~(ATTR_DIR | ATTR_VOLUME); /* only keep the DIR and VOLUME attributes */
- fs_write(file->offset, MSDOS_NAME+2, file->dir_ent.name);
- }
- else
- {
- 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);
@@ -473,7 +464,7 @@ static void rename_file(DOS_FILE * file)
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,
@@ -554,12 +545,20 @@ static int check_file(DOS_FS * fs, DOS_FILE * file)
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), (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;
@@ -845,7 +844,7 @@ static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test)
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);
@@ -886,7 +885,7 @@ static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test)
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;
diff --git a/src/common.c b/src/common.c
index af222a2..9d11193 100644
--- a/src/common.c
+++ b/src/common.c
@@ -37,7 +37,7 @@ typedef struct _link {
struct _link *next;
} LINK;
-void die(char *msg, ...)
+void die(const char *msg, ...)
{
va_list args;
@@ -48,7 +48,7 @@ void die(char *msg, ...)
exit(1);
}
-void pdie(char *msg, ...)
+void pdie(const char *msg, ...)
{
va_list args;
@@ -96,7 +96,7 @@ int min(int a, int b)
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/src/common.h b/src/common.h
index 8508602..c15efb5 100644
--- a/src/common.h
+++ b/src/common.h
@@ -20,16 +20,14 @@
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. */
@@ -50,7 +48,7 @@ int min(int a, int b);
/* 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/src/fat.c b/src/fat.c
index 027c586..5a92f56 100644
--- a/src/fat.c
+++ b/src/fat.c
@@ -80,7 +80,7 @@ void get_fat(FAT_ENTRY * entry, void *fat, uint32_t cluster, DOS_FS * fs)
*/
void read_fat(DOS_FS * fs)
{
- int eff_size;
+ int eff_size, alloc_size;
uint32_t i;
void *first, *second = NULL;
int first_ok, second_ok;
@@ -96,10 +96,18 @@ void read_fat(DOS_FS * fs)
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) {
diff --git a/src/file.c b/src/file.c
index 30adcde..9519070 100644
--- a/src/file.c
+++ b/src/file.c
@@ -30,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"
#include "charconv.h"
FDSC *fp_root = NULL;
diff --git a/src/file.h b/src/file.h
index 3adfc96..eaaf356 100644
--- a/src/file.h
+++ b/src/file.h
@@ -23,6 +23,8 @@
#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/src/fsck.fat.c b/src/fsck.fat.c
index c073d9a..f786a93 100644
--- a/src/fsck.fat.c
+++ b/src/fsck.fat.c
@@ -63,7 +63,7 @@ static void usage(char *name)
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 filesystem\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");
@@ -108,11 +108,11 @@ int main(int argc, char **argv)
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, "Aac:d:bflnprtu:vVwy")) != EOF)
+ while ((c = getopt(argc, argv, "Aac:d:bflnprtu:vVwy")) != -1)
switch (c) {
case 'A': /* toggle Atari format */
atari_format = !atari_format;
@@ -169,7 +169,7 @@ int main(int argc, char **argv)
}
set_dos_codepage(-1); /* set default codepage if none was given in command line */
if ((test || write_immed) && !rw) {
- fprintf(stderr, "-t and -w require -a or -r\n");
+ fprintf(stderr, "-t and -w can not be used in read only mode\n");
exit(2);
}
if (optind != argc - 1)
diff --git a/src/fsck.fat.h b/src/fsck.fat.h
index e5ade5b..e5f6178 100644
--- a/src/fsck.fat.h
+++ b/src/fsck.fat.h
@@ -28,20 +28,12 @@
#define _DOSFSCK_H
#include <fcntl.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> */
-
-#include <asm/types.h>
-#include <asm/byteorder.h>
-
-#include <linux/msdos_fs.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
@@ -49,95 +41,95 @@
/* ++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
+ 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 */
- __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) */
/* 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 */
+ 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 */
- __u8 junk[422];
+ uint8_t 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
+ 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 */
- __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 */
+ 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 */
- __u8 junk[450];
+ uint8_t 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;
+ 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 {
- __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) */
+ 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 {
diff --git a/src/io.c b/src/io.c
index 3755ba5..450432c 100644
--- a/src/io.c
+++ b/src/io.c
@@ -31,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>
diff --git a/src/lfn.c b/src/lfn.c
index 2e60198..2601172 100644
--- a/src/lfn.c
+++ b/src/lfn.c
@@ -21,6 +21,7 @@
*/
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
@@ -33,14 +34,14 @@
#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
@@ -173,7 +174,7 @@ static void clear_lfn_slots(int start, int end)
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];
@@ -409,7 +410,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset)
char *lfn_get(DIR_ENT * de, loff_t * lfn_offset)
{
char *lfn;
- __u8 sum;
+ uint8_t sum;
int i;
*lfn_offset = 0;
@@ -453,7 +454,7 @@ char *lfn_get(DIR_ENT * de, loff_t * lfn_offset)
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);
}
diff --git a/src/mkfs.fat.c b/src/mkfs.fat.c
index 604b7d0..b38d116 100644
--- a/src/mkfs.fat.c
+++ b/src/mkfs.fat.c
@@ -60,15 +60,15 @@
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>
#include <stdint.h>
#include <endian.h>
+#include <getopt.h>
-#include <asm/types.h>
+#include "msdos_fs.h"
/* In earlier versions, an own llseek() was used, but glibc lseek() is
* sufficient (or even better :) for 64 bit offsets in the meantime */
@@ -102,21 +102,6 @@ static inline int cdiv(int a, int b)
return (a + b - 1) / b;
}
-/* MS-DOS filesystem structures -- I included them here instead of
- including linux/msdos_fs.h since that doesn't include some fields we
- need */
-
-#define ATTR_RO 1 /* read-only */
-#define ATTR_HIDDEN 2 /* hidden */
-#define ATTR_SYS 4 /* system */
-#define ATTR_VOLUME 8 /* volume label */
-#define ATTR_DIR 16 /* directory */
-#define ATTR_ARCH 32 /* archived */
-
-#define ATTR_NONE 0 /* no attribute bits */
-#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN)
- /* attribute bits that are copied "as is" */
-
/* FAT values */
#define FAT_EOF (atari_format ? 0x0fffffff : 0x0ffffff8)
#define FAT_BAD 0x0ffffff7
@@ -148,80 +133,67 @@ static inline int cdiv(int a, int b)
* alignments */
struct msdos_volume_info {
- __u8 drive_number; /* BIOS drive number */
- __u8 RESERVED; /* Unused */
- __u8 ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */
- __u8 volume_id[4]; /* Volume ID number */
- __u8 volume_label[11]; /* Volume label */
- __u8 fs_type[8]; /* Typically FAT12 or FAT16 */
+ uint8_t drive_number; /* BIOS drive number */
+ uint8_t RESERVED; /* Unused */
+ uint8_t ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */
+ uint8_t volume_id[4]; /* Volume ID number */
+ uint8_t volume_label[11]; /* Volume label */
+ uint8_t fs_type[8]; /* Typically FAT12 or FAT16 */
} __attribute__ ((packed));
struct msdos_boot_sector {
- __u8 boot_jump[3]; /* Boot strap short or near jump */
- __u8 system_id[8]; /* Name - can be used to special case
+ uint8_t boot_jump[3]; /* Boot strap short or near jump */
+ uint8_t system_id[8]; /* Name - can be used to special case
partition manager volumes */
- __u8 sector_size[2]; /* bytes per logical sector */
- __u8 cluster_size; /* sectors/cluster */
- __u16 reserved; /* reserved sectors */
- __u8 fats; /* number of FATs */
- __u8 dir_entries[2]; /* root directory entries */
- __u8 sectors[2]; /* number of sectors */
- __u8 media; /* media code (unused) */
- __u16 fat_length; /* sectors/FAT */
- __u16 secs_track; /* sectors per track */
- __u16 heads; /* number of heads */
- __u32 hidden; /* hidden sectors (unused) */
- __u32 total_sect; /* number of sectors (if sectors == 0) */
+ uint8_t sector_size[2]; /* bytes per logical sector */
+ uint8_t cluster_size; /* sectors/cluster */
+ uint16_t reserved; /* reserved sectors */
+ uint8_t fats; /* number of FATs */
+ uint8_t dir_entries[2]; /* root directory entries */
+ uint8_t sectors[2]; /* number of sectors */
+ uint8_t media; /* media code (unused) */
+ uint16_t fat_length; /* sectors/FAT */
+ uint16_t secs_track; /* sectors per track */
+ uint16_t heads; /* number of heads */
+ uint32_t hidden; /* hidden sectors (unused) */
+ uint32_t total_sect; /* number of sectors (if sectors == 0) */
union {
struct {
struct msdos_volume_info vi;
- __u8 boot_code[BOOTCODE_SIZE];
+ uint8_t boot_code[BOOTCODE_SIZE];
} __attribute__ ((packed)) _oldfat;
struct {
- __u32 fat32_length; /* sectors/FAT */
- __u16 flags; /* bit 8: fat mirroring, low 4: active fat */
- __u8 version[2]; /* major, minor filesystem version */
- __u32 root_cluster; /* first cluster in root directory */
- __u16 info_sector; /* filesystem info sector */
- __u16 backup_boot; /* backup boot sector */
- __u16 reserved2[6]; /* Unused */
+ uint32_t fat32_length; /* sectors/FAT */
+ uint16_t flags; /* bit 8: fat mirroring, low 4: active fat */
+ uint8_t version[2]; /* major, minor filesystem version */
+ uint32_t root_cluster; /* first cluster in root directory */
+ uint16_t info_sector; /* filesystem info sector */
+ uint16_t backup_boot; /* backup boot sector */
+ uint16_t reserved2[6]; /* Unused */
struct msdos_volume_info vi;
- __u8 boot_code[BOOTCODE_FAT32_SIZE];
+ uint8_t boot_code[BOOTCODE_FAT32_SIZE];
} __attribute__ ((packed)) _fat32;
} __attribute__ ((packed)) fstype;
- __u16 boot_sign;
+ uint16_t boot_sign;
} __attribute__ ((packed));
#define fat32 fstype._fat32
#define oldfat fstype._oldfat
struct fat32_fsinfo {
- __u32 reserved1; /* Nothing as far as I can tell */
- __u32 signature; /* 0x61417272L */
- __u32 free_clusters; /* Free cluster count. -1 if unknown */
- __u32 next_cluster; /* Most recently allocated cluster.
+ uint32_t reserved1; /* Nothing as far as I can tell */
+ uint32_t signature; /* 0x61417272L */
+ uint32_t free_clusters; /* Free cluster count. -1 if unknown */
+ uint32_t next_cluster; /* Most recently allocated cluster.
* Unused under Linux. */
- __u32 reserved2[4];
+ uint32_t reserved2[4];
};
-struct msdos_dir_entry {
- char name[8], ext[3]; /* name and extension */
- __u8 attr; /* attribute bits */
- __u8 lcase; /* Case for base and extension */
- __u8 ctime_ms; /* Creation time, milliseconds */
- __u16 ctime; /* Creation time */
- __u16 cdate; /* Creation date */
- __u16 adate; /* Last access date */
- __u16 starthi; /* high 16 bits of first cl. (FAT32) */
- __u16 time, date, start; /* time, date and first cluster */
- __u32 size; /* file size (in bytes) */
-} __attribute__ ((packed));
-
/* The "boot code" we put into the filesystem... it writes a message and
tells the user to try again */
-char dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 };
+unsigned char dummy_boot_jump[3] = { 0xeb, 0x3c, 0x90 };
-char dummy_boot_jump_m68k[2] = { 0x60, 0x1c };
+unsigned char dummy_boot_jump_m68k[2] = { 0x60, 0x1c };
#define MSG_OFFSET_OFFSET 3
char dummy_boot_code[BOOTCODE_SIZE] = "\x0e" /* push cs */
@@ -250,14 +222,13 @@ char dummy_boot_code[BOOTCODE_SIZE] = "\x0e" /* push cs */
/* Global variables - the root of all evil :-) - see these and weep! */
-static char *program_name = "mkfs.fat"; /* Name of the program */
+static const char *program_name = "mkfs.fat"; /* Name of the program */
static char *device_name = NULL; /* Name of the device on which to create the filesystem */
static int atari_format = 0; /* Use Atari variation of MS-DOS FS format */
static int check = FALSE; /* Default to no readablity checking */
static int verbose = 0; /* Default to verbose mode off */
static long volume_id; /* Volume ID number */
static time_t create_time; /* Creation time */
-static struct timeval create_timeval; /* Creation time */
static char volume_name[] = NO_NAME; /* Volume name */
static uint64_t blocks; /* Number of blocks in filesystem */
static int sector_size = 512; /* Size of a logical sector */
@@ -290,6 +261,9 @@ static int fat_media_byte = 0; /* media byte in header and starting FAT */
static int malloc_entire_fat = FALSE; /* Whether we should malloc() the entire FAT or not */
static int align_structures = TRUE; /* Whether to enforce alignment */
static int orphaned_sectors = 0; /* Sectors that exist in the last block of filesystem */
+static int invariant = 0; /* Whether to set normally randomized or
+ current time based values to
+ constants */
/* Function prototype definitions */
@@ -700,17 +674,18 @@ def_hd_params:
}
if (size_fat == 32) {
/* For FAT32, try to do the same as M$'s format command
- * (http://technet.microsoft.com/en-us/library/cc938438.aspx):
- * fs size < 8G: 4k clusters
- * fs size < 16G: 8k clusters
- * fs size < 32G: 16k clusters
- * fs size >= 32G: 32k clusters
+ * (see http://www.win.tue.nl/~aeb/linux/fs/fat/fatgen103.pdf p. 20):
+ * fs size <= 260M: 0.5k clusters
+ * fs size <= 8G: 4k clusters
+ * fs size <= 16G: 8k clusters
+ * fs size <= 32G: 16k clusters
+ * fs size > 32G: 32k clusters
*/
uint32_t sz_mb =
(blocks + (1 << (20 - BLOCK_SIZE_BITS)) - 1) >> (20 -
BLOCK_SIZE_BITS);
bs.cluster_size =
- sz_mb >= 32 * 1024 ? 64 : sz_mb >= 16 * 1024 ? 32 : sz_mb >=
+ sz_mb > 32 * 1024 ? 64 : sz_mb > 16 * 1024 ? 32 : sz_mb >
8 * 1024 ? 16 : sz_mb > 260 ? 8 : 1;
} else {
/* FAT12 and FAT16: start at 4 sectors per cluster */
@@ -826,7 +801,7 @@ static void setup_tables(void)
bs.hidden = htole32(hidden_sectors);
else {
/* In Atari format, hidden is a 16 bit field */
- __u16 hidden = htole16(hidden_sectors);
+ uint16_t hidden = htole16(hidden_sectors);
if (hidden_sectors & ~0xffff)
die("#hidden doesn't fit in 16bit field of Atari format\n");
memcpy(&bs.hidden, &hidden, 2);
@@ -1239,7 +1214,10 @@ static void setup_tables(void)
memcpy(de->name, volume_name, 8);
memcpy(de->ext, volume_name + 8, 3);
de->attr = ATTR_VOLUME;
- ctime = localtime(&create_time);
+ if (!invariant)
+ ctime = localtime(&create_time);
+ else
+ ctime = gmtime(&create_time);
de->time = htole16((unsigned short)((ctime->tm_sec >> 1) +
(ctime->tm_min << 5) +
(ctime->tm_hour << 11)));
@@ -1247,7 +1225,7 @@ static void setup_tables(void)
htole16((unsigned short)(ctime->tm_mday +
((ctime->tm_mon + 1) << 5) +
((ctime->tm_year - 80) << 9)));
- de->ctime_ms = 0;
+ de->ctime_cs = 0;
de->ctime = de->time;
de->cdate = de->date;
de->adate = de->date;
@@ -1279,7 +1257,7 @@ static void setup_tables(void)
info->next_cluster = htole32(2);
/* Info sector also must have boot sign */
- *(__u16 *) (info_sector + 0x1fe) = htole16(BOOT_SIGN);
+ *(uint16_t *) (info_sector + 0x1fe) = htole16(BOOT_SIGN);
}
if (!(blank_sector = malloc(sector_size)))
@@ -1357,17 +1335,20 @@ static void write_tables(void)
free(fat); /* Free up the fat table space reserved during setup_tables */
}
-/* Report the command usage and return a failure error code */
+/* Report the command usage and exit with the given error code */
-static void usage(void)
+static void usage(int exitval)
{
- fatal_error("\
+ fprintf(stderr, "\
Usage: mkfs.fat [-a][-A][-c][-C][-v][-I][-l bad-block-file][-b backup-boot-sector]\n\
[-m boot-msg-file][-n volume-name][-i volume-id]\n\
[-s sectors-per-cluster][-S logical-sector-size][-f number-of-FATs]\n\
[-h hidden-sectors][-F fat-size][-r root-dir-entries][-R reserved-sectors]\n\
[-M FAT-media-byte][-D drive_number]\n\
+ [--invariant]\n\
+ [--help]\n\
/dev/name [blocks]\n");
+ exit(exitval);
}
/*
@@ -1412,6 +1393,15 @@ int main(int argc, char **argv)
int create = 0;
uint64_t cblocks = 0;
int min_sector_size;
+ int bad_block_count = 0;
+ struct timeval create_timeval;
+
+ enum {OPT_HELP=1000, OPT_INVARIANT,};
+ const struct option long_options[] = {
+ {"help", no_argument, NULL, OPT_HELP},
+ {"invariant", no_argument, NULL, OPT_INVARIANT},
+ {0,}
+ };
if (argc && *argv) { /* What's the program name? */
char *p;
@@ -1427,7 +1417,8 @@ int main(int argc, char **argv)
printf("mkfs.fat " VERSION " (" VERSION_DATE ")\n");
- while ((c = getopt(argc, argv, "aAb:cCf:D:F:Ii:l:m:M:n:r:R:s:S:h:v")) != EOF)
+ while ((c = getopt_long(argc, argv, "aAb:cCf:D:F:Ii:l:m:M:n:r:R:s:S:h:v",
+ long_options, NULL)) != -1)
/* Scan the command line for options */
switch (c) {
case 'A': /* toggle Atari format */
@@ -1442,7 +1433,7 @@ int main(int argc, char **argv)
backup_boot = (int)strtol(optarg, &tmp, 0);
if (*tmp || backup_boot < 2 || backup_boot > 0xffff) {
printf("Bad location for backup boot sector : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1459,7 +1450,7 @@ int main(int argc, char **argv)
drive_number_option = (int) strtol (optarg, &tmp, 0);
if (*tmp || (drive_number_option != 0 && drive_number_option != 0x80)) {
printf ("Drive number must be 0 or 0x80: %s\n", optarg);
- usage ();
+ usage(1);
}
drive_number_by_user=1;
break;
@@ -1468,7 +1459,7 @@ int main(int argc, char **argv)
nr_fats = (int)strtol(optarg, &tmp, 0);
if (*tmp || nr_fats < 1 || nr_fats > 4) {
printf("Bad number of FATs : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1476,7 +1467,7 @@ int main(int argc, char **argv)
size_fat = (int)strtol(optarg, &tmp, 0);
if (*tmp || (size_fat != 12 && size_fat != 16 && size_fat != 32)) {
printf("Bad FAT type : %s\n", optarg);
- usage();
+ usage(1);
}
size_fat_by_user = 1;
break;
@@ -1485,7 +1476,7 @@ int main(int argc, char **argv)
hidden_sectors = (int)strtol(optarg, &tmp, 0);
if (*tmp || hidden_sectors < 0) {
printf("Bad number of hidden sectors : %s\n", optarg);
- usage();
+ usage(1);
}
hidden_sectors_by_user = 1;
break;
@@ -1498,7 +1489,7 @@ int main(int argc, char **argv)
volume_id = strtoul(optarg, &tmp, 16);
if (*tmp) {
printf("Volume ID must be a hexadecimal number\n");
- usage();
+ usage(1);
}
break;
@@ -1568,10 +1559,14 @@ int main(int argc, char **argv)
break;
case 'M': /* M : FAT Media byte */
- fat_media_byte = (int) strtol (optarg, &tmp, 0);
- if (*tmp || fat_media_byte < 248 || fat_media_byte > 255) {
- printf ("FAT Media byte must be between 0xF8 and 0xFF : %s\n", optarg);
- usage ();
+ fat_media_byte = (int)strtol(optarg, &tmp, 0);
+ if (*tmp) {
+ printf("Bad number for media descriptor : %s\n", optarg);
+ usage(1);
+ }
+ if (fat_media_byte != 0xf0 && (fat_media_byte < 0xf8 || fat_media_byte > 0xff)) {
+ printf("FAT Media byte must either be between 0xF8 and 0xFF or be 0xF0 : %s\n", optarg);
+ usage(1);
}
break;
@@ -1591,7 +1586,7 @@ int main(int argc, char **argv)
root_dir_entries = (int)strtol(optarg, &tmp, 0);
if (*tmp || root_dir_entries < 16 || root_dir_entries > 32768) {
printf("Bad number of root directory entries : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1599,7 +1594,7 @@ int main(int argc, char **argv)
reserved_sectors = (int)strtol(optarg, &tmp, 0);
if (*tmp || reserved_sectors < 1 || reserved_sectors > 0xffff) {
printf("Bad number of reserved sectors : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1612,7 +1607,7 @@ int main(int argc, char **argv)
&& sectors_per_cluster != 64
&& sectors_per_cluster != 128)) {
printf("Bad number of sectors per cluster : %s\n", optarg);
- usage();
+ usage(1);
}
break;
@@ -1623,7 +1618,7 @@ int main(int argc, char **argv)
sector_size != 8192 && sector_size != 16384 &&
sector_size != 32768)) {
printf("Bad logical sector size : %s\n", optarg);
- usage();
+ usage(1);
}
sector_size_set = 1;
break;
@@ -1632,16 +1627,26 @@ int main(int argc, char **argv)
++verbose;
break;
+ case OPT_HELP:
+ usage(0);
+ break;
+
+ case OPT_INVARIANT:
+ invariant = 1;
+ volume_id = 0x1234abcd;
+ create_time = 1426325213;
+ break;
+
default:
printf("Unknown option: %c\n", c);
- usage();
+ usage(1);
}
if (optind < argc) {
device_name = argv[optind]; /* Determine the number of blocks in the FS */
if (!device_name) {
printf("No device specified.\n");
- usage();
+ usage(1);
}
if (!create)
@@ -1653,18 +1658,19 @@ int main(int argc, char **argv)
fprintf(stderr, "Warning: block count mismatch: ");
fprintf(stderr, "found %llu but assuming %llu.\n", (unsigned long long)cblocks, (unsigned long long)blocks);
}
+ if (*tmp)
+ bad_block_count = 1;
} else if (optind == argc - 1) { /* Or use value found */
if (create)
die("Need intended size with -C.");
blocks = cblocks;
- tmp = "";
} else {
fprintf(stderr, "No device specified!\n");
- usage();
+ usage(1);
}
- if (*tmp) {
+ if (bad_block_count) {
printf("Bad block count : %s\n", argv[optind + 1]);
- usage();
+ usage(1);
}
if (check && listfile) /* Auto and specified bad block handling are mutually */
@@ -1679,20 +1685,17 @@ int main(int argc, char **argv)
exit(1); /* The error exit code is 1! */
}
} else {
- loff_t offset = blocks * BLOCK_SIZE - 1;
- char null = 0;
/* create the file */
- dev = open(device_name, O_EXCL | O_RDWR | O_CREAT | O_TRUNC, 0666);
- if (dev < 0)
- die("unable to create %s");
- /* seek to the intended end-1, and write one byte. this creates a
- * sparse-as-possible file of appropriate size. */
- if (llseek(dev, offset, SEEK_SET) != offset)
- die("seek failed");
- if (write(dev, &null, 1) < 0)
- die("write failed");
- if (llseek(dev, 0, SEEK_SET) != 0)
- die("seek failed");
+ dev = open(device_name, O_EXCL | O_RDWR | O_CREAT, 0666);
+ if (dev < 0) {
+ if (errno == EEXIST)
+ die("file %s already exists");
+ else
+ die("unable to create %s");
+ }
+ /* expand to desired size */
+ if (ftruncate(dev, blocks * BLOCK_SIZE))
+ die("unable to resize %s");
}
if (fstat(dev, &statbuf) < 0)
diff --git a/src/msdos_fs.h b/src/msdos_fs.h
new file mode 100644
index 0000000..54b2a34
--- /dev/null
+++ b/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/src/version.h b/src/version.h
index 4ccc759..f0716d3 100644
--- a/src/version.h
+++ b/src/version.h
@@ -23,7 +23,7 @@
#ifndef _version_h
#define _version_h
-#define VERSION "3.0.27"
-#define VERSION_DATE "2014-11-12"
+#define VERSION "3.0.28"
+#define VERSION_DATE "2015-05-16"
#endif