mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +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; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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 | ||||
|  * the file associated with 'dentptr' | ||||
| @@ -535,29 +571,36 @@ static int clear_fatent(fsdata *mydata, __u32 entry) | ||||
|  * or return -1 on fatal errors. | ||||
|  */ | ||||
| static int | ||||
| set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, | ||||
| 	      loff_t maxsize, loff_t *gotsize) | ||||
| set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer, | ||||
| 	     loff_t maxsize, loff_t *gotsize) | ||||
| { | ||||
| 	loff_t filesize = FAT2CPU32(dentptr->size); | ||||
| 	loff_t filesize; | ||||
| 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size; | ||||
| 	__u32 curclust = START(dentptr); | ||||
| 	__u32 endclust = 0, newclust = 0; | ||||
| 	loff_t actsize; | ||||
|  | ||||
| 	*gotsize = 0; | ||||
| 	debug("Filesize: %llu bytes\n", filesize); | ||||
|  | ||||
| 	if (maxsize > 0 && filesize > maxsize) | ||||
| 		filesize = maxsize; | ||||
| 	filesize = maxsize; | ||||
|  | ||||
| 	debug("%llu bytes\n", filesize); | ||||
|  | ||||
| 	if (!curclust) { | ||||
| 		if (filesize) { | ||||
| 			debug("error: nonempty clusterless file!\n"); | ||||
| 	if (curclust) { | ||||
| 		/* | ||||
| 		 * release already-allocated clusters anyway | ||||
| 		 */ | ||||
| 		if (clear_fatent(mydata, curclust)) { | ||||
| 			printf("Error: clearing FAT entries\n"); | ||||
| 			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; | ||||
| @@ -568,6 +611,7 @@ set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer, | ||||
| 			newclust = determine_fatent(mydata, endclust); | ||||
|  | ||||
| 			if ((newclust - 1) != endclust) | ||||
| 				/* write to <curclust..endclust> */ | ||||
| 				goto getit; | ||||
|  | ||||
| 			if (CHECK_CLUST(newclust, mydata->fatsize)) { | ||||
| @@ -614,18 +658,8 @@ getit: | ||||
| 		actsize = bytesperclust; | ||||
| 		curclust = endclust = newclust; | ||||
| 	} while (1); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -642,31 +676,6 @@ static void fill_dentry(fsdata *mydata, dir_entry *dentptr, | ||||
| 	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 | ||||
|  * If the directory entry is not found, | ||||
| @@ -784,11 +793,10 @@ static int normalize_longname(char *l_filename, const char *filename) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int do_fat_write(const char *filename, void *buffer, loff_t size, | ||||
| 			loff_t *actwrite) | ||||
| int file_fat_write_at(const char *filename, loff_t pos, void *buffer, | ||||
| 		      loff_t size, loff_t *actwrite) | ||||
| { | ||||
| 	dir_entry *retdent; | ||||
| 	__u32 start_cluster; | ||||
| 	fsdata datablock = { .fatbuf = NULL, }; | ||||
| 	fsdata *mydata = &datablock; | ||||
| 	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 l_filename[VFAT_MAXLEN_BYTES]; | ||||
|  | ||||
| 	debug("writing %s\n", filename); | ||||
|  | ||||
| 	filename_copy = strdup(filename); | ||||
| 	if (!filename_copy) | ||||
| 		return -ENOMEM; | ||||
| @@ -839,47 +849,8 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, | ||||
| 			goto exit; | ||||
| 		} | ||||
|  | ||||
| 		/* Update file size and start_cluster in a directory entry */ | ||||
| 		retdent->size = cpu_to_le32(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); | ||||
| 		} | ||||
| 		/* Update file size in a directory entry */ | ||||
| 		retdent->size = cpu_to_le32(pos + size); | ||||
| 	} else { | ||||
| 		/* Create a new file */ | ||||
|  | ||||
| @@ -907,32 +878,13 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, | ||||
| 			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 */ | ||||
| 		fill_dentry(itr->fsdata, itr->dent, filename, | ||||
| 			    start_cluster, size, 0x20); | ||||
| 		fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20); | ||||
|  | ||||
| 		retdent = itr->dent; | ||||
| 	} | ||||
|  | ||||
| 	ret = set_contents(mydata, retdent, buffer, size, actwrite); | ||||
| 	ret = set_contents(mydata, retdent, pos, buffer, size, actwrite); | ||||
| 	if (ret < 0) { | ||||
| 		printf("Error: writing contents\n"); | ||||
| 		ret = -EIO; | ||||
| @@ -971,6 +923,5 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	printf("writing %s\n", filename); | ||||
| 	return do_fat_write(filename, buffer, maxsize, actwrite); | ||||
| 	return file_fat_write_at(filename, offset, buffer, maxsize, actwrite); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user