[U-Boot] [PATCH 0/3] fs: fat: misc fix for FAT16/12

This patch series fix the bug when search files in root dir in FAT16/12.
In early time, I've sent a single patch for this: http://patchwork.ozlabs.org/patch/336585/
This patch series is updated version compare with the early one in above URL. It not only refined my early fix but also add other misc fixes.
Josh Wu (3): fs/fat: add fat12 cluster check fs: fat_write: fix the incorrect last cluster checking fs/fat: correct FAT16/12 file finding in root dir
fs/fat/fat_write.c | 29 ++++++++++++++++++++++++++++- include/fat.h | 7 ++++++- 2 files changed, 34 insertions(+), 2 deletions(-)

Signed-off-by: Josh Wu josh.wu@atmel.com --- include/fat.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/fat.h b/include/fat.h index c8eb7cc..65da733 100644 --- a/include/fat.h +++ b/include/fat.h @@ -85,7 +85,9 @@ + (mydata->fatsize != 32 ? 0 : \ (FAT2CPU16((dent)->starthi) << 16))) #define CHECK_CLUST(x, fatsize) ((x) <= 1 || \ - (x) >= ((fatsize) != 32 ? 0xfff0 : 0xffffff0)) + (x) >= ((fatsize) != 32 ? \ + ((fatsize) != 16 ? 0xff0 : 0xfff0) : \ + 0xffffff0))
typedef struct boot_sector { __u8 ignored[3]; /* Bootstrap code */

On Thu, May 08, 2014 at 04:14:05PM +0800, Wu, Josh wrote:
Signed-off-by: Josh Wu josh.wu@atmel.com
Applied to u-boot/master, thanks!

In fat_write.c, the last clust condition check is incorrect:
if ((curclust >= 0xffffff8) || (curclust >= 0xfff8)) { ... ... }
For example, in FAT32 if curclust is 0x11000. It is a valid clust. But on above condition check, it will be think as a last clust.
So the correct last clust check should be: in fat32, curclust >= 0xffffff8 in fat16, curclust >= 0xfff8 in fat12, curclust >= 0xff8
This patch correct the last clust check.
Signed-off-by: Josh Wu josh.wu@atmel.com --- fs/fat/fat_write.c | 2 +- include/fat.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 9f5e911..623d11c 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -882,7 +882,7 @@ static dir_entry *find_directory_entry(fsdata *mydata, int startsect, }
curclust = get_fatent_value(mydata, dir_curclust); - if ((curclust >= 0xffffff8) || (curclust >= 0xfff8)) { + if (IS_LAST_CLUST(curclust, mydata->fatsize)) { empty_dentptr = dentptr; return NULL; } diff --git a/include/fat.h b/include/fat.h index 65da733..81d9790 100644 --- a/include/fat.h +++ b/include/fat.h @@ -84,6 +84,9 @@ #define START(dent) (FAT2CPU16((dent)->start) \ + (mydata->fatsize != 32 ? 0 : \ (FAT2CPU16((dent)->starthi) << 16))) +#define IS_LAST_CLUST(x, fatsize) ((x) >= ((fatsize) != 32 ? \ + ((fatsize) != 16 ? 0xff8 : 0xfff8) : \ + 0xffffff8)) #define CHECK_CLUST(x, fatsize) ((x) <= 1 || \ (x) >= ((fatsize) != 32 ? \ ((fatsize) != 16 ? 0xff0 : 0xfff0) : \

On Thu, May 08, 2014 at 04:14:06PM +0800, Wu, Josh wrote:
In fat_write.c, the last clust condition check is incorrect:
if ((curclust >= 0xffffff8) || (curclust >= 0xfff8)) { ... ... }
For example, in FAT32 if curclust is 0x11000. It is a valid clust. But on above condition check, it will be think as a last clust.
So the correct last clust check should be: in fat32, curclust >= 0xffffff8 in fat16, curclust >= 0xfff8 in fat12, curclust >= 0xff8
This patch correct the last clust check.
Signed-off-by: Josh Wu josh.wu@atmel.com
Applied to u-boot/master, thanks!

When write a file into FAT file system, it will search a match file in root dir. So the find_directory_entry() will get the first cluster of root dir content and search the directory item one by one. If the file is not found, we will call get_fatent_value() to get next cluster of root dir via lookup the FAT table and continue the search.
The issue is in FAT16/12 system, we cannot get root dir's next clust from FAT table. The FAT table only be use to find the clust of data aera in FAT16/12.
In FAT16/12 if the clust is in root dir, the clust number is a negative number or 0, 1. Since root dir is located in front of the data area. Data area start clust #2. So the root dir clust number should < 2.
This patch will check above situation before call get_fatenv_value(). If curclust is < 2, include minus number, we just increase one on the curclust since root dir is in continous cluster.
The patch also add a sanity check for entry in get_fatenv_value().
Signed-off-by: Josh Wu josh.wu@atmel.com --- fs/fat/fat_write.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 623d11c..da8902a 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -139,6 +139,11 @@ static __u32 get_fatent_value(fsdata *mydata, __u32 entry) __u32 ret = 0x00; __u16 val1, val2;
+ if (CHECK_CLUST(entry, mydata->fatsize)) { + printf("Error: Invalid FAT entry: 0x%08x\n", entry); + return ret; + } + switch (mydata->fatsize) { case 32: bufnum = entry / FAT32BUFSIZE; @@ -881,6 +886,28 @@ static dir_entry *find_directory_entry(fsdata *mydata, int startsect, return dentptr; }
+ /* + * In FAT16/12, the root dir is locate before data area, shows + * in following: + * ------------------------------------------------------------- + * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) | + * ------------------------------------------------------------- + * + * As a result if curclust is in Root dir, it is a negative + * number or 0, 1. + * + */ + if (mydata->fatsize != 32 && (int)curclust <= 1) { + /* Current clust is in root dir, set to next clust */ + curclust++; + if ((int)curclust <= 1) + continue; /* continue to find */ + + /* Reach the end of root dir */ + empty_dentptr = dentptr; + return NULL; + } + curclust = get_fatent_value(mydata, dir_curclust); if (IS_LAST_CLUST(curclust, mydata->fatsize)) { empty_dentptr = dentptr;

On Thu, May 08, 2014 at 04:14:07PM +0800, Wu, Josh wrote:
When write a file into FAT file system, it will search a match file in root dir. So the find_directory_entry() will get the first cluster of root dir content and search the directory item one by one. If the file is not found, we will call get_fatent_value() to get next cluster of root dir via lookup the FAT table and continue the search.
The issue is in FAT16/12 system, we cannot get root dir's next clust from FAT table. The FAT table only be use to find the clust of data aera in FAT16/12.
In FAT16/12 if the clust is in root dir, the clust number is a negative number or 0, 1. Since root dir is located in front of the data area. Data area start clust #2. So the root dir clust number should < 2.
This patch will check above situation before call get_fatenv_value(). If curclust is < 2, include minus number, we just increase one on the curclust since root dir is in continous cluster.
The patch also add a sanity check for entry in get_fatenv_value().
Signed-off-by: Josh Wu josh.wu@atmel.com
Applied to u-boot/master, thanks!
participants (2)
-
Josh Wu
-
Tom Rini