summaryrefslogtreecommitdiffstats
path: root/dosfstools/src/fat.c
diff options
context:
space:
mode:
Diffstat (limited to 'dosfstools/src/fat.c')
-rw-r--r--dosfstools/src/fat.c107
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);