From mboxrd@z Thu Jan 1 00:00:00 1970 From: Heinrich Schuchardt Date: Mon, 25 Feb 2019 19:20:46 +0100 Subject: [U-Boot] [BUG] cb8af8af5ba0 "fs: fat: support write with non-zero offset" leads to link error In-Reply-To: <20180911065922.19141-11-takahiro.akashi@linaro.org> References: <20180911065922.19141-1-takahiro.akashi@linaro.org> <20180911065922.19141-11-takahiro.akashi@linaro.org> Message-ID: <6a304ad1-6ff0-10c1-4a51-e065b14c8dca@gmx.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On 9/11/18 8:59 AM, Akashi, Takahiro wrote: > From: AKASHI Takahiro > > In this patch, all the necessary code for allowing for a file offset > at write is implemented. What plays a major roll here is get_set_cluster(), > which, in contrast to its counterpart, set_cluster(), only operates on > already-allocated clusters, overwriting with data. > > So, with a file offset specified, set_contents() seeks and writes data > with set_get_cluster() until the end of a file, and, once it reaches > there, continues writing with set_cluster() for the rest. > > Please note that a file will be trimmed as a result of write operation if > write ends before reaching file's end. This is an intended behavior > in order to maintain compatibility with the current interface. > > Signed-off-by: AKASHI Takahiro > --- > fs/fat/fat_write.c | 288 ++++++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 273 insertions(+), 15 deletions(-) > > diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c > index c22d8c7a46a1..651c7866debc 100644 > --- a/fs/fat/fat_write.c > +++ b/fs/fat/fat_write.c > @@ -450,6 +450,121 @@ 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 beginning */ > + 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 = lldiv(size, bytesperclust); > + > + 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 > */ > @@ -578,26 +693,158 @@ set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer, > 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; > - filesize = maxsize; > + filesize = pos + maxsize; > > debug("%llu bytes\n", filesize); > > - if (curclust) { > - /* > - * release already-allocated clusters anyway > - */ > - if (clear_fatent(mydata, curclust)) { > - printf("Error: clearing FAT entries\n"); > + 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) { > + 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; > } > > - curclust = find_empty_cluster(mydata); > - set_start_cluster(mydata, dentptr, curclust); > + 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)); This patch was merged as cb8af8af5ba03ae8e0a7315b66bfcc46d5c55627 When compiled with DEBUG=1 the line above leads to a link error: fs/fat/fat_write.c:831: undefined reference to `__aeabi_ldivmod' We should use function do_div() for the division. Best regards Heinrich