From e5c28549feefc2684c68e4dbd115060f52d5f46f Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Fri, 3 Dec 2010 11:36:00 +0900 Subject: [PATCH] fat: update Signed-off-by: Minkyu Kang --- fs/fat/fat.c | 69 ++++++++++++++++++++++++++++++++++++++++------------------- include/fat.h | 4 ++++ 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/fs/fat/fat.c b/fs/fat/fat.c index c22f657..4368668 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -631,15 +631,23 @@ __u8 get_vfatname_block[MAX_CLUSTSIZE]; static int get_vfatname (fsdata *mydata, int curclust, __u8 *cluster, - dir_entry **retdent, char *l_name) + dir_entry *retdent, char *l_name) { dir_entry *realdent; - dir_slot *slotptr = (dir_slot *)(*retdent); - __u8 *nextclust = cluster + mydata->clust_size * SECTOR_SIZE; + dir_slot *slotptr = (dir_slot *)retdent; + __u8 *buflimit = cluster + ((curclust == 0) ? + LINEAR_PREFETCH_SIZE : + (mydata->clust_size * SECTOR_SIZE) + ); __u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff; int idx = 0; - while ((__u8 *)slotptr < nextclust) { + if (counter > VFAT_MAXSEQ) { + debug("Error: VFAT name is too long\n"); + return -1; + } + + while ((__u8 *)slotptr < buflimit) { if (counter == 0) break; if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter) @@ -648,10 +656,11 @@ get_vfatname (fsdata *mydata, int curclust, __u8 *cluster, counter--; } - if ((__u8 *)slotptr >= nextclust) { + if ((__u8 *)slotptr >= buflimit) { dir_slot *slotptr2; - slotptr--; + if (curclust == 0) + return -1; curclust = get_fatent(mydata, curclust); if (CHECK_CLUST(curclust, mydata->fatsize)) { debug("curclust: 0x%x\n", curclust); @@ -666,14 +675,19 @@ get_vfatname (fsdata *mydata, int curclust, __u8 *cluster, } slotptr2 = (dir_slot *)get_vfatname_block; - while (slotptr2->id > 0x01) + while (counter > 0) { + if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK) + & 0xff) != counter) + return -1; slotptr2++; + counter--; + } /* Save the real directory entry */ - realdent = (dir_entry *)slotptr2 + 1; - while ((__u8 *)slotptr2 >= get_vfatname_block) { - slot2str(slotptr2, l_name, &idx); + realdent = (dir_entry *)slotptr2; + while ((__u8 *)slotptr2 > get_vfatname_block) { slotptr2--; + slot2str(slotptr2, l_name, &idx); } } else { /* Save the real directory entry */ @@ -694,7 +708,7 @@ get_vfatname (fsdata *mydata, int curclust, __u8 *cluster, downcase(l_name); /* Return the real directory entry */ - *retdent = realdent; + memcpy(retdent, realdent, sizeof(dir_entry)); return 0; } @@ -774,7 +788,7 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect, int dols) { __u16 prevcksum = 0xffff; - __u32 curclust = startsect; + __u32 curclust = START(retdent); int files = 0, dirs = 0; debug("get_dentfromdir: %s\n", filename); @@ -784,16 +798,16 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect, int i; - if (disk_read(curclust, mydata->clust_size, - get_dentfromdir_block) < 0) { - printf("Error: reading directory block\n"); + if (get_cluster(mydata, curclust, get_dentfromdir_block, + mydata->clust_size * SECTOR_SIZE) != 0) { + debug("Error: reading directory block\n"); return NULL; } dentptr = (dir_entry *)get_dentfromdir_block; for (i = 0; i < DIRENTSPERCLUST; i++) { - char s_name[14], l_name[256]; + char s_name[14], l_name[VFAT_MAXLEN_BYTES]; l_name[0] = '\0'; if (dentptr->name[0] == DELETED_FLAG) { @@ -807,7 +821,7 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect, prevcksum = ((dir_slot *)dentptr)->alias_checksum; get_vfatname(mydata, curclust, get_dentfromdir_block, - &dentptr, l_name); + dentptr, l_name); if (dols) { int isdir; char dirc; @@ -913,7 +927,7 @@ static dir_entry *get_dentfromdir (fsdata *mydata, int startsect, FAT2CPU32(dentptr->size), (dentptr->attr & ATTR_DIR) ? "(DIR)" : ""); - return dentptr; + return retdent; } curclust = get_fatent(mydata, curclust); @@ -1093,7 +1107,11 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize, debug("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) { + if (disk_read(cursect, + (mydata->fatsize == 32) ? + (mydata->clust_size) : + LINEAR_PREFETCH_SIZE / SECTOR_SIZE, + do_fat_read_block) < 0) { debug("Error: reading rootdir block\n"); return -1; } @@ -1101,9 +1119,13 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize, dentptr = (dir_entry *) do_fat_read_block; for (i = 0; i < DIRENTSPERBLOCK; i++) { - char s_name[14], l_name[256]; + char s_name[14], l_name[VFAT_MAXLEN_BYTES]; l_name[0] = '\0'; + if (dentptr->name[0] == DELETED_FLAG) { + dentptr++; + continue; + } if ((dentptr->attr & ATTR_VOLUME)) { #ifdef CONFIG_SUPPORT_VFAT if ((dentptr->attr & ATTR_VFAT) && @@ -1111,9 +1133,12 @@ do_fat_read (const char *filename, void *buffer, unsigned long maxsize, prevcksum = ((dir_slot *)dentptr)->alias_checksum; - get_vfatname(mydata, 0, + get_vfatname(mydata, + (mydata->fatsize == 32) ? + root_cluster : + 0, do_fat_read_block, - &dentptr, l_name); + dentptr, l_name); if (dols == LS_ROOT) { char dirc; diff --git a/include/fat.h b/include/fat.h index 772cf35..b7839ac 100644 --- a/include/fat.h +++ b/include/fat.h @@ -30,6 +30,10 @@ #include #define CONFIG_SUPPORT_VFAT +/* Maximum Long File Name length supported here is 128 UTF-16 code units */ +#define VFAT_MAXLEN_BYTES 256 /* Maximum LFN buffer in bytes */ +#define VFAT_MAXSEQ 9 /* Up to 9 of 13 2-byte UTF-16 entries */ +#define LINEAR_PREFETCH_SIZE (SECTOR_SIZE*2) /* Prefetch buffer size */ #define SECTOR_SIZE FS_BLOCK_SIZE -- 2.7.4