[PATCH 2/2] fs: fat: Implement FAT file rename
Burak Gerz
burak at gerz.io
Thu Dec 12 23:06:29 CET 2024
Implement a simple FAT file rename.
Signed-off-by: Burak Gerz <burak at 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
More information about the U-Boot
mailing list