From mboxrd@z Thu Jan 1 00:00:00 1970 From: AKASHI Takahiro Date: Fri, 29 Jun 2018 05:45:21 +0900 Subject: [U-Boot] [PATCH 1/1] fs: fat: write with non-zero offset In-Reply-To: <3c25a3a8-0ce6-b08c-b2c4-6d571339c2a7@gmx.de> References: <3c25a3a8-0ce6-b08c-b2c4-6d571339c2a7@gmx.de> Message-ID: <20180628204517.GA17245@fireball> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.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 */ > > + 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 */ > > 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; > > } > > >