Fix reading FAT32 root dirs that span >1 cluster
authorNick Gasson <nick@nickg.me.uk>
Sat, 13 Nov 2010 18:57:35 +0000 (18:57 +0000)
committerSteve Sakoman <steve@sakoman.com>
Wed, 24 Nov 2010 14:29:56 +0000 (06:29 -0800)
Unlike FAT12/16, FAT32 does not guarantee that root directories will
occupy consecutive clusters. To get each cluster after the first you
must access the FAT as with any other directory. This patch implements
this and bumps up the largest valid cluster number to support large
e.g. 64MB partitions.

fs/fat/fat.c

index c6bdb13..44ecb4a 100644 (file)
@@ -384,7 +384,7 @@ get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
                        newclust = get_fatent(mydata, endclust);
                        if((newclust -1)!=endclust)
                                goto getit;
-                       if (newclust <= 0x0001 || newclust >= 0xfff0) {
+                       if (newclust <= 0x0001 || newclust >= 0xfffff0) {
                                FAT_DPRINT("curclust: 0x%x\n", newclust);
                                FAT_DPRINT("Invalid FAT entry\n");
                                return gotsize;
@@ -419,7 +419,7 @@ getit:
                filesize -= actsize;
                buffer += actsize;
                curclust = get_fatent(mydata, endclust);
-               if (curclust <= 0x0001 || curclust >= 0xfff0) {
+               if (curclust <= 0x0001 || curclust >= 0xfffff0) {
                        FAT_DPRINT("curclust: 0x%x\n", curclust);
                        FAT_ERROR("Invalid FAT entry\n");
                        return gotsize;
@@ -580,7 +580,7 @@ static dir_entry *get_dentfromdir (fsdata * mydata, int startsect,
            return retdent;
        }
        curclust = get_fatent (mydata, curclust);
-       if (curclust <= 0x0001 || curclust >= 0xfff0) {
+       if (curclust <= 0x0001 || curclust >= 0xfffff0) {
            FAT_DPRINT ("curclust: 0x%x\n", curclust);
            FAT_ERROR ("Invalid FAT entry\n");
            return NULL;
@@ -679,7 +679,7 @@ do_fat_read(const char *filename, void *buffer, unsigned long maxsize,
     dir_entry *dentptr;
     __u16 prevcksum = 0xffff;
     char *subname = "";
-    int rootdir_size, cursect;
+    int rootdir_size, cursect, curclus;
     int idx, isdir = 0;
     int files = 0, dirs = 0;
     long ret = 0;
@@ -697,6 +697,7 @@ do_fat_read(const char *filename, void *buffer, unsigned long maxsize,
     mydata->fat_sect = bs.reserved;
     cursect = mydata->rootdir_sect
            = mydata->fat_sect + mydata->fatlength * bs.fats;
+    curclus = bs.root_cluster;   // For FAT32 only
     mydata->clust_size = bs.cluster_size;
     if (mydata->fatsize == 32) {
        rootdir_size = mydata->clust_size;
@@ -818,7 +819,16 @@ do_fat_read(const char *filename, void *buffer, unsigned long maxsize,
 
            goto rootdir_done;  /* We got a match */
        }
-       cursect++;
+
+       if (mydata->fatsize != 32)
+          cursect++;
+       else {
+          // FAT32 does not guarantee contiguous root directory
+          curclus = get_fatent (mydata, curclus);
+          cursect = (curclus * mydata->clust_size) + mydata->data_begin;
+
+          FAT_DPRINT ("root clus %d sector %d\n", curclus, cursect);
+       }
     }
   rootdir_done: