diff options
author | JinWang An <jinwang.an@samsung.com> | 2022-12-26 13:14:06 +0900 |
---|---|---|
committer | JinWang An <jinwang.an@samsung.com> | 2022-12-26 13:14:06 +0900 |
commit | f2f0e690db008447a230628762679108d1d9e72b (patch) | |
tree | 34591c76e9cf24b4bec943301979335711f9e4cc /src | |
parent | 43faab009aefa5beeaa7c8abc6dcca705507ace7 (diff) | |
download | dosfstools-f2f0e690db008447a230628762679108d1d9e72b.tar.gz dosfstools-f2f0e690db008447a230628762679108d1d9e72b.tar.bz2 dosfstools-f2f0e690db008447a230628762679108d1d9e72b.zip |
Imported Upstream version 3.0.28upstream/3.0.28
Diffstat (limited to 'src')
-rw-r--r-- | src/boot.c | 20 | ||||
-rw-r--r-- | src/check.c | 73 | ||||
-rw-r--r-- | src/common.c | 6 | ||||
-rw-r--r-- | src/common.h | 8 | ||||
-rw-r--r-- | src/fat.c | 14 | ||||
-rw-r--r-- | src/file.c | 9 | ||||
-rw-r--r-- | src/file.h | 2 | ||||
-rw-r--r-- | src/fsck.fat.c | 10 | ||||
-rw-r--r-- | src/fsck.fat.h | 156 | ||||
-rw-r--r-- | src/io.c | 1 | ||||
-rw-r--r-- | src/lfn.c | 23 | ||||
-rw-r--r-- | src/mkfs.fat.c | 235 | ||||
-rw-r--r-- | src/msdos_fs.h | 61 | ||||
-rw-r--r-- | src/version.h | 4 |
14 files changed, 339 insertions, 283 deletions
@@ -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. */ @@ -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) { @@ -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; @@ -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 { @@ -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> @@ -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 |