diff options
Diffstat (limited to '')
-rw-r--r-- | dosfstools/src/boot.c | 226 | ||||
-rw-r--r-- | dosfstools/src/boot.h | 4 | ||||
-rw-r--r-- | dosfstools/src/check.c | 184 | ||||
-rw-r--r-- | dosfstools/src/check.h | 7 | ||||
-rw-r--r-- | dosfstools/src/common.c | 9 | ||||
-rw-r--r-- | dosfstools/src/common.h | 11 | ||||
-rw-r--r-- | dosfstools/src/dosfsck.h | 218 | ||||
-rw-r--r-- | dosfstools/src/fat.c | 107 | ||||
-rw-r--r-- | dosfstools/src/fat.h | 21 | ||||
-rw-r--r-- | dosfstools/src/fatlabel.c (renamed from dosfstools/src/dosfslabel.c) | 46 | ||||
-rw-r--r-- | dosfstools/src/file.c | 12 | ||||
-rw-r--r-- | dosfstools/src/file.h | 5 | ||||
-rw-r--r-- | dosfstools/src/fsck.fat.c (renamed from dosfstools/src/dosfsck.c) | 79 | ||||
-rw-r--r-- | dosfstools/src/fsck.fat.h | 191 | ||||
-rw-r--r-- | dosfstools/src/io.c | 16 | ||||
-rw-r--r-- | dosfstools/src/io.h | 11 | ||||
-rw-r--r-- | dosfstools/src/lfn.c | 62 | ||||
-rw-r--r-- | dosfstools/src/lfn.h | 3 | ||||
-rw-r--r-- | dosfstools/src/mkfs.fat.c (renamed from dosfstools/src/mkdosfs.c) | 493 | ||||
-rw-r--r-- | dosfstools/src/msdos_fs.h | 61 | ||||
-rw-r--r-- | dosfstools/src/version.h | 7 |
21 files changed, 983 insertions, 790 deletions
diff --git a/dosfstools/src/boot.c b/dosfstools/src/boot.c index bbaee0471..0c0918f8b 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 @@ static struct { 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 @@ static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss) /* 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 @@ static void dump_boot(DOS_FS * fs, struct boot_sector *b, unsigned lss) 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 @@ static void check_backup_boot(DOS_FS * fs, struct boot_sector *b, int lss) 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 @@ static void check_backup_boot(DOS_FS * fs, struct boot_sector *b, int lss) 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 @@ 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("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 check_backup_boot(DOS_FS * fs, struct boot_sector *b, int lss) 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 @@ 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; - 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 @@ static void read_fsinfo(DOS_FS * fs, struct boot_sector *b, int lss) 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 @@ static void read_fsinfo(DOS_FS * fs, struct boot_sector *b, int lss) } 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 @@ void read_boot(DOS_FS * fs) 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 @@ void read_boot(DOS_FS * fs) 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 @@ void read_boot(DOS_FS * fs) " 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 @@ void read_boot(DOS_FS * fs) 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 @@ 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) @@ -407,8 +440,8 @@ void read_boot(DOS_FS * fs) } 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 @@ void read_boot(DOS_FS * fs) 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 @@ static loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de) 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 @@ static loff_t find_volume_de(DOS_FS * fs, DIR_ENT * de) 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 @@ static void write_volume_label(DOS_FS * fs, char *label) 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 c9edfa337..d52e62476 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 3f175b019..bbb97e4f3 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 @@ static DOS_FILE *root; /* 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 @@ static DOS_FILE *root; #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 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern) 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 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern) 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 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern) 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 @@ static char *path_name(DOS_FILE * file) 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 @@ static char *file_stat(DOS_FILE * file) 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 @@ static int bad_name(DOS_FILE * file) 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 @@ static int bad_name(DOS_FILE * file) 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 @@ static int bad_name(DOS_FILE * file) } 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 lfn_remove(loff_t from, loff_t to) 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 @@ static void drop_file(DOS_FS * fs, DOS_FILE * file) --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 @@ static void truncate_file(DOS_FS * fs, DOS_FILE * file, unsigned long clusters) set_fat(fs, walk, 0); else if ((deleting = !--clusters)) set_fat(fs, walk, -1); - prev = walk; walk = next; } } @@ -374,7 +386,7 @@ static void truncate_file(DOS_FS * fs, DOS_FILE * file, unsigned long clusters) 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 @@ static void auto_rename(DOS_FILE * file) 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 @@ static void auto_rename(DOS_FILE * file) (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 @@ 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)) { - 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 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, @@ -462,7 +492,7 @@ static int handle_dot(DOS_FS * fs, DOS_FILE * file, int dots) 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 @@ static int check_file(DOS_FS * fs, DOS_FILE * file) { 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 @@ static int check_file(DOS_FS * fs, DOS_FILE * file) 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 @@ 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), 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 @@ static int check_file(DOS_FS * fs, DOS_FILE * file) 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 @@ static int check_file(DOS_FS * fs, DOS_FILE * file) 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 @@ static int check_file(DOS_FS * fs, DOS_FILE * file) 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 @@ static int check_file(DOS_FS * fs, DOS_FILE * file) 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 int check_dir(DOS_FS * fs, DOS_FILE ** root, int dots) 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 @@ static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test) 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 @@ static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test) 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 @@ 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; @@ -863,9 +901,9 @@ static void test_file(DOS_FS * fs, DOS_FILE * file, int read_test) 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 @@ static void undelete(DOS_FS * fs, DOS_FILE * file) 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 @@ static void add_file(DOS_FS * fs, DOS_FILE *** chain, DOS_FILE * parent, 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 @@ static int scan_dir(DOS_FS * fs, DOS_FILE * this, FDSC ** cp) { 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 277c44b6f..fcb6bea39 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 @@ loff_t alloc_rootdir_entry(DOS_FS * fs, DIR_ENT * de, const char *pattern); 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 51605a2aa..9d1119322 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 @@ typedef struct _link { struct _link *next; } LINK; -void die(char *msg, ...) +void die(const char *msg, ...) { va_list args; @@ -47,7 +48,7 @@ void die(char *msg, ...) exit(1); } -void pdie(char *msg, ...) +void pdie(const char *msg, ...) { va_list args; @@ -95,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/dosfstools/src/common.h b/dosfstools/src/common.h index 395eabb59..c15efb538 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 @@ 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/dosfstools/src/dosfsck.h b/dosfstools/src/dosfsck.h deleted file mode 100644 index 6f53c72cf..000000000 --- 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 5a0dfb0f2..5a92f5684 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 @@ void get_fat(FAT_ENTRY * entry, void *fat, unsigned long cluster, DOS_FS * fs) (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 get_fat(FAT_ENTRY * entry, void *fat, unsigned long cluster, DOS_FS * fs) */ 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 @@ void read_fat(DOS_FS * fs) 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 @@ void read_fat(DOS_FS * fs) * -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 @@ void set_fat(DOS_FS * fs, unsigned long cluster, unsigned long new) 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 @@ void set_fat(DOS_FS * fs, unsigned long cluster, unsigned long new) 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 @@ void set_fat(DOS_FS * fs, unsigned long cluster, unsigned long new) } } -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 @@ int bad_cluster(DOS_FS * fs, unsigned long cluster) * @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 @@ unsigned long next_cluster(DOS_FS * fs, unsigned long cluster) 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 @@ loff_t cluster_start(DOS_FS * fs, unsigned long cluster) * @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 @@ void set_owner(DOS_FS * fs, unsigned long cluster, DOS_FILE * owner) 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 @@ DOS_FILE *get_owner(DOS_FS * fs, unsigned long cluster) void fix_bad(DOS_FS * fs) { - unsigned long i; + uint32_t i; if (verbose) printf("Checking for bad clusters.\n"); @@ -307,7 +318,7 @@ void fix_bad(DOS_FS * fs) 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 fix_bad(DOS_FS * fs) 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 @@ void reclaim_free(DOS_FS * fs) } } 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 @@ void reclaim_free(DOS_FS * fs) * 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 @@ void reclaim_file(DOS_FS * fs) 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 @@ void reclaim_file(DOS_FS * fs) 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 @@ void reclaim_file(DOS_FS * fs) 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 @@ void reclaim_file(DOS_FS * fs) 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 @@ unsigned long update_free(DOS_FS * fs) 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 @@ unsigned long update_free(DOS_FS * fs) 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 @@ unsigned long update_free(DOS_FS * fs) } 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 13ac1b345..b50ed4a96 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 @@ void reclaim_file(DOS_FS * fs); 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 index 5e2d2824f..1484ba527 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 @@ static void usage(int error) 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 @@ static void check_atari(void) 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 @@ int main(int argc, char *argv[]) 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 a73b73f5e..dffcec1cd 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 40bd58a92..eaaf356be 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 index a7a59e1a1..2bc3dc216 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 @@ int main(int argc, char **argv) { 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 @@ int main(int argc, char **argv) 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 @@ int main(int argc, char **argv) break; case 'v': verbose = 1; - printf("dosfsck " VERSION " (" VERSION_DATE ")\n"); break; case 'V': verify = 1; @@ -166,33 +161,32 @@ int main(int argc, char **argv) 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 @@ int main(int argc, char **argv) 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 @@ int main(int argc, char **argv) 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 000000000..e5f617871 --- /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 a703c2db1..450432c8e 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 @@ void fs_read(loff_t pos, int size, void *data) 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 @@ int fs_close(int write) 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 2db4ea7ac..d23d07ee3 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 @@ loff_t llseek(int fd, loff_t offset, int whence); 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 @@ void fs_write(loff_t pos, int size, void *data); 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 736491cb0..2601172ee 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 @@ static unsigned char fat_uni2esc[64] = { (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 @@ static char *cnv_unicode(const unsigned char *uni, int maxlen, int use_q) 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 @@ static char *cnv_unicode(const unsigned char *uni, int maxlen, int use_q) 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 @@ 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]; @@ -366,7 +390,7 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset) 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 @@ void lfn_add_slot(DIR_ENT * de, loff_t dir_offset) 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 @@ 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; @@ -430,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); } @@ -440,8 +464,10 @@ char *lfn_get(DIR_ENT * de, loff_t * lfn_offset) } } - 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 2ea44a725..e5c3991ff 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 index 9873bef12..dddbe2472 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 @@ 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 */ @@ -274,16 +222,15 @@ char dummy_boot_code[BOOTCODE_SIZE] = "\x0e" /* push cs */ /* 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 sectors_per_cluster = 0; /* Number of sectors per disk cluster */ 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 alarm_intr(int alnum); 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 long do_check(char *buffer, int try, off_t current_block) static void alarm_intr(int alnum) { + (void)alnum; + if (currently_testing >= blocks) return; @@ -474,7 +430,7 @@ static void get_list_blocks(char *filename) { int i; FILE *listfile; - unsigned long blockno; + long blockno; listfile = fopen(filename, "r"); if (listfile == (FILE *) NULL) @@ -508,8 +464,7 @@ static int valid_offset(int fd, loff_t offset) /* 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 @@ static unsigned long long count_blocks(char *filename, int *remainder) } 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 @@ static void check_mount(char *device_name) 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 @@ static void establish_params(int device_num, int size) if (ioctl(dev, FDGETPRM, ¶m)) /* 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 @@ floppy_default: 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 @@ floppy_default: 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 @@ floppy_default: 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 @@ floppy_default: 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 @@ def_hd_params: /* 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) } 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) "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 @@ static void setup_tables(void) "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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) if (!cluster_count) { if (sectors_per_cluster) /* If yes, die if we'd spec'd sectors per cluster */ - die("Too many clusters for 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 @@ static void setup_tables(void) 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 @@ static void setup_tables(void) } 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 @@ static void setup_tables(void) } 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 @@ static void setup_tables(void) 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 @@ static void write_tables(void) 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 @@ static void write_tables(void) 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 @@ 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 */ -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 @@ int main(int argc, char **argv) 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 @@ int main(int argc, char **argv) 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 @@ 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; @@ -1463,11 +1446,20 @@ int main(int argc, char **argv) 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 @@ 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; @@ -1484,8 +1476,9 @@ 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; case 'I': @@ -1496,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; @@ -1565,15 +1558,35 @@ int main(int argc, char **argv) } 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 @@ 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; @@ -1594,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; @@ -1605,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; @@ -1614,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) @@ -1633,20 +1656,21 @@ int main(int argc, char **argv) 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 @@ 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) @@ -1690,10 +1711,10 @@ int main(int argc, char **argv) * 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 @@ int main(int argc, char **argv) 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 000000000..54b2a3446 --- /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 6379103b6..f0716d346 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 |