From: Wu, Josh <Josh.wu@atmel.com>
Date: Thu, 8 May 2014 08:14:07 +0000 (+0800)
Subject: fs/fat: correct FAT16/12 file finding in root dir
X-Git-Tag: v2025.01-rc5-pxa1908~15329
X-Git-Url: http://git.dujemihanovic.xyz/img/html/static/git-favicon.png?a=commitdiff_plain;h=dd6d7967dfa88bd51062a8afb004962d16006ecd;p=u-boot.git

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 <josh.wu@atmel.com>
---

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;