Implement a simple FAT file rename.

Signed-off-by: Burak Gerz <bu...@gerz.io>

---

 fs/fat/fat_write.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++
 fs/fs.c            | 30 ++++++++++++++
 include/fat.h      |  1 +
 include/fs.h       |  2 +
 4 files changed, 132 insertions(+)

diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
index ea877ee917..acd0e22652 100644
--- a/fs/fat/fat_write.c
+++ b/fs/fat/fat_write.c
@@ -1813,3 +1813,102 @@ exit:
        free(dotdent);
        return ret;
 }
+
+int file_fat_rename(const char *path, const char *new_filename)
+{
+       char *dirname, *basename;
+       char path_copy[VFAT_MAXLEN_BYTES];
+       char new_path[VFAT_MAXLEN_BYTES];
+       dir_entry *dentry_src, *dentry_dst;
+       fsdata src_datablock = { .fatbuf = NULL };
+       fsdata dst_datablock = { .fatbuf = NULL };
+       fat_itr *src_itr = NULL;
+       fat_itr *dst_itr = NULL;
+       loff_t actwrite;
+       int ret;
+       void *buffer = &actwrite;
+
+       if (strlen(new_filename) > VFAT_MAXLEN_BYTES)
+               return -EINVAL;
+       strcpy(path_copy, path);
+       split_filename(path_copy, &dirname, &basename);
+       strcpy(new_path, dirname);
+       strcat(new_path, "/");
+       strcat(new_path, new_filename);
+       src_itr = malloc_cache_aligned(sizeof(*src_itr));
+               if (!src_itr)
+                       goto exit;
+       dst_itr = malloc_cache_aligned(sizeof(*dst_itr));
+               if (!dst_itr)
+                       goto exit;
+       ret = fat_itr_root(src_itr, &src_datablock);
+       if (ret)
+               goto exit;
+       ret = fat_itr_root(dst_itr, &dst_datablock);
+       if (ret)
+               goto exit;
+       ret = fat_itr_resolve(src_itr, dirname, TYPE_DIR);
+       if (ret)
+               goto exit;
+       dentry_src = find_directory_entry(src_itr, (char *)basename);
+       if (!dentry_src)
+               goto exit;
+
+       dst_datablock.fatbuf = NULL;
+       fat_itr_root(dst_itr, &dst_datablock);
+       ret = fat_itr_resolve(dst_itr, dirname, TYPE_DIR);
+       if (ret)
+               goto exit;
+       dentry_dst = find_directory_entry(dst_itr, (char *)new_filename);
+       if (dentry_dst)
+               goto exit;
+       ret = file_fat_write(new_path, buffer, 0, 0, &actwrite);
+       if (ret)
+               goto exit;
+       dst_datablock.fatbuf = NULL;
+       fat_itr_root(dst_itr, &dst_datablock);
+       ret = fat_itr_resolve(dst_itr, dirname, TYPE_DIR);
+       if (ret)
+               goto exit;
+       dentry_dst = find_directory_entry(dst_itr, (char *)new_filename);
+       if (!dentry_dst)
+               goto exit;
+       dentry_dst->starthi = dentry_src->starthi;
+       dentry_dst->start = dentry_src->start;
+       dentry_dst->size = dentry_src->size;
+       ret = flush_dir(dst_itr);
+       if (ret)
+               return -1;
+       src_datablock.fatbuf = NULL;
+       ret = fat_itr_root(src_itr, &src_datablock);
+       if (ret)
+               goto exit;
+       ret = fat_itr_resolve(src_itr, dirname, TYPE_DIR);
+       if (ret)
+               goto exit;
+       dentry_src = find_directory_entry(src_itr, (char *)basename);
+       if (!dentry_src)
+               goto exit;
+       dir_entry *dent = src_itr->dent;
+
+       if (src_itr->clust != src_itr->dent_clust) {
+               ret = fat_move_to_cluster(src_itr, src_itr->dent_clust);
+               if (ret)
+                       goto exit;
+       }
+       src_itr->dent = src_itr->dent_start;
+       src_itr->remaining = src_itr->dent_rem;
+       dent = src_itr->dent_start;
+       if ((dent->attr & ATTR_VFAT) == ATTR_VFAT &&
+           (dent->nameext.name[0] & LAST_LONG_ENTRY_MASK)) {
+               ret = delete_long_name(src_itr);
+               if (ret)
+                       goto exit;
+       }
+       delete_single_dentry(src_itr);
+       ret = flush_dir(src_itr);
+exit:
+       free(src_itr);
+       free(dst_itr);
+       return ret;
+}
diff --git a/fs/fs.c b/fs/fs.c
index 21a23efd93..3024bd2cec 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -118,6 +118,11 @@ static inline int fs_ln_unsupported(const char *filename, 
const char *target)
        return -1;
 }
 
+static inline int fs_rename_unsupported(const char *filename, const char 
*target)
+{
+       return -1;
+}
+
 static inline void fs_close_unsupported(void)
 {
 }
