When storage devices contain files larger than the embedded RAM, it is useful to
be able to read these files by chunks, e.g. for a software update to the
embedded NAND Flash from an external storage device (USB stick, SD card, etc.).

Hence, this patch makes it possible by adding a new FAT API to read files from a
given position.

Signed-off-by: Benoît Thébaudeau <benoit.thebaud...@advansee.com>
Cc: Wolfgang Denk <w...@denx.de>
---
Changes for v2:
 - Patch renumbering because of the new v2 1/8.
 - Possible code style changes due to the new v2 1/8.
 - Add missing vairable renaming to fat_write.c.

 .../fs/fat/fat.c                                   |   88 ++++++++++++++++----
 .../fs/fat/fat_write.c                             |   18 ++--
 2 files changed, 80 insertions(+), 26 deletions(-)

diff --git u-boot-66714b1.orig/fs/fat/fat.c u-boot-66714b1/fs/fat/fat.c
index 19f6a8c..8c94b28 100644
--- u-boot-66714b1.orig/fs/fat/fat.c
+++ u-boot-66714b1/fs/fat/fat.c
@@ -328,13 +328,16 @@ get_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer, 
unsigned long size)
 }
 
 /*
- * Read at most 'maxsize' bytes from the file associated with 'dentptr'
+ * Read at most 'maxsize' bytes from 'pos' in the file associated with 
'dentptr'
  * into 'buffer'.
  * Return the number of bytes read or -1 on fatal errors.
  */
+__u8 get_contents_vfatname_block[MAX_CLUSTSIZE]
+       __aligned(ARCH_DMA_MINALIGN);
+
 static long
-get_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
-            unsigned long maxsize)
+get_contents(fsdata *mydata, dir_entry *dentptr, unsigned long pos,
+            __u8 *buffer, unsigned long maxsize)
 {
        unsigned long filesize = FAT2CPU32(dentptr->size), gotsize = 0;
        unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
@@ -344,12 +347,59 @@ get_contents(fsdata *mydata, dir_entry *dentptr, __u8 
*buffer,
 
        debug("Filesize: %ld bytes\n", filesize);
 
-       if (maxsize > 0 && filesize > maxsize)
-               filesize = maxsize;
+       if (pos >= filesize) {
+               debug("Read position past EOF: %lu\n", pos);
+               return gotsize;
+       }
+
+       if (maxsize > 0 && filesize > pos + maxsize)
+               filesize = pos + maxsize;
 
        debug("%ld bytes\n", filesize);
 
        actsize = bytesperclust;
+
+       /* go to cluster at pos */
+       while (actsize <= pos) {
+               curclust = get_fatent(mydata, curclust);
+               if (CHECK_CLUST(curclust, mydata->fatsize)) {
+                       debug("curclust: 0x%x\n", curclust);
+                       debug("Invalid FAT entry\n");
+                       return gotsize;
+               }
+               actsize += bytesperclust;
+       }
+
+       /* actsize > pos */
+       actsize -= bytesperclust;
+       filesize -= actsize;
+       pos -= actsize;
+
+       /* align to beginning of next cluster if any */
+       if (pos) {
+               actsize = min(filesize, bytesperclust);
+               if (get_cluster(mydata, curclust, get_contents_vfatname_block,
+                               (int)actsize) != 0) {
+                       printf("Error reading cluster\n");
+                       return -1;
+               }
+               filesize -= actsize;
+               actsize -= pos;
+               memcpy(buffer, get_contents_vfatname_block + pos, actsize);
+               gotsize += actsize;
+               if (!filesize)
+                       return gotsize;
+               buffer += actsize;
+
+               curclust = get_fatent(mydata, curclust);
+               if (CHECK_CLUST(curclust, mydata->fatsize)) {
+                       debug("curclust: 0x%x\n", curclust);
+                       debug("Invalid FAT entry\n");
+                       return gotsize;
+               }
+       }
+
+       actsize = bytesperclust;
        endclust = curclust;
 
        do {
@@ -433,9 +483,6 @@ static int slot2str(dir_slot *slotptr, char *l_name, int 
*idx)
  * into 'retdent'
  * Return 0 on success, -1 otherwise.
  */
-__u8 get_vfatname_block[MAX_CLUSTSIZE]
-       __aligned(ARCH_DMA_MINALIGN);
-
 static int
 get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,
             dir_entry *retdent, char *l_name)
@@ -474,13 +521,13 @@ get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,
                        return -1;
                }
 
-               if (get_cluster(mydata, curclust, get_vfatname_block,
+               if (get_cluster(mydata, curclust, get_contents_vfatname_block,
                                mydata->clust_size * mydata->sect_size) != 0) {
                        debug("Error: reading directory block\n");
                        return -1;
                }
 
-               slotptr2 = (dir_slot *)get_vfatname_block;
+               slotptr2 = (dir_slot *)get_contents_vfatname_block;
                while (counter > 0) {
                        if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
                            & 0xff) != counter)
@@ -491,7 +538,7 @@ get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,
 
                /* Save the real directory entry */
                realdent = (dir_entry *)slotptr2;
-               while ((__u8 *)slotptr2 > get_vfatname_block) {
+               while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
                        slotptr2--;
                        slot2str(slotptr2, l_name, &idx);
                }
@@ -770,11 +817,12 @@ exit:
        return ret;
 }
 
-__u8 do_fat_read_block[MAX_CLUSTSIZE]
+__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
        __aligned(ARCH_DMA_MINALIGN);
 
 long
-do_fat_read(const char *filename, void *buffer, unsigned long maxsize, int 
dols)
+do_fat_read_at(const char *filename, unsigned long pos, void *buffer,
+              unsigned long maxsize, int dols)
 {
        char fnamecopy[2048];
        boot_sector bs;
@@ -888,12 +936,12 @@ do_fat_read(const char *filename, void *buffer, unsigned 
long maxsize, int dols)
                                        (mydata->fatsize == 32) ?
                                        (mydata->clust_size) :
                                        PREFETCH_BLOCKS,
-                                       do_fat_read_block) < 0) {
+                                       do_fat_read_at_block) < 0) {
                                debug("Error: reading rootdir block\n");
                                goto exit;
                        }
 
-                       dentptr = (dir_entry *) do_fat_read_block;
+                       dentptr = (dir_entry *) do_fat_read_at_block;
                }
 
                for (i = 0; i < DIRENTSPERBLOCK; i++) {
@@ -913,7 +961,7 @@ do_fat_read(const char *filename, void *buffer, unsigned 
long maxsize, int dols)
 
                                        get_vfatname(mydata,
                                                     root_cluster,
-                                                    do_fat_read_block,
+                                                    do_fat_read_at_block,
                                                     dentptr, l_name);
 
                                        if (dols == LS_ROOT) {
@@ -1116,7 +1164,7 @@ rootdir_done:
                        subname = nextname;
        }
 
-       ret = get_contents(mydata, dentptr, buffer, maxsize);
+       ret = get_contents(mydata, dentptr, pos, buffer, maxsize);
        debug("Size: %d, got: %ld\n", FAT2CPU32(dentptr->size), ret);
 
 exit:
@@ -1124,6 +1172,12 @@ exit:
        return ret;
 }
 
+long
+do_fat_read(const char *filename, void *buffer, unsigned long maxsize, int 
dols)
+{
+       return do_fat_read_at(filename, 0, buffer, maxsize, dols);
+}
+
 int file_fat_detectfs(void)
 {
        boot_sector bs;
diff --git u-boot-66714b1.orig/fs/fat/fat_write.c 
u-boot-66714b1/fs/fat/fat_write.c
index a6181e7..5829adf 100644
--- u-boot-66714b1.orig/fs/fat/fat_write.c
+++ u-boot-66714b1/fs/fat/fat_write.c
@@ -328,7 +328,7 @@ static void flush_dir_table(fsdata *mydata, dir_entry 
**dentptr);
 static void
 fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name)
 {
-       dir_slot *slotptr = (dir_slot *)get_vfatname_block;
+       dir_slot *slotptr = (dir_slot *)get_contents_vfatname_block;
        __u8 counter = 0, checksum;
        int idx = 0, ret;
        char s_name[16];
@@ -373,7 +373,7 @@ static __u32 dir_curclust;
  * a slot) into 'l_name'. If successful also copy the real directory entry
  * into 'retdent'
  * If additional adjacent cluster for directory entries is read into memory,
- * then 'get_vfatname_block' is copied into 'get_dentfromdir_block' and
+ * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' 
and
  * the location of the real directory entry is returned by 'retdent'
  * Return 0 on success, -1 otherwise.
  */
@@ -416,13 +416,13 @@ get_long_file_name(fsdata *mydata, int curclust, __u8 
*cluster,
 
                dir_curclust = curclust;
 
-               if (get_cluster(mydata, curclust, get_vfatname_block,
+               if (get_cluster(mydata, curclust, get_contents_vfatname_block,
                                mydata->clust_size * mydata->sect_size) != 0) {
                        debug("Error: reading directory block\n");
                        return -1;
                }
 
-               slotptr2 = (dir_slot *)get_vfatname_block;
+               slotptr2 = (dir_slot *)get_contents_vfatname_block;
                while (counter > 0) {
                        if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
                            & 0xff) != counter)
@@ -433,7 +433,7 @@ get_long_file_name(fsdata *mydata, int curclust, __u8 
*cluster,
 
                /* Save the real directory entry */
                realdent = (dir_entry *)slotptr2;
-               while ((__u8 *)slotptr2 > get_vfatname_block) {
+               while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
                        slotptr2--;
                        slot2str(slotptr2, l_name, &idx);
                }
@@ -459,9 +459,9 @@ get_long_file_name(fsdata *mydata, int curclust, __u8 
*cluster,
        *retdent = realdent;
 
        if (slotptr2) {
-               memcpy(get_dentfromdir_block, get_vfatname_block,
+               memcpy(get_dentfromdir_block, get_contents_vfatname_block,
                        mydata->clust_size * mydata->sect_size);
-               cur_position = (__u8 *)realdent - get_vfatname_block;
+               cur_position = (__u8 *)realdent - get_contents_vfatname_block;
                *retdent = (dir_entry *) &get_dentfromdir_block[cur_position];
        }
 
@@ -980,11 +980,11 @@ static int do_fat_write(const char *filename, void 
*buffer,
        if (disk_read(cursect,
                (mydata->fatsize == 32) ?
                (mydata->clust_size) :
-               PREFETCH_BLOCKS, do_fat_read_block) < 0) {
+               PREFETCH_BLOCKS, do_fat_read_at_block) < 0) {
                debug("Error: reading rootdir block\n");
                goto exit;
        }
-       dentptr = (dir_entry *) do_fat_read_block;
+       dentptr = (dir_entry *) do_fat_read_at_block;
 
        name_len = strlen(filename);
        if (name_len >= VFAT_MAXLEN_BYTES)
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to