This implementation currently does not support moving files between directories.
Signed-off-by: Daniel Venzin <daniel.ven...@mt.com> --- Changes in v3: - Abort the rename if the destination is a path instead of a file Changes in v2: - Separate the rename implementation from changes in the filesystem layer - Eliminate code duplication with delete_dentry_long(..) - Ensure that the source file exists, but not the destination file - Free the fatbuf if it has been reinitialized with fat_itr_root - Delete orphaned FAT entry after copying file metadata fs/fat/fat_write.c | 125 +++++++++++++++++++++++++++++++++++++++++++++ fs/fs.c | 2 +- include/fat.h | 1 + 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index c78b80e0b7a..6e4ff7c57d4 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -1821,3 +1821,128 @@ exit: free(dotdent); return ret; } + +int file_fat_rename(const char *path, const char *new_fname) +{ + fsdata datablock = { .fatbuf = NULL, }; + fat_itr *itr = NULL; + + dir_entry *dentry; + + char new_path[VFAT_MAXLEN_BYTES]; + char *new_fname_copy = NULL, *new_fname_dirname, *new_fname_basename; + char *path_copy = NULL, *path_dirname, *path_basename; + + loff_t actwrite; + + __u16 starthi, start; + __u32 size, entry; + + int ret = -1; + + new_fname_copy = strdup(new_fname); + if (!new_fname_copy) + goto exit; + + split_filename(new_fname_copy, &new_fname_dirname, &new_fname_basename); + + if (strlen(new_fname_dirname) > 1 || + (strcmp(new_fname_dirname, "/") != 0 && + strcmp(new_fname_dirname, ".") != 0)) { + ret = -EINVAL; + goto exit; + } + + path_copy = strdup(path); + if (!path_copy) + goto exit; + + split_filename(path_copy, &path_dirname, &path_basename); + snprintf(new_path, sizeof(new_path), "%s/%s", path_dirname, new_fname_basename); + + if (!fat_exists(path)) { + ret = -ENOENT; + goto exit; + } + + if (fat_exists(new_path)) { + ret = -EEXIST; + goto exit; + } + + ret = file_fat_write(new_path, &actwrite, 0, 0, &actwrite); + if (ret) + goto exit; + + itr = malloc_cache_aligned(sizeof(*itr)); + if (!itr) { + ret = -ENOMEM; + goto exit; + } + + ret = fat_itr_root(itr, &datablock); + if (ret) + goto exit; + + ret = fat_itr_resolve(itr, path, TYPE_FILE); + if (ret) + goto exit; + + dentry = itr->dent; + + starthi = dentry->starthi; + start = dentry->start; + size = dentry->size; + + free(datablock.fatbuf); + datablock.fatbuf = NULL; + + ret = fat_itr_root(itr, &datablock); + if (ret) + goto exit; + + ret = fat_itr_resolve(itr, new_path, TYPE_FILE); + if (ret) + goto exit; + + dentry = itr->dent; + + fsdata *mydata = itr->fsdata; + + entry = START(dentry); + + dentry->starthi = starthi; + dentry->start = start; + dentry->size = size; + + ret = flush_dir(itr); + if (ret) + goto exit; + + clear_fatent(mydata, entry); + if (flush_dirty_fat_buffer(mydata) < 0) { + printf("Error: flush fat buffer\n"); + ret = -EIO; + goto exit; + } + + free(datablock.fatbuf); + datablock.fatbuf = NULL; + + ret = fat_itr_root(itr, &datablock); + if (ret) + goto exit; + + ret = fat_itr_resolve(itr, path, TYPE_FILE); + if (ret) + goto exit; + + ret = delete_dentry_long(itr, FATENT_CLEAR_SKIP); + +exit: + free(new_fname_copy); + free(path_copy); + free(datablock.fatbuf); + free(itr); + return ret; +} diff --git a/fs/fs.c b/fs/fs.c index b746d05ebcd..3576d5c6644 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -208,7 +208,7 @@ static struct fstype_info fstypes[] = { .write = file_fat_write, .unlink = fat_unlink, .mkdir = fat_mkdir, - .rename = fs_rename_unsupported, + .rename = file_fat_rename, #else .write = fs_write_unsupported, .unlink = fs_unlink_unsupported, diff --git a/include/fat.h b/include/fat.h index 3dce99a23cf..415ebd7b7c8 100644 --- a/include/fat.h +++ b/include/fat.h @@ -207,6 +207,7 @@ int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp); void fat_closedir(struct fs_dir_stream *dirs); int fat_unlink(const char *filename); int fat_mkdir(const char *dirname); +int file_fat_rename(const char *path, const char *new_filename); void fat_close(void); void *fat_next_cluster(fat_itr *itr, unsigned int *nbytes); -- 2.39.5