From dd6d7967dfa88bd51062a8afb004962d16006ecd Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Thu, 8 May 2014 16:14:07 +0800 Subject: fs/fat: correct FAT16/12 file finding in root dir 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 --- fs/fat/fat_write.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'fs/fat') diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 90d6ab63bf..ba7e3aeb0b 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; -- cgit v1.2.1