Message ID | 20180720025723.6736-14-takahiro.akashi@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | fs: fat: extend FAT write operations | expand |
On 07/20/2018 04:57 AM, AKASHI Takahiro wrote: > In this patch, mkdir support is added to FAT file system. > A newly created directory contains only "." and ".." entries. > > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> The patch does set the creation date of the directory according to the real time clock but to 1980-01-01T00:00:00Z. $ ls /mnt/dir1/ -la --full-time drwxr-xr-x 2 root root 2048 1980-01-01 01:00:00.000000000 +0100 dir3 Please, set the time correctly if the real time clock is available. Best regards Heinrich > --- > fs/fat/fat_write.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ > fs/fs.c | 3 +- > include/fat.h | 1 + > 3 files changed, 141 insertions(+), 1 deletion(-) > > diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c > index cc45a33876..781883c9f4 100644 > --- a/fs/fat/fat_write.c > +++ b/fs/fat/fat_write.c > @@ -1185,3 +1185,141 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, > { > return file_fat_write_at(filename, offset, buffer, maxsize, actwrite); > } > + > +int fat_mkdir(const char *new_dirname) > +{ > + dir_entry *retdent; > + fsdata datablock = { .fatbuf = NULL, }; > + fsdata *mydata = &datablock; > + fat_itr *itr = NULL; > + char *dirname_copy, *parent, *dirname; > + char l_dirname[VFAT_MAXLEN_BYTES]; > + int ret = -1; > + loff_t actwrite; > + unsigned int bytesperclust; > + dir_entry *dotdent = NULL; > + > + dirname_copy = strdup(new_dirname); > + if (!dirname_copy) > + goto exit; > + > + split_filename(dirname_copy, &parent, &dirname); > + if (!strlen(dirname)) { > + ret = -EINVAL; > + goto exit; > + } > + > + if (normalize_longname(l_dirname, dirname)) { > + printf("FAT: illegal filename (%s)\n", dirname); > + ret = -EINVAL; > + goto exit; > + } > + > + itr = malloc_cache_aligned(sizeof(fat_itr)); > + if (!itr) { > + ret = -ENOMEM; > + goto exit; > + } > + > + ret = fat_itr_root(itr, &datablock); > + if (ret) > + goto exit; > + > + total_sector = datablock.bs_total_sect; > + if (total_sector == 0) > + total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ > + > + ret = fat_itr_resolve(itr, parent, TYPE_DIR); > + if (ret) { > + printf("%s: doesn't exist (%d)\n", parent, ret); > + goto exit; > + } > + > + retdent = find_directory_entry(itr, l_dirname); > + > + if (retdent) { > + printf("%s: already exists\n", l_dirname); > + ret = -EEXIST; > + goto exit; > + } else { > + if (itr->is_root) { > + /* root dir cannot have "." or ".." */ > + if (!strcmp(l_dirname, ".") || > + !strcmp(l_dirname, "..")) { > + ret = -EINVAL; > + goto exit; > + } > + } > + > + if (!itr->dent) { > + printf("Error: allocating new dir entry\n"); > + ret = -EIO; > + goto exit; > + } > + > + memset(itr->dent, 0, sizeof(*itr->dent)); > + > + /* Set short name to set alias checksum field in dir_slot */ > + set_name(itr->dent, dirname); > + fill_dir_slot(itr, dirname); > + > + /* Set attribute as archieve for regular file */ > + fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0, > + ATTR_DIR | ATTR_ARCH); > + > + retdent = itr->dent; > + } > + > + /* Default entries */ > + bytesperclust = mydata->clust_size * mydata->sect_size; > + dotdent = malloc_cache_aligned(bytesperclust); > + if (!dotdent) { > + ret = -ENOMEM; > + goto exit; > + } > + memset(dotdent, 0, bytesperclust); > + > + memcpy(dotdent[0].name, ". ", 8); > + memcpy(dotdent[0].ext, " ", 3); > + dotdent[0].attr = ATTR_DIR | ATTR_ARCH; > + > + memcpy(dotdent[1].name, ".. ", 8); > + memcpy(dotdent[1].ext, " ", 3); > + dotdent[1].attr = ATTR_DIR | ATTR_ARCH; > + set_start_cluster(mydata, &dotdent[1], itr->start_clust); > + > + ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, bytesperclust, > + &actwrite); > + if (ret < 0) { > + printf("Error: writing contents\n"); > + goto exit; > + } > + /* Write twice for "." */ > + set_start_cluster(mydata, &dotdent[0], START(retdent)); > + ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, bytesperclust, > + &actwrite); > + if (ret < 0) { > + printf("Error: writing contents\n"); > + goto exit; > + } > + > + /* Flush fat buffer */ > + ret = flush_dirty_fat_buffer(mydata); > + if (ret) { > + printf("Error: flush fat buffer\n"); > + goto exit; > + } > + > + /* Write directory table to device */ > + ret = set_cluster(mydata, itr->clust, itr->block, > + mydata->clust_size * mydata->sect_size); > + if (ret) > + printf("Error: writing directory entry\n"); > + > +exit: > + free(dirname_copy); > + free(mydata->fatbuf); > + free(itr); > + free(dotdent); > + return ret; > +} > diff --git a/fs/fs.c b/fs/fs.c > index 3cb6b21fe9..a92e060296 100644 > --- a/fs/fs.c > +++ b/fs/fs.c > @@ -164,14 +164,15 @@ static struct fstype_info fstypes[] = { > .read = fat_read_file, > #ifdef CONFIG_FAT_WRITE > .write = file_fat_write, > + .mkdir = fat_mkdir, > #else > .write = fs_write_unsupported, > + .mkdir = fs_mkdir_unsupported, > #endif > .uuid = fs_uuid_unsupported, > .opendir = fat_opendir, > .readdir = fat_readdir, > .closedir = fat_closedir, > - .mkdir = fs_mkdir_unsupported, > }, > #endif > #ifdef CONFIG_FS_EXT4 > diff --git a/include/fat.h b/include/fat.h > index 295da0f243..039b6e03de 100644 > --- a/include/fat.h > +++ b/include/fat.h > @@ -237,5 +237,6 @@ 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_mkdir(const char *dirname); > void fat_close(void); > #endif /* _FAT_H_ */ >
On Fri, Jul 20, 2018 at 07:14:21PM +0200, Heinrich Schuchardt wrote: > On 07/20/2018 04:57 AM, AKASHI Takahiro wrote: > > In this patch, mkdir support is added to FAT file system. > > A newly created directory contains only "." and ".." entries. > > > > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> > > The patch does set the creation date of the directory according to the > real time clock but to 1980-01-01T00:00:00Z. > > $ ls /mnt/dir1/ -la --full-time > drwxr-xr-x 2 root root 2048 1980-01-01 01:00:00.000000000 +0100 dir3 > > Please, set the time correctly if the real time clock is available. Good point, but I'd like to put this issue into future TODO list as it will end up introducing a new API, such as gettimeofday()? (and this is not a FAT-specific issue.) Thanks, -Takahiro AKASHI > Best regards > > Heinrich > > > --- > > fs/fat/fat_write.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ > > fs/fs.c | 3 +- > > include/fat.h | 1 + > > 3 files changed, 141 insertions(+), 1 deletion(-) > > > > diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c > > index cc45a33876..781883c9f4 100644 > > --- a/fs/fat/fat_write.c > > +++ b/fs/fat/fat_write.c > > @@ -1185,3 +1185,141 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, > > { > > return file_fat_write_at(filename, offset, buffer, maxsize, actwrite); > > } > > + > > +int fat_mkdir(const char *new_dirname) > > +{ > > + dir_entry *retdent; > > + fsdata datablock = { .fatbuf = NULL, }; > > + fsdata *mydata = &datablock; > > + fat_itr *itr = NULL; > > + char *dirname_copy, *parent, *dirname; > > + char l_dirname[VFAT_MAXLEN_BYTES]; > > + int ret = -1; > > + loff_t actwrite; > > + unsigned int bytesperclust; > > + dir_entry *dotdent = NULL; > > + > > + dirname_copy = strdup(new_dirname); > > + if (!dirname_copy) > > + goto exit; > > + > > + split_filename(dirname_copy, &parent, &dirname); > > + if (!strlen(dirname)) { > > + ret = -EINVAL; > > + goto exit; > > + } > > + > > + if (normalize_longname(l_dirname, dirname)) { > > + printf("FAT: illegal filename (%s)\n", dirname); > > + ret = -EINVAL; > > + goto exit; > > + } > > + > > + itr = malloc_cache_aligned(sizeof(fat_itr)); > > + if (!itr) { > > + ret = -ENOMEM; > > + goto exit; > > + } > > + > > + ret = fat_itr_root(itr, &datablock); > > + if (ret) > > + goto exit; > > + > > + total_sector = datablock.bs_total_sect; > > + if (total_sector == 0) > > + total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ > > + > > + ret = fat_itr_resolve(itr, parent, TYPE_DIR); > > + if (ret) { > > + printf("%s: doesn't exist (%d)\n", parent, ret); > > + goto exit; > > + } > > + > > + retdent = find_directory_entry(itr, l_dirname); > > + > > + if (retdent) { > > + printf("%s: already exists\n", l_dirname); > > + ret = -EEXIST; > > + goto exit; > > + } else { > > + if (itr->is_root) { > > + /* root dir cannot have "." or ".." */ > > + if (!strcmp(l_dirname, ".") || > > + !strcmp(l_dirname, "..")) { > > + ret = -EINVAL; > > + goto exit; > > + } > > + } > > + > > + if (!itr->dent) { > > + printf("Error: allocating new dir entry\n"); > > + ret = -EIO; > > + goto exit; > > + } > > + > > + memset(itr->dent, 0, sizeof(*itr->dent)); > > + > > + /* Set short name to set alias checksum field in dir_slot */ > > + set_name(itr->dent, dirname); > > + fill_dir_slot(itr, dirname); > > + > > + /* Set attribute as archieve for regular file */ > > + fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0, > > + ATTR_DIR | ATTR_ARCH); > > + > > + retdent = itr->dent; > > + } > > + > > + /* Default entries */ > > + bytesperclust = mydata->clust_size * mydata->sect_size; > > + dotdent = malloc_cache_aligned(bytesperclust); > > + if (!dotdent) { > > + ret = -ENOMEM; > > + goto exit; > > + } > > + memset(dotdent, 0, bytesperclust); > > + > > + memcpy(dotdent[0].name, ". ", 8); > > + memcpy(dotdent[0].ext, " ", 3); > > + dotdent[0].attr = ATTR_DIR | ATTR_ARCH; > > + > > + memcpy(dotdent[1].name, ".. ", 8); > > + memcpy(dotdent[1].ext, " ", 3); > > + dotdent[1].attr = ATTR_DIR | ATTR_ARCH; > > + set_start_cluster(mydata, &dotdent[1], itr->start_clust); > > + > > + ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, bytesperclust, > > + &actwrite); > > + if (ret < 0) { > > + printf("Error: writing contents\n"); > > + goto exit; > > + } > > + /* Write twice for "." */ > > + set_start_cluster(mydata, &dotdent[0], START(retdent)); > > + ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, bytesperclust, > > + &actwrite); > > + if (ret < 0) { > > + printf("Error: writing contents\n"); > > + goto exit; > > + } > > + > > + /* Flush fat buffer */ > > + ret = flush_dirty_fat_buffer(mydata); > > + if (ret) { > > + printf("Error: flush fat buffer\n"); > > + goto exit; > > + } > > + > > + /* Write directory table to device */ > > + ret = set_cluster(mydata, itr->clust, itr->block, > > + mydata->clust_size * mydata->sect_size); > > + if (ret) > > + printf("Error: writing directory entry\n"); > > + > > +exit: > > + free(dirname_copy); > > + free(mydata->fatbuf); > > + free(itr); > > + free(dotdent); > > + return ret; > > +} > > diff --git a/fs/fs.c b/fs/fs.c > > index 3cb6b21fe9..a92e060296 100644 > > --- a/fs/fs.c > > +++ b/fs/fs.c > > @@ -164,14 +164,15 @@ static struct fstype_info fstypes[] = { > > .read = fat_read_file, > > #ifdef CONFIG_FAT_WRITE > > .write = file_fat_write, > > + .mkdir = fat_mkdir, > > #else > > .write = fs_write_unsupported, > > + .mkdir = fs_mkdir_unsupported, > > #endif > > .uuid = fs_uuid_unsupported, > > .opendir = fat_opendir, > > .readdir = fat_readdir, > > .closedir = fat_closedir, > > - .mkdir = fs_mkdir_unsupported, > > }, > > #endif > > #ifdef CONFIG_FS_EXT4 > > diff --git a/include/fat.h b/include/fat.h > > index 295da0f243..039b6e03de 100644 > > --- a/include/fat.h > > +++ b/include/fat.h > > @@ -237,5 +237,6 @@ 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_mkdir(const char *dirname); > > void fat_close(void); > > #endif /* _FAT_H_ */ > > >
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index cc45a33876..781883c9f4 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -1185,3 +1185,141 @@ int file_fat_write(const char *filename, void *buffer, loff_t offset, { return file_fat_write_at(filename, offset, buffer, maxsize, actwrite); } + +int fat_mkdir(const char *new_dirname) +{ + dir_entry *retdent; + fsdata datablock = { .fatbuf = NULL, }; + fsdata *mydata = &datablock; + fat_itr *itr = NULL; + char *dirname_copy, *parent, *dirname; + char l_dirname[VFAT_MAXLEN_BYTES]; + int ret = -1; + loff_t actwrite; + unsigned int bytesperclust; + dir_entry *dotdent = NULL; + + dirname_copy = strdup(new_dirname); + if (!dirname_copy) + goto exit; + + split_filename(dirname_copy, &parent, &dirname); + if (!strlen(dirname)) { + ret = -EINVAL; + goto exit; + } + + if (normalize_longname(l_dirname, dirname)) { + printf("FAT: illegal filename (%s)\n", dirname); + ret = -EINVAL; + goto exit; + } + + itr = malloc_cache_aligned(sizeof(fat_itr)); + if (!itr) { + ret = -ENOMEM; + goto exit; + } + + ret = fat_itr_root(itr, &datablock); + if (ret) + goto exit; + + total_sector = datablock.bs_total_sect; + if (total_sector == 0) + total_sector = (int)cur_part_info.size; /* cast of lbaint_t */ + + ret = fat_itr_resolve(itr, parent, TYPE_DIR); + if (ret) { + printf("%s: doesn't exist (%d)\n", parent, ret); + goto exit; + } + + retdent = find_directory_entry(itr, l_dirname); + + if (retdent) { + printf("%s: already exists\n", l_dirname); + ret = -EEXIST; + goto exit; + } else { + if (itr->is_root) { + /* root dir cannot have "." or ".." */ + if (!strcmp(l_dirname, ".") || + !strcmp(l_dirname, "..")) { + ret = -EINVAL; + goto exit; + } + } + + if (!itr->dent) { + printf("Error: allocating new dir entry\n"); + ret = -EIO; + goto exit; + } + + memset(itr->dent, 0, sizeof(*itr->dent)); + + /* Set short name to set alias checksum field in dir_slot */ + set_name(itr->dent, dirname); + fill_dir_slot(itr, dirname); + + /* Set attribute as archieve for regular file */ + fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0, + ATTR_DIR | ATTR_ARCH); + + retdent = itr->dent; + } + + /* Default entries */ + bytesperclust = mydata->clust_size * mydata->sect_size; + dotdent = malloc_cache_aligned(bytesperclust); + if (!dotdent) { + ret = -ENOMEM; + goto exit; + } + memset(dotdent, 0, bytesperclust); + + memcpy(dotdent[0].name, ". ", 8); + memcpy(dotdent[0].ext, " ", 3); + dotdent[0].attr = ATTR_DIR | ATTR_ARCH; + + memcpy(dotdent[1].name, ".. ", 8); + memcpy(dotdent[1].ext, " ", 3); + dotdent[1].attr = ATTR_DIR | ATTR_ARCH; + set_start_cluster(mydata, &dotdent[1], itr->start_clust); + + ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, bytesperclust, + &actwrite); + if (ret < 0) { + printf("Error: writing contents\n"); + goto exit; + } + /* Write twice for "." */ + set_start_cluster(mydata, &dotdent[0], START(retdent)); + ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent, bytesperclust, + &actwrite); + if (ret < 0) { + printf("Error: writing contents\n"); + goto exit; + } + + /* Flush fat buffer */ + ret = flush_dirty_fat_buffer(mydata); + if (ret) { + printf("Error: flush fat buffer\n"); + goto exit; + } + + /* Write directory table to device */ + ret = set_cluster(mydata, itr->clust, itr->block, + mydata->clust_size * mydata->sect_size); + if (ret) + printf("Error: writing directory entry\n"); + +exit: + free(dirname_copy); + free(mydata->fatbuf); + free(itr); + free(dotdent); + return ret; +} diff --git a/fs/fs.c b/fs/fs.c index 3cb6b21fe9..a92e060296 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -164,14 +164,15 @@ static struct fstype_info fstypes[] = { .read = fat_read_file, #ifdef CONFIG_FAT_WRITE .write = file_fat_write, + .mkdir = fat_mkdir, #else .write = fs_write_unsupported, + .mkdir = fs_mkdir_unsupported, #endif .uuid = fs_uuid_unsupported, .opendir = fat_opendir, .readdir = fat_readdir, .closedir = fat_closedir, - .mkdir = fs_mkdir_unsupported, }, #endif #ifdef CONFIG_FS_EXT4 diff --git a/include/fat.h b/include/fat.h index 295da0f243..039b6e03de 100644 --- a/include/fat.h +++ b/include/fat.h @@ -237,5 +237,6 @@ 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_mkdir(const char *dirname); void fat_close(void); #endif /* _FAT_H_ */
In this patch, mkdir support is added to FAT file system. A newly created directory contains only "." and ".." entries. Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> --- fs/fat/fat_write.c | 138 +++++++++++++++++++++++++++++++++++++++++++++ fs/fs.c | 3 +- include/fat.h | 1 + 3 files changed, 141 insertions(+), 1 deletion(-)