summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorAKASHI Takahiro <takahiro.akashi@linaro.org>2018-09-11 15:59:14 +0900
committerAlexander Graf <agraf@suse.de>2018-09-23 21:55:30 +0200
commitf8240ce95d64dbe3a1eb6d5001ba23107c7e7cfe (patch)
tree52baacf53a486ac302d6f26eca8b222b3b8a06ea /fs
parente2519daf5cef63c19ed16ead74e3525f951c24e0 (diff)
fs: fat: support unlink
In this patch, unlink support is added to FAT file system. A directory can be deleted only if it is empty. In this implementation, only a directory entry for a short file name will be removed. So entries for a long file name can and should be reclaimed with fsck. Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/fat/fat_write.c132
-rw-r--r--fs/fs.c3
2 files changed, 134 insertions, 1 deletions
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
index 035469f31c..6d3d2d1abb 100644
--- a/fs/fat/fat_write.c
+++ b/fs/fat/fat_write.c
@@ -1184,6 +1184,138 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset,
return file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
}
+static int fat_dir_entries(fat_itr *itr)
+{
+ fat_itr *dirs;
+ fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
+ /* for FATBUFSIZE */
+ int count;
+
+ dirs = malloc_cache_aligned(sizeof(fat_itr));
+ if (!dirs) {
+ debug("Error: allocating memory\n");
+ count = -ENOMEM;
+ goto exit;
+ }
+
+ /* duplicate fsdata */
+ fat_itr_child(dirs, itr);
+ fsdata = *dirs->fsdata;
+
+ /* allocate local fat buffer */
+ fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
+ if (!fsdata.fatbuf) {
+ debug("Error: allocating memory\n");
+ count = -ENOMEM;
+ goto exit;
+ }
+ fsdata.fatbufnum = -1;
+ dirs->fsdata = &fsdata;
+
+ for (count = 0; fat_itr_next(dirs); count++)
+ ;
+
+exit:
+ free(fsdata.fatbuf);
+ free(dirs);
+ return count;
+}
+
+static int delete_dentry(fat_itr *itr)
+{
+ fsdata *mydata = itr->fsdata;
+ dir_entry *dentptr = itr->dent;
+
+ /* free cluster blocks */
+ clear_fatent(mydata, START(dentptr));
+ if (flush_dirty_fat_buffer(mydata) < 0) {
+ printf("Error: flush fat buffer\n");
+ return -EIO;
+ }
+
+ /*
+ * update a directory entry
+ * TODO:
+ * - long file name support
+ * - find and mark the "new" first invalid entry as name[0]=0x00
+ */
+ memset(dentptr, 0, sizeof(*dentptr));
+ dentptr->name[0] = 0xe5;
+
+ if (set_cluster(mydata, itr->clust, itr->block,
+ mydata->clust_size * mydata->sect_size) != 0) {
+ printf("error: writing directory entry\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int fat_unlink(const char *filename)
+{
+ fsdata fsdata = { .fatbuf = NULL, };
+ fat_itr *itr = NULL;
+ int n_entries, ret;
+ char *filename_copy, *dirname, *basename;
+
+ filename_copy = strdup(filename);
+ split_filename(filename_copy, &dirname, &basename);
+
+ if (!strcmp(dirname, "/") && !strcmp(basename, "")) {
+ printf("Error: cannot remove root\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ itr = malloc_cache_aligned(sizeof(fat_itr));
+ if (!itr) {
+ printf("Error: allocating memory\n");
+ return -ENOMEM;
+ }
+
+ ret = fat_itr_root(itr, &fsdata);
+ if (ret)
+ goto exit;
+
+ total_sector = fsdata.total_sect;
+
+ ret = fat_itr_resolve(itr, dirname, TYPE_DIR);
+ if (ret) {
+ printf("%s: doesn't exist (%d)\n", dirname, ret);
+ ret = -ENOENT;
+ goto exit;
+ }
+
+ if (!find_directory_entry(itr, basename)) {
+ printf("%s: doesn't exist\n", basename);
+ ret = -ENOENT;
+ goto exit;
+ }
+
+ if (fat_itr_isdir(itr)) {
+ n_entries = fat_dir_entries(itr);
+ if (n_entries < 0) {
+ ret = n_entries;
+ goto exit;
+ }
+ if (n_entries > 2) {
+ printf("Error: directory is not empty: %d\n",
+ n_entries);
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+ ret = delete_dentry(itr);
+
+exit:
+ free(fsdata.fatbuf);
+ free(itr);
+ free(filename_copy);
+
+ return ret;
+}
+
int fat_mkdir(const char *new_dirname)
{
dir_entry *retdent;
diff --git a/fs/fs.c b/fs/fs.c
index ba9a65166c..adae98d021 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -170,16 +170,17 @@ static struct fstype_info fstypes[] = {
.read = fat_read_file,
#ifdef CONFIG_FAT_WRITE
.write = file_fat_write,
+ .unlink = fat_unlink,
.mkdir = fat_mkdir,
#else
.write = fs_write_unsupported,
+ .unlink = fs_unlink_unsupported,
.mkdir = fs_mkdir_unsupported,
#endif
.uuid = fs_uuid_unsupported,
.opendir = fat_opendir,
.readdir = fat_readdir,
.closedir = fat_closedir,
- .unlink = fs_unlink_unsupported,
},
#endif
#ifdef CONFIG_FS_EXT4