diff options
Diffstat (limited to 'dosfstools/src/fat.c')
-rw-r--r-- | dosfstools/src/fat.c | 107 |
1 files changed, 59 insertions, 48 deletions
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); |