FAT32: fix broken root directory handling.
On FAT32, instead of fetching the cluster numbers from the FAT, the
code assumed (incorrectly) that the clusters for the root directory
were allocated contiguously. In the result, only the first cluster
could be accessed. At the typical cluster size of 8 sectors this
caused all accesses to files after the first 128 entries to fail -
"fatls" would terminate after 128 files (usually displaying a bogus
file name, occasionally even crashing the system), and "fatload"
would fail to find any files that were not in the first directory
cluster.
Signed-off-by: Wolfgang Denk <wd@denx.de>
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 5b9ec2a..18b291c 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -201,6 +201,9 @@
return ret;
}
+ FAT_DPRINT("FAT%d: entry: 0x%04x = %d, offset: 0x%04x = %d\n",
+ mydata->fatsize, entry, entry, offset, offset);
+
/* Read a new block of FAT entries into the cache. */
if (bufnum != mydata->fatbufnum) {
int getsize = FATBUFSIZE/FS_BLOCK_SIZE;
@@ -260,7 +263,8 @@
}
break;
}
- FAT_DPRINT("ret: %d, offset: %d\n", ret, offset);
+ FAT_DPRINT("FAT%d: ret: %08x, offset: %04x\n",
+ mydata->fatsize, ret, offset);
return ret;
}
@@ -323,7 +327,7 @@
if (maxsize > 0 && filesize > maxsize) filesize = maxsize;
- FAT_DPRINT("Reading: %ld bytes\n", filesize);
+ FAT_DPRINT("%ld bytes\n", filesize);
actsize=bytesperclust;
endclust=curclust;
@@ -719,16 +723,19 @@
dir_entry *dentptr;
__u16 prevcksum = 0xffff;
char *subname = "";
- int rootdir_size, cursect;
+ int cursect;
int idx, isdir = 0;
int files = 0, dirs = 0;
long ret = 0;
int firsttime;
+ int root_cluster;
+ int j;
if (read_bootsectandvi (&bs, &volinfo, &mydata->fatsize)) {
FAT_DPRINT ("Error: reading boot sector\n");
return -1;
}
+ root_cluster = bs.root_cluster;
if (mydata->fatsize == 32) {
mydata->fatlength = bs.fat32_length;
} else {
@@ -739,10 +746,11 @@
= mydata->fat_sect + mydata->fatlength * bs.fats;
mydata->clust_size = bs.cluster_size;
if (mydata->fatsize == 32) {
- rootdir_size = mydata->clust_size;
- mydata->data_begin = mydata->rootdir_sect /* + rootdir_size */
+ mydata->data_begin = mydata->rootdir_sect
- (mydata->clust_size * 2);
} else {
+ int rootdir_size;
+
rootdir_size = ((bs.dir_entries[1] * (int) 256 + bs.dir_entries[0])
* sizeof (dir_entry)) / SECTOR_SIZE;
mydata->data_begin = mydata->rootdir_sect + rootdir_size
@@ -750,12 +758,19 @@
}
mydata->fatbufnum = -1;
- FAT_DPRINT ("FAT%d, fatlength: %d\n", mydata->fatsize,
+#ifdef CONFIG_SUPPORT_VFAT
+ FAT_DPRINT ("VFAT Support enabled\n");
+#endif
+ FAT_DPRINT ("FAT%d, fat_sect: %d, fatlength: %d\n",
+ mydata->fatsize,
+ mydata->fat_sect,
mydata->fatlength);
- FAT_DPRINT ("Rootdir begins at sector: %d, offset: %x, size: %d\n"
+ FAT_DPRINT ("Rootdir begins at cluster: %d, sector: %d, offset: %x\n"
"Data begins at: %d\n",
- mydata->rootdir_sect, mydata->rootdir_sect * SECTOR_SIZE,
- rootdir_size, mydata->data_begin);
+ root_cluster,
+ mydata->rootdir_sect,
+ mydata->rootdir_sect * SECTOR_SIZE,
+ mydata->data_begin);
FAT_DPRINT ("Cluster size: %d\n", mydata->clust_size);
/* "cwd" is always the root... */
@@ -779,9 +794,12 @@
isdir = 1;
}
+ j=0;
while (1) {
int i;
+ FAT_DPRINT ("FAT read sect=%d, clust_size=%d, DIRENTSPERBLOCK=%d\n",
+ cursect, mydata->clust_size, DIRENTSPERBLOCK);
if (disk_read (cursect, mydata->clust_size, do_fat_read_block) < 0) {
FAT_DPRINT ("Error: reading rootdir block\n");
return -1;
@@ -894,7 +912,29 @@
goto rootdir_done; /* We got a match */
}
+ FAT_DPRINT ("END LOOP: j=%d clust_size=%d\n", j, mydata->clust_size);
+
+ /*
+ * On FAT32 we must fetch the FAT entries for the next
+ * root directory clusters when a cluster has been
+ * completely processed.
+ */
+ if ((mydata->fatsize == 32) && (++j == mydata->clust_size)) {
+ int nxtsect;
+ int cur_clust, nxt_clust;
+
+ cur_clust = (cursect - mydata->data_begin) / mydata->clust_size;
+ nxt_clust = get_fatent(mydata, root_cluster);
+ nxtsect = mydata->data_begin + (nxt_clust * mydata->clust_size);
+ FAT_DPRINT ("END LOOP: sect=%d, clust=%d, root_clust=%d, n_sect=%d, n_clust=%d\n",
+ cursect, cur_clust, root_cluster, nxtsect, nxt_clust);
+ root_cluster = nxt_clust;
+
+ cursect = nxtsect;
+ j = 0;
+ } else {
+ cursect++;
+ }
- cursect++;
}
rootdir_done: