diff mbox

[U-Boot,7/7] FAT: Make it possible to read from any file position

Message ID 895920526.294134.1342735386480.JavaMail.root@advansee.com
State Superseded
Headers show

Commit Message

Benoît Thébaudeau July 19, 2012, 10:03 p.m. UTC
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.thebaudeau@advansee.com>
Cc: Wolfgang Denk <wd@denx.de>
---
 .../fs/fat/fat.c                                   |   90 ++++++++++++++++----
 1 file changed, 72 insertions(+), 18 deletions(-)

Comments

Mike Frysinger July 19, 2012, 10:44 p.m. UTC | #1
On Thursday 19 July 2012 18:03:06 Benoît Thébaudeau wrote:
> --- u-boot-66714b1.orig/fs/fat/fat.c
> +++ u-boot-66714b1/fs/fat/fat.c
> 
> +__u8 get_contents_vfatname_block[MAX_CLUSTSIZE]
> +	__aligned(ARCH_DMA_MINALIGN);

is there any reason for this to be exported ?  could you mark it static ?

>  static long
> -get_contents (fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
> -	      unsigned long maxsize)
> +get_contents (fsdata *mydata, dir_entry *dentptr, unsigned long pos,

delete the space before the "("

>  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,

delete the space before the "("

> +long
> +do_fat_read (const char *filename, void *buffer, unsigned long maxsize,

no spaces before that "("
-mike
Benoît Thébaudeau July 19, 2012, 11:17 p.m. UTC | #2
On Friday 20 July 2012 00:44:52 Mike Frysinger wrote:
> On Thursday 19 July 2012 18:03:06 Benoît Thébaudeau wrote:
> > --- u-boot-66714b1.orig/fs/fat/fat.c
> > +++ u-boot-66714b1/fs/fat/fat.c
> > 
> > +__u8 get_contents_vfatname_block[MAX_CLUSTSIZE]
> > +	__aligned(ARCH_DMA_MINALIGN);
> 
> is there any reason for this to be exported ?  could you mark it
> static ?

I'll do that. There are probably other variables in fat.c missing static, so
I'll do a dedicated patch before this series. That will shift the patch numbers.
How should I repost the new version of the series? Should I keep the message ID
of each patch even if the numbering changes, or should I post a v2 completely
separately from v1?

> >  static long
> > -get_contents (fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
> > -	      unsigned long maxsize)
> > +get_contents (fsdata *mydata, dir_entry *dentptr, unsigned long
> > pos,
> 
> delete the space before the "("
> 
> >  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,
> 
> delete the space before the "("
> 
> > +long
> > +do_fat_read (const char *filename, void *buffer, unsigned long
> > maxsize,
> 
> no spaces before that "("

I'll add a cosmetic patch for that in a prequel.

Regards,
Benoît
Mike Frysinger July 20, 2012, 3:02 a.m. UTC | #3
On Thursday 19 July 2012 19:17:31 Benoît Thébaudeau wrote:
> On Friday 20 July 2012 00:44:52 Mike Frysinger wrote:
> > On Thursday 19 July 2012 18:03:06 Benoît Thébaudeau wrote:
> > > --- u-boot-66714b1.orig/fs/fat/fat.c
> > > +++ u-boot-66714b1/fs/fat/fat.c
> > > 
> > > +__u8 get_contents_vfatname_block[MAX_CLUSTSIZE]
> > > +	__aligned(ARCH_DMA_MINALIGN);
> > 
> > is there any reason for this to be exported ?  could you mark it
> > static ?
> 
> I'll do that. There are probably other variables in fat.c missing static,
> so I'll do a dedicated patch before this series. That will shift the patch
> numbers. How should I repost the new version of the series? Should I keep
> the message ID of each patch even if the numbering changes, or should I
> post a v2 completely separately from v1?

it's easier on everyone to do this.  you might want to look at tools/patman/ 
as a way for managing the review process.
-mike
diff mbox

Patch

diff --git u-boot-66714b1.orig/fs/fat/fat.c u-boot-66714b1/fs/fat/fat.c
index 8ac8b85..709a5eb 100644
--- u-boot-66714b1.orig/fs/fat/fat.c
+++ u-boot-66714b1/fs/fat/fat.c
@@ -329,13 +329,16 @@  get_cluster (fsdata *mydata, __u32 clustnum, __u8 *buffer,
 }
 
 /*
- * 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;
@@ -345,12 +348,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 {
@@ -434,9 +484,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)
@@ -475,13 +522,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)
@@ -492,7 +539,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);
 		}
@@ -771,12 +818,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;
@@ -890,12 +937,12 @@  do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
 					(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++) {
@@ -915,7 +962,7 @@  do_fat_read (const char *filename, void *buffer, unsigned long maxsize,
 
 					get_vfatname(mydata,
 						     root_cluster,
-						     do_fat_read_block,
+						     do_fat_read_at_block,
 						     dentptr, l_name);
 
 					if (dols == LS_ROOT) {
@@ -1118,7 +1165,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:
@@ -1126,6 +1173,13 @@  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;