@@ -183,6 +188,7 @@ struct fstype_info {
        int (*unlink)(const char *filename);
        int (*mkdir)(const char *dirname);
        int (*ln)(const char *filename, const char *target);
+       int (*rename)(const char *old_filename_path, const char *new_filename);
 };
 
 static struct fstype_info fstypes[] = {
@@ -201,6 +207,7 @@ static struct fstype_info fstypes[] = {
                .write = file_fat_write,
                .unlink = fat_unlink,
                .mkdir = fat_mkdir,
+               .rename = file_fat_rename,
 #else
                .write = fs_write_unsupported,
                .unlink = fs_unlink_unsupported,
@@ -222,6 +229,7 @@ static struct fstype_info fstypes[] = {
                .probe = ext4fs_probe,
                .close = ext4fs_close,
                .ls = fs_ls_generic,
+               .rename = fs_rename_unsupported,
                .exists = ext4fs_exists,
                .size = ext4fs_size,
                .read = ext4_read_file,
@@ -247,6 +255,7 @@ static struct fstype_info fstypes[] = {
                .null_dev_desc_ok = true,
                .probe = sandbox_fs_set_blk_dev,
                .close = sandbox_fs_close,
+               .rename = fs_rename_unsupported,
                .ls = sandbox_fs_ls,
                .exists = sandbox_fs_exists,
                .size = sandbox_fs_size,
@@ -266,6 +275,7 @@ static struct fstype_info fstypes[] = {
                .null_dev_desc_ok = true,
                .probe = smh_fs_set_blk_dev,
                .close = fs_close_unsupported,
+               .rename = fs_rename_unsupported,
                .ls = fs_ls_unsupported,
                .exists = fs_exists_unsupported,
                .size = smh_fs_size,
@@ -284,6 +294,7 @@ static struct fstype_info fstypes[] = {
                .fstype = FS_TYPE_UBIFS,
                .name = "ubifs",
                .null_dev_desc_ok = true,
+               .rename = fs_rename_unsupported,
                .probe = ubifs_set_blk_dev,
                .close = ubifs_close,
                .ls = ubifs_ls,
@@ -305,6 +316,7 @@ static struct fstype_info fstypes[] = {
                .fstype = FS_TYPE_BTRFS,
                .name = "btrfs",
                .null_dev_desc_ok = false,
+               .rename = fs_rename_unsupported,
                .probe = btrfs_probe,
                .close = btrfs_close,
                .ls = btrfs_ls,
@@ -327,6 +339,7 @@ static struct fstype_info fstypes[] = {
                .null_dev_desc_ok = false,
                .probe = sqfs_probe,
                .opendir = sqfs_opendir,
+               .rename = fs_rename_unsupported,
                .readdir = sqfs_readdir,
                .ls = fs_ls_generic,
                .read = sqfs_read,
@@ -348,6 +361,7 @@ static struct fstype_info fstypes[] = {
                .null_dev_desc_ok = false,
                .probe = erofs_probe,
                .opendir = erofs_opendir,
+               .rename = fs_rename_unsupported,
                .readdir = erofs_readdir,
                .ls = fs_ls_generic,
                .read = erofs_read,
@@ -369,6 +383,7 @@ static struct fstype_info fstypes[] = {
                .probe = fs_probe_unsupported,
                .close = fs_close_unsupported,
                .ls = fs_ls_unsupported,
+               .rename = fs_rename_unsupported,
                .exists = fs_exists_unsupported,
                .size = fs_size_unsupported,
                .read = fs_read_unsupported,
@@ -697,6 +712,21 @@ int fs_mkdir(const char *dirname)
        return ret;
 }
 
+int fs_rename(const char *path, const char *new_filename)
+{
+       struct fstype_info *info = fs_get_info(fs_type);
+       int ret;
+
+       ret = info->rename(path, new_filename);
+       if (ret < 0) {
+               log_err("** Unable to rename from %s to %s **\n", path, 
new_filename);
+           ret = -1;
+       }
+       fs_close();
+
+       return ret;
+}
+
 int fs_ln(const char *fname, const char *target)
 {
        struct fstype_info *info = fs_get_info(fs_type);
diff --git a/include/fat.h b/include/fat.h
index 3dce99a23c..1155e59c68 100644
--- a/include/fat.h
+++ b/include/fat.h
@@ -208,6 +208,7 @@ void fat_closedir(struct fs_dir_stream *dirs);
 int fat_unlink(const char *filename);
 int fat_mkdir(const char *dirname);
 void fat_close(void);
+int file_fat_rename(const char *filename, const char *buffer);
 void *fat_next_cluster(fat_itr *itr, unsigned int *nbytes);
 
 /**
diff --git a/include/fs.h b/include/fs.h
index 2474880385..c8d0eb41c9 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -165,6 +165,8 @@ 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);
 
+int fs_rename(const char *path, const char *filename);
+
 /*
  * Directory entry types, matches the subset of DT_x in posix readdir()
  * which apply to u-boot.
-- 
2.45.2

Reply via email to