fs_write() with an offset trims the file at the end of the written
range. Add fs_overwrite() for callers that need to update a part of a
file and keep the rest.

Add an optional overwrite() operation to struct fstype_info and set it
for FAT. A filesystem without it falls back to write(), so nothing
changes for them. fs_write() and fs_overwrite() share the same code.

Signed-off-by: Cedric Hombourger <[email protected]>
---
 fs/fs.c      | 25 ++++++++++++++++++++++---
 include/fs.h | 16 ++++++++++++++++
 2 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/fs/fs.c b/fs/fs.c
index 
b18ccec8cb43d8e575d2c22f7df3a01308f47751..b0bb8d58d2a458f983b9b98a47eefa05416689a1
 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -169,6 +169,9 @@ struct fstype_info {
                    loff_t len, loff_t *actread);
        int (*write)(const char *filename, void *buf, loff_t offset,
                     loff_t len, loff_t *actwrite);
+       /* Optional: like write, but keeps data after the written range */
+       int (*overwrite)(const char *filename, void *buf, loff_t offset,
+                        loff_t len, loff_t *actwrite);
        void (*close)(void);
        int (*uuid)(char *uuid_str);
        /*
@@ -205,6 +208,7 @@ static struct fstype_info fstypes[] = {
                .read = fat_read_file,
 #if CONFIG_IS_ENABLED(FAT_WRITE)
                .write = file_fat_write,
+               .overwrite = file_fat_overwrite,
                .unlink = fat_unlink,
                .mkdir = fat_mkdir,
 #else
@@ -709,15 +713,18 @@ int fs_read(const char *filename, ulong addr, loff_t 
offset, loff_t len,
        return _fs_read(filename, addr, offset, len, 0, actread);
 }
 
-int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
-            loff_t *actwrite)
+static int fs_write_with(bool keep_tail, const char *filename, ulong addr,
+                        loff_t offset, loff_t len, loff_t *actwrite)
 {
        struct fstype_info *info = fs_get_info(fs_type);
        void *buf;
        int ret;
 
        buf = map_sysmem(addr, len);
-       ret = info->write(filename, buf, offset, len, actwrite);
+       if (keep_tail && info->overwrite)
+               ret = info->overwrite(filename, buf, offset, len, actwrite);
+       else
+               ret = info->write(filename, buf, offset, len, actwrite);
        unmap_sysmem(buf);
 
        if (ret < 0 && len != *actwrite) {
@@ -729,6 +736,18 @@ int fs_write(const char *filename, ulong addr, loff_t 
offset, loff_t len,
        return ret;
 }
 
+int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
+            loff_t *actwrite)
+{
+       return fs_write_with(false, filename, addr, offset, len, actwrite);
+}
+
+int fs_overwrite(const char *filename, ulong addr, loff_t offset, loff_t len,
+                loff_t *actwrite)
+{
+       return fs_write_with(true, filename, addr, offset, len, actwrite);
+}
+
 struct fs_dir_stream *fs_opendir(const char *filename)
 {
        struct fstype_info *info = fs_get_info(fs_type);
diff --git a/include/fs.h b/include/fs.h
index 
8afc81c0017da1d7fbc2c3a5c63fb00d2fc1c262..02d357cd62849cc19e15ad3fad08964d9ec66c94
 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -167,6 +167,22 @@ int fs_read(const char *filename, ulong addr, loff_t 
offset, loff_t len,
 int fs_write(const char *filename, ulong addr, loff_t offset, loff_t len,
             loff_t *actwrite);
 
+/**
+ * fs_overwrite() - write into a file without cutting off its tail
+ *
+ * Like fs_write(), but data after the written range stays and the file
+ * size only grows. Filesystem drivers without support fall back to fs_write().
+ *
+ * @filename:  full path of the file to write to
+ * @addr:      address of the buffer to read from
+ * @offset:    offset in the file from where to start writing
+ * @len:       the number of bytes to write
+ * @actwrite:  returns the actual number of bytes written
+ * Return:     0 if OK with valid @actwrite, -1 on error conditions
+ */
+int fs_overwrite(const char *filename, ulong addr, loff_t offset, loff_t len,
+                loff_t *actwrite);
+
 /*
  * Directory entry types, matches the subset of DT_x in posix readdir()
  * which apply to u-boot.

-- 
2.47.3

Reply via email to