mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 18:35:42 +01:00 
			
		
		
		
	fs: fat: refactor write interface for a file offset
The current write implementation is quite simple: remove existing clusters and then allocating new ones and filling them with data. This, inevitably, enforces always writing from the beginning of a file. As the first step to lift this restriction, fat_file_write() and set_contents() are modified to accept an additional parameter, file offset and further re-factored so that, in the next patch, all the necessary code will be put into set_contents(). Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
		
				
					committed by
					
						 Alexander Graf
						Alexander Graf
					
				
			
			
				
	
			
			
			
						parent
						
							4ced2039dc
						
					
				
				
					commit
					704df6aa0a
				
			| @@ -528,6 +528,42 @@ static int clear_fatent(fsdata *mydata, __u32 entry) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Set start cluster in directory entry | ||||||
|  |  */ | ||||||
|  | static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr, | ||||||
|  | 			      __u32 start_cluster) | ||||||
|  | { | ||||||
|  | 	if (mydata->fatsize == 32) | ||||||
|  | 		dentptr->starthi = | ||||||
|  | 			cpu_to_le16((start_cluster & 0xffff0000) >> 16); | ||||||
|  | 	dentptr->start = cpu_to_le16(start_cluster & 0xffff); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Check whether adding a file makes the file system to | ||||||
|  |  * exceed the size of the block device | ||||||
|  |  * Return -1 when overflow occurs, otherwise return 0 | ||||||
|  |  */ | ||||||
|  | static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size) | ||||||
|  | { | ||||||
|  | 	__u32 startsect, sect_num, offset; | ||||||
|  |  | ||||||
|  | 	if (clustnum > 0) | ||||||
|  | 		startsect = clust_to_sect(mydata, clustnum); | ||||||
|  | 	else | ||||||
|  | 		startsect = mydata->rootdir_sect; | ||||||
|  |  | ||||||
|  | 	sect_num = div_u64_rem(size, mydata->sect_size, &offset); | ||||||
|  |  | ||||||
|  | 	if (offset != 0) | ||||||
|  | 		sect_num++; | ||||||
|  |  | ||||||
|  | 	if (startsect + sect_num > total_sector) | ||||||
|  | 		return -1; | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Write at most 'maxsize' bytes from 'buffer' into |  * Write at most 'maxsize' bytes from 'buffer' into | ||||||
|  * the file associated with 'dentptr' |  * the file associated with 'dentptr' | ||||||
| @@ -535,29 +571,36 @@ static int clear_fatent(fsdata *mydata, __u32 entry) | |||||||
|  * or return -1 on fatal errors. |  * or return -1 on fatal errors. | ||||||
|  */ |  */ | ||||||
| static int | static int | ||||||
| set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, | set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer, | ||||||
| 	      loff_t maxsize, loff_t *gotsize) | 	     loff_t maxsize, loff_t *gotsize) | ||||||
| { | { | ||||||
| 	loff_t filesize = FAT2CPU32(dentptr->size); | 	loff_t filesize; | ||||||
| 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; | 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; | ||||||
| 	__u32 curclust = START(dentptr); | 	__u32 curclust = START(dentptr); | ||||||
| 	__u32 endclust = 0, newclust = 0; | 	__u32 endclust = 0, newclust = 0; | ||||||
| 	loff_t actsize; | 	loff_t actsize; | ||||||
|  |  | ||||||
| 	*gotsize = 0; | 	*gotsize = 0; | ||||||
| 	debug("Filesize: %llu bytes\n", filesize); | 	filesize = maxsize; | ||||||
|  |  | ||||||
| 	if (maxsize > 0 && filesize > maxsize) |  | ||||||
| 		filesize = maxsize; |  | ||||||
|  |  | ||||||
| 	debug("%llu bytes\n", filesize); | 	debug("%llu bytes\n", filesize); | ||||||
|  |  | ||||||
| 	if (!curclust) { | 	if (curclust) { | ||||||
| 		if (filesize) { | 		/* | ||||||
| 			debug("error: nonempty clusterless file!\n"); | 		 * release already-allocated clusters anyway | ||||||
|  | 		 */ | ||||||
|  | 		if (clear_fatent(mydata, curclust)) { | ||||||
|  | 			printf("Error: clearing FAT entries\n"); | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| 		return 0; | 	} | ||||||
|  |  | ||||||
|  | 	curclust = find_empty_cluster(mydata); | ||||||
|  | 	set_start_cluster(mydata, dentptr, curclust); | ||||||
|  |  | ||||||
|  | 	if (check_overflow(mydata, curclust, filesize)) { | ||||||
|  | 		printf("Error: no space left: %llu\n", filesize); | ||||||
|  | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	actsize = bytesperclust; | 	actsize = bytesperclust; | ||||||
| @@ -568,6 +611,7 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, | |||||||
| 			newclust = determine_fatent(mydata, endclust); | 			newclust = determine_fatent(mydata, endclust); | ||||||
|  |  | ||||||
| 			if ((newclust - 1) != endclust) | 			if ((newclust - 1) != endclust) | ||||||
|  | 				/* write to <curclust..endclust> */ | ||||||
| 				goto getit; | 				goto getit; | ||||||
|  |  | ||||||
| 			if (CHECK_CLUST(newclust, mydata->fatsize)) { | 			if (CHECK_CLUST(newclust, mydata->fatsize)) { | ||||||
| @@ -614,18 +658,8 @@ getit: | |||||||
| 		actsize = bytesperclust; | 		actsize = bytesperclust; | ||||||
| 		curclust = endclust = newclust; | 		curclust = endclust = newclust; | ||||||
| 	} while (1); | 	} while (1); | ||||||
| } |  | ||||||
|  |  | ||||||
| /* | 	return 0; | ||||||
|  * Set start cluster in directory entry |  | ||||||
|  */ |  | ||||||
| static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr, |  | ||||||
| 				__u32 start_cluster) |  | ||||||
| { |  | ||||||
| 	if (mydata->fatsize == 32) |  | ||||||
| 		dentptr->starthi = |  | ||||||
| 			cpu_to_le16((start_cluster & 0xffff0000) >> 16); |  | ||||||
| 	dentptr->start = cpu_to_le16(start_cluster & 0xffff); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -642,31 +676,6 @@ static void fill_dentry(fsdata *mydata, dir_entry *dentptr, | |||||||
| 	set_name(dentptr, filename); | 	set_name(dentptr, filename); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Check whether adding a file makes the file system to |  | ||||||
|  * exceed the size of the block device |  | ||||||
|  * Return -1 when overflow occurs, otherwise return 0 |  | ||||||
|  */ |  | ||||||
| static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size) |  | ||||||
| { |  | ||||||
| 	__u32 startsect, sect_num, offset; |  | ||||||
|  |  | ||||||
| 	if (clustnum > 0) { |  | ||||||
| 		startsect = clust_to_sect(mydata, clustnum); |  | ||||||
| 	} else { |  | ||||||
| 		startsect = mydata->rootdir_sect; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	sect_num = div_u64_rem(size, mydata->sect_size, &offset); |  | ||||||
|  |  | ||||||
| 	if (offset != 0) |  | ||||||
| 		sect_num++; |  | ||||||
|  |  | ||||||
| 	if (startsect + sect_num > total_sector) |  | ||||||
| 		return -1; |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Find a directory entry based on filename or start cluster number |  * Find a directory entry based on filename or start cluster number | ||||||
|  * If the directory entry is not found, |  * If the directory entry is not found, | ||||||
| @@ -784,11 +793,10 @@ static int normalize_longname(char *l_filename, const char *filename) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int do_fat_write(const char *filename, void *buffer, loff_t size, | int file_fat_write_at(const char *filename, loff_t pos, void *buffer, | ||||||
| 			loff_t *actwrite) | 		      loff_t size, loff_t *actwrite) | ||||||
| { | { | ||||||
| 	dir_entry *retdent; | 	dir_entry *retdent; | ||||||
| 	__u32 start_cluster; |  | ||||||
| 	fsdata datablock = { .fatbuf = NULL, }; | 	fsdata datablock = { .fatbuf = NULL, }; | ||||||
| 	fsdata *mydata = &datablock; | 	fsdata *mydata = &datablock; | ||||||
| 	fat_itr *itr = NULL; | 	fat_itr *itr = NULL; | ||||||
| @@ -796,6 +804,8 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, | |||||||
| 	char *filename_copy, *parent, *basename; | 	char *filename_copy, *parent, *basename; | ||||||
| 	char l_filename[VFAT_MAXLEN_BYTES]; | 	char l_filename[VFAT_MAXLEN_BYTES]; | ||||||
|  |  | ||||||
|  | 	debug("writing %s\n", filename); | ||||||
|  |  | ||||||
| 	filename_copy = strdup(filename); | 	filename_copy = strdup(filename); | ||||||
| 	if (!filename_copy) | 	if (!filename_copy) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| @@ -839,47 +849,8 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, | |||||||
| 			goto exit; | 			goto exit; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		/* Update file size and start_cluster in a directory entry */ | 		/* Update file size in a directory entry */ | ||||||
| 		retdent->size = cpu_to_le32(size); | 		retdent->size = cpu_to_le32(pos + size); | ||||||
| 		start_cluster = START(retdent); |  | ||||||
|  |  | ||||||
| 		if (start_cluster) { |  | ||||||
| 			if (size) { |  | ||||||
| 				ret = check_overflow(mydata, start_cluster, |  | ||||||
| 							size); |  | ||||||
| 				if (ret) { |  | ||||||
| 					printf("Error: %llu overflow\n", size); |  | ||||||
| 					ret = -ENOSPC; |  | ||||||
| 					goto exit; |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			ret = clear_fatent(mydata, start_cluster); |  | ||||||
| 			if (ret) { |  | ||||||
| 				printf("Error: clearing FAT entries\n"); |  | ||||||
| 				ret = -EIO; |  | ||||||
| 				goto exit; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (!size) |  | ||||||
| 				set_start_cluster(mydata, retdent, 0); |  | ||||||
| 		} else if (size) { |  | ||||||
| 			ret = start_cluster = find_empty_cluster(mydata); |  | ||||||
| 			if (ret < 0) { |  | ||||||
| 				printf("Error: finding empty cluster\n"); |  | ||||||
| 				ret = -ENOSPC; |  | ||||||
| 				goto exit; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			ret = check_overflow(mydata, start_cluster, size); |  | ||||||
| 			if (ret) { |  | ||||||
| 				printf("Error: %llu overflow\n", size); |  | ||||||
| 				ret = -ENOSPC; |  | ||||||
| 				goto exit; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			set_start_cluster(mydata, retdent, start_cluster); |  | ||||||
| 		} |  | ||||||
| 	} else { | 	} else { | ||||||
| 		/* Create a new file */ | 		/* Create a new file */ | ||||||
|  |  | ||||||
| @@ -907,32 +878,13 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, | |||||||
| 			goto exit; | 			goto exit; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (size) { |  | ||||||
| 			ret = start_cluster = find_empty_cluster(mydata); |  | ||||||
| 			if (ret < 0) { |  | ||||||
| 				printf("Error: finding empty cluster\n"); |  | ||||||
| 				ret = -ENOSPC; |  | ||||||
| 				goto exit; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			ret = check_overflow(mydata, start_cluster, size); |  | ||||||
| 			if (ret) { |  | ||||||
| 				printf("Error: %llu overflow\n", size); |  | ||||||
| 				ret = -ENOSPC; |  | ||||||
| 				goto exit; |  | ||||||
| 			} |  | ||||||
| 		} else { |  | ||||||
| 			start_cluster = 0; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		/* Set attribute as archive for regular file */ | 		/* Set attribute as archive for regular file */ | ||||||
| 		fill_dentry(itr->fsdata, itr->dent, filename, | 		fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20); | ||||||
| 			    start_cluster, size, 0x20); |  | ||||||
|  |  | ||||||
| 		retdent = itr->dent; | 		retdent = itr->dent; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ret = set_contents(mydata, retdent, buffer, size, actwrite); | 	ret = set_contents(mydata, retdent, pos, buffer, size, actwrite); | ||||||
| 	if (ret < 0) { | 	if (ret < 0) { | ||||||
| 		printf("Error: writing contents\n"); | 		printf("Error: writing contents\n"); | ||||||
| 		ret = -EIO; | 		ret = -EIO; | ||||||
| @@ -971,6 +923,5 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, | |||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	printf("writing %s\n", filename); | 	return file_fat_write_at(filename, offset, buffer, maxsize, actwrite); | ||||||
| 	return do_fat_write(filename, buffer, maxsize, actwrite); |  | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user