fat: write: fix broken write to fragmented files
authorMarek Szyprowski <m.szyprowski@samsung.com>
Fri, 13 Sep 2019 11:54:08 +0000 (13:54 +0200)
committerJaehoon Chung <jh80.chung@samsung.com>
Thu, 10 Oct 2019 04:39:03 +0000 (13:39 +0900)
The code for handing file overwrite incorrectly assumed that the file on
disk is always contiguous. This resulted in corrupting disk structure
every time when write to existing fragmented file happened. Fix this
by adding proper check for cluster discontinuity and adjust chunk size
on each partial write.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Oleksandr Suvorov <oleksandr.suvorov@toradex.com>
Reviewed-by: Lukasz Majewski <lukma@denx.de>
Change-Id: Ic32563cd9e1fc34efd153d94ecd34de4de80e8b2
Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
fs/fat/fat_write.c

index 729cf39630d35107b178859803e4b5e7ed5f055b..6cfa5b4565245551a8189a967e60a00b82017f37 100644 (file)
@@ -794,6 +794,8 @@ set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
 
                        newclust = get_fatent(mydata, endclust);
 
+                       if ((newclust - 1) != endclust)
+                               break;
                        if (IS_LAST_CLUST(newclust, mydata->fatsize))
                                break;
                        if (CHECK_CLUST(newclust, mydata->fatsize)) {
@@ -811,7 +813,7 @@ set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
                        offset = 0;
                else
                        offset = pos - cur_pos;
-               wsize = min(cur_pos + actsize, filesize) - pos;
+               wsize = min_t(unsigned long long, actsize, filesize - cur_pos);
                if (get_set_cluster(mydata, curclust, offset,
                                    buffer, wsize, &actsize)) {
                        printf("Error get-and-setting cluster\n");
@@ -824,8 +826,6 @@ set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
                if (filesize <= cur_pos)
                        break;
 
-               /* CHECK: newclust = get_fatent(mydata, endclust); */
-
                if (IS_LAST_CLUST(newclust, mydata->fatsize))
                        /* no more clusters */
                        break;