From: AKASHI Takahiro <takahiro.akashi@linaro.org>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 1/1] fs: fat: write with non-zero offset
Date: Fri, 29 Jun 2018 05:45:21 +0900 [thread overview]
Message-ID: <20180628204517.GA17245@fireball> (raw)
In-Reply-To: <3c25a3a8-0ce6-b08c-b2c4-6d571339c2a7@gmx.de>
Hey Heinrich,
On Thu, Jun 28, 2018 at 08:14:17PM +0200, Heinrich Schuchardt wrote:
> This relates to a patch in
> https://git.linaro.org/people/takahiro.akashi/u-boot.git
> branch efi/for_sct.
Thanks for your comment, but
please don't cite and post my changes from this branch
*in any form*. It's just not intended to do so.
I wanna submit it as several separate series once I finish
major re-work.
For the meantime, I dropped the branch.
-Takahiro AKASHI
> On 06/13/2018 08:32 AM, AKASHI Takahiro wrote:
> > ---
> > fs/fat/fat_write.c | 385 +++++++++++++++++++++++++++++++++++----------
> > 1 file changed, 299 insertions(+), 86 deletions(-)
> >
> > diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
> > index a930b66f28..7e63646655 100644
> > --- a/fs/fat/fat_write.c
> > +++ b/fs/fat/fat_write.c
> > @@ -445,6 +445,119 @@ set_cluster(fsdata *mydata, __u32 clustnum, __u8 *buffer,
> > return 0;
> > }
> >
> > +static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
> > +
> > +/*
> > + * Read and modify data on existing and consecutive cluster blocks
> > + */
> > +static int
> > +get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
> > + loff_t size, loff_t *gotsize)
> > +{
> > + unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
> > + __u32 startsect;
> > + loff_t wsize;
> > + int clustcount, i, ret;
> > +
> > + *gotsize = 0;
> > + if (!size)
> > + return 0;
> > +
> > + assert(pos < bytesperclust);
> > + startsect = clust_to_sect(mydata, clustnum);
> > +
> > + debug("clustnum: %d, startsect: %d, pos: %lld\n", clustnum, startsect,
> > + pos);
> > +
> > + /* partial write at begining */
> > + if (pos) {
> > + wsize = min(bytesperclust - pos, size);
> > + ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
> > + if (ret != mydata->clust_size) {
> > + debug("Error reading data (got %d)\n", ret);
> > + return -1;
> > + }
> > +
> > + memcpy(tmpbuf_cluster + pos, buffer, wsize);
> > + ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
> > + if (ret != mydata->clust_size) {
> > + debug("Error writing data (got %d)\n", ret);
> > + return -1;
> > + }
> > +
> > + size -= wsize;
> > + buffer += wsize;
> > + *gotsize += wsize;
> > +
> > + startsect += mydata->clust_size;
> > +
> > + if (!size)
> > + return 0;
> > + }
> > +
> > + /* full-cluster write */
> > + if (size >= bytesperclust) {
> > + clustcount = size / bytesperclust;
>
> Hello Takahiro,
>
> the line above should read
> + clustcount = lldiv(size, bytesperclust);
>
> Otherwise I get an error
>
> undefined reference to `__divdi3'
>
> with qemu_x86_defconfig and gcc 7.3.0.
>
> Best regards
>
> Heinrich
>
> > +
> > + if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
> > + wsize = clustcount * bytesperclust;
> > + ret = disk_write(startsect,
> > + clustcount * mydata->clust_size,
> > + buffer);
> > + if (ret != clustcount * mydata->clust_size) {
> > + debug("Error writing data (got %d)\n", ret);
> > + return -1;
> > + }
> > +
> > + size -= wsize;
> > + buffer += wsize;
> > + *gotsize += wsize;
> > +
> > + startsect += clustcount * mydata->clust_size;
> > + } else {
> > + for (i = 0; i < clustcount; i++) {
> > + memcpy(tmpbuf_cluster, buffer, bytesperclust);
> > + ret = disk_write(startsect, mydata->clust_size,
> > + tmpbuf_cluster);
> > + if (ret != mydata->clust_size) {
> > + debug("Error writing data (got %d)\n", ret);
> > + return -1;
> > + }
> > +
> > + size -= bytesperclust;
> > + buffer += bytesperclust;
> > + *gotsize += bytesperclust;
> > +
> > + startsect += mydata->clust_size;
> > + }
> > + }
> > + }
> > +
> > + /* partial write at end */
> > + if (size) {
> > + wsize = size;
> > + ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
> > + if (ret != mydata->clust_size) {
> > + debug("Error reading data (got %d)\n", ret);
> > + return -1;
> > + }
> > + memcpy(tmpbuf_cluster, buffer, wsize);
> > + ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
> > + if (ret != mydata->clust_size) {
> > + debug("Error writing data (got %d)\n", ret);
> > + return -1;
> > + }
> > +
> > + size -= wsize;
> > + buffer += wsize;
> > + *gotsize += wsize;
> > + }
> > +
> > + assert(!size);
> > +
> > + return 0;
> > +}
> > +
> > /*
> > * Find the first empty cluster
> > */
> > @@ -523,6 +636,18 @@ 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);
> > +}
> > +
> > /*
> > * Write at most 'maxsize' bytes from 'buffer' into
> > * the file associated with 'dentptr'
> > @@ -530,31 +655,164 @@ 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,
> > +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;
> > + loff_t cur_pos, offset, actsize, wsize;
> >
> > *gotsize = 0;
> > - debug("Filesize: %llu bytes\n", filesize);
> > -
> > - if (maxsize > 0 && filesize > maxsize)
> > - filesize = maxsize;
> > + filesize = pos + maxsize;
> >
> > debug("%llu bytes\n", filesize);
> >
> > + if (!filesize) {
> > + if (!curclust)
> > + return 0;
> > + if (!CHECK_CLUST(curclust, mydata->fatsize) ||
> > + IS_LAST_CLUST(curclust, mydata->fatsize)) {
> > + clear_fatent(mydata, curclust);
> > + set_start_cluster(mydata, dentptr, 0);
> > + return 0;
> > + }
> > + debug("curclust: 0x%x\n", curclust);
> > + debug("Invalid FAT entry\n");
> > + return -1;
> > + }
> > +
> > if (!curclust) {
> > - if (filesize) {
> > - debug("error: nonempty clusterless file!\n");
> > + assert(pos == 0);
> > + goto set_clusters;
> > + }
> > +
> > + /* go to cluster at pos */
> > + cur_pos = bytesperclust;
> > + while (1) {
> > + if (pos <= cur_pos)
> > + break;
> > + if (IS_LAST_CLUST(curclust, mydata->fatsize))
> > + break;
> > +
> > + newclust = get_fatent(mydata, curclust);
> > + if (!IS_LAST_CLUST(newclust, mydata->fatsize) &&
> > + CHECK_CLUST(newclust, mydata->fatsize)) {
> > + debug("curclust: 0x%x\n", curclust);
> > + debug("Invalid FAT entry\n");
> > return -1;
> > }
> > +
> > + cur_pos += bytesperclust;
> > + curclust = newclust;
> > + }
> > + if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
> > + assert(pos == cur_pos);
> > + goto set_clusters;
> > + }
> > +
> > + assert(pos < cur_pos);
> > + cur_pos -= bytesperclust;
> > +
> > + /* overwrite */
> > + assert(IS_LAST_CLUST(curclust, mydata->fatsize) ||
> > + !CHECK_CLUST(curclust, mydata->fatsize));
> > +
> > + while (1) {
> > + /* search for allocated consecutive clusters */
> > + actsize = bytesperclust;
> > + endclust = curclust;
> > + while (1) {
> > + if (filesize <= (cur_pos + actsize))
> > + break;
> > +
> > + newclust = get_fatent(mydata, endclust);
> > +
> > + if (IS_LAST_CLUST(newclust, mydata->fatsize))
> > + break;
> > + if (CHECK_CLUST(newclust, mydata->fatsize)) {
> > + debug("curclust: 0x%x\n", curclust);
> > + debug("Invalid FAT entry\n");
> > + return -1;
> > + }
> > +
> > + actsize += bytesperclust;
> > + endclust = newclust;
> > + }
> > +
> > + /* overwrite to <curclust..endclust> */
> > + if (pos < cur_pos)
> > + offset = 0;
> > + else
> > + offset = pos - cur_pos;
> > + wsize = min(cur_pos + actsize, filesize) - pos;
> > + if (get_set_cluster(mydata, curclust, offset, buffer, wsize,
> > + &actsize)) {
> > + printf("Error get-and-setting cluster\n");
> > + return -1;
> > + }
> > + buffer += wsize;
> > + *gotsize += wsize;
> > + cur_pos += offset + wsize;
> > +
> > + if (filesize <= cur_pos)
> > + break;
> > +
> > + /* CHECK: newclust = get_fatent(mydata, endclust); */
> > +
> > + if (IS_LAST_CLUST(newclust, mydata->fatsize))
> > + /* no more clusters */
> > + break;
> > +
> > + curclust = newclust;
> > + }
> > +
> > + if (filesize <= cur_pos) {
> > + /* no more write */
> > + newclust = get_fatent(mydata, endclust);
> > + if (!IS_LAST_CLUST(newclust, mydata->fatsize)) {
> > + /* truncate the rest */
> > + clear_fatent(mydata, newclust);
> > +
> > + /* Mark end of file in FAT */
> > + if (mydata->fatsize == 12)
> > + newclust = 0xfff;
> > + else if (mydata->fatsize == 16)
> > + newclust = 0xffff;
> > + else if (mydata->fatsize == 32)
> > + newclust = 0xfffffff;
> > + set_fatent_value(mydata, endclust, newclust);
> > + }
> > +
> > return 0;
> > }
> >
> > + curclust = endclust;
> > + filesize -= cur_pos;
> > + assert (!(cur_pos % bytesperclust));
> > +
> > +set_clusters:
> > + /* allocate and write */
> > + assert(!pos);
> > +
> > + /* Assure that curclust is valid */
> > + if (!curclust) {
> > + curclust = find_empty_cluster(mydata);
> > + set_start_cluster(mydata, dentptr, curclust);
> > + } else {
> > + newclust = get_fatent(mydata, curclust);
> > +
> > + if (IS_LAST_CLUST(newclust, mydata->fatsize)) {
> > + newclust = determine_fatent(mydata, curclust);
> > + set_fatent_value(mydata, curclust, newclust);
> > + curclust = newclust;
> > + } else {
> > + debug("error: something wrong\n");
> > + return -1;
> > + }
> > + }
> > +
> > actsize = bytesperclust;
> > endclust = curclust;
> > do {
> > @@ -563,6 +821,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)) {
> > @@ -609,18 +868,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;
> > }
> >
> > /*
> > @@ -637,6 +886,7 @@ static void fill_dentry(fsdata *mydata, dir_entry *dentptr,
> > set_name(dentptr, filename);
> > }
> >
> > +#if 0 /* TODO: need re-work */
> > /*
> > * Check whether adding a file makes the file system to
> > * exceed the size of the block device
> > @@ -661,6 +911,7 @@ static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
> > return -1;
> > return 0;
> > }
> > +#endif
> >
> > /*
> > * Find a directory entry based on filename or start cluster number
> > @@ -792,11 +1043,10 @@ again:
> > 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;
> > @@ -807,11 +1057,12 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size,
> > char bad[2] = " ";
> > const char illegal[] = "<>:\"/\\|?*";
> >
> > + debug("writing %s\n", filename);
> > +
> > filename_copy = strdup(filename);
> > if (!filename_copy)
> > goto exit;
> > split_filename(filename_copy, &dirname, &basename);
> > -printf(">>> %s -> \"%s\" + \"%s\"\n", filename, dirname, basename);
> > filename = basename;
> >
> > /* Check that the filename is valid */
> > @@ -853,45 +1104,24 @@ printf(">>> %s -> \"%s\" + \"%s\"\n", filename, dirname, basename);
> > retdent = find_directory_entry(itr, l_filename);
> >
> > if (retdent) {
> > - /* 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);
> > - goto exit;
> > - }
> > - }
> > -
> > - ret = clear_fatent(mydata, start_cluster);
> > - if (ret) {
> > - printf("Error: clearing FAT entries\n");
> > - 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");
> > - goto exit;
> > - }
> > -
> > - ret = check_overflow(mydata, start_cluster, size);
> > - if (ret) {
> > - printf("Error: %llu overflow\n", size);
> > - goto exit;
> > - }
> > -
> > - set_start_cluster(mydata, retdent, start_cluster);
> > + /* A file exists */
> > + if (pos == -1)
> > + /* Append to the end */
> > + pos = FAT2CPU32(retdent->size);
> > + if (pos > retdent->size) {
> > + /* No hole allowed */
> > + goto exit;
> > }
> > +
> > + /* Update file size in a directory entry */
> > + retdent->size = cpu_to_le32(pos + size);
> > } else {
> > -/* FIXME: empty_dentptr */
> > + /* Create a new file */
> > + if (pos) {
> > + /* No hole allowed */
> > + ret = -EINVAL;
> > + goto exit;
> > + }
> > memset(itr->dent, 0, sizeof(*itr->dent));
> >
> > /* Set short name to set alias checksum field in dir_slot */
> > @@ -901,30 +1131,13 @@ printf(">>> %s -> \"%s\" + \"%s\"\n", filename, dirname, basename);
> > goto exit;
> > }
> >
> > - if (size) {
> > - ret = start_cluster = find_empty_cluster(mydata);
> > - if (ret < 0) {
> > - printf("Error: finding empty cluster\n");
> > - goto exit;
> > - }
> > -
> > - ret = check_overflow(mydata, start_cluster, size);
> > - if (ret) {
> > - printf("Error: %llu overflow\n", size);
> > - goto exit;
> > - }
> > - } else {
> > - start_cluster = 0;
> > - }
> > -
> > /* Set attribute as archieve 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");
> > goto exit;
> > @@ -954,11 +1167,11 @@ exit:
> > int file_fat_write(const char *filename, void *buffer, loff_t offset,
> > loff_t maxsize, loff_t *actwrite)
> > {
> > - if (offset != 0) {
> > - printf("Error: non zero offset is currently not supported.\n");
> > - return -1;
> > - }
> > + int ret;
> >
> > - printf("writing %s\n", filename);
> > - return do_fat_write(filename, buffer, maxsize, actwrite);
> > + ret = file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
> > + if (ret)
> > + printf("** Unable to write file %s **\n", filename);
> > +
> > + return ret;
> > }
> >
>
prev parent reply other threads:[~2018-06-28 20:45 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-06-28 18:14 [U-Boot] [PATCH 1/1] fs: fat: write with non-zero offset Heinrich Schuchardt
2018-06-28 20:45 ` AKASHI Takahiro [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180628204517.GA17245@fireball \
--to=takahiro.akashi@linaro.org \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.