diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/fat/fat.c | 98 | ||||
| -rw-r--r-- | fs/fat/fat_write.c | 18 | 
2 files changed, 88 insertions, 28 deletions
| diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 19f6a8c0a..41ae15eeb 100644 --- a/fs/fat/fat.c +++ b/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; @@ -1192,8 +1246,14 @@ int file_fat_ls(const char *dir)  	return do_fat_read(dir, NULL, 0, LS_YES);  } -long file_fat_read(const char *filename, void *buffer, unsigned long maxsize) +long file_fat_read_at(const char *filename, unsigned long pos, void *buffer, +		      unsigned long maxsize)  {  	printf("reading %s\n", filename); -	return do_fat_read(filename, buffer, maxsize, LS_NO); +	return do_fat_read_at(filename, pos, buffer, maxsize, LS_NO); +} + +long file_fat_read(const char *filename, void *buffer, unsigned long maxsize) +{ +	return file_fat_read_at(filename, 0, buffer, maxsize);  } diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index a6181e71b..5829adf1a 100644 --- a/fs/fat/fat_write.c +++ b/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) |