mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00: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:
parent
4ced2039dc
commit
704df6aa0a
1 changed files with 65 additions and 114 deletions
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue