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>
This commit is contained in:
parent
e2519daf5c
commit
f8240ce95d
@ -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;
|
||||
|
3
fs/fs.c
3
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
|
||||
|
@ -203,6 +203,7 @@ int fat_read_file(const char *filename, void *buf, loff_t offset, loff_t len,
|
||||
int fat_opendir(const char *filename, struct fs_dir_stream **dirsp);
|
||||
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);
|
||||
void fat_close(void);
|
||||
#endif /* _FAT_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user