fs: fat: support mkdir
authorAKASHI Takahiro <takahiro.akashi@linaro.org>
Tue, 11 Sep 2018 06:59:10 +0000 (15:59 +0900)
committerAlexander Graf <agraf@suse.de>
Sun, 23 Sep 2018 19:55:30 +0000 (21:55 +0200)
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>
Signed-off-by: Alexander Graf <agraf@suse.de>
fs/fat/fat_write.c
fs/fs.c
include/fat.h

index 651c7866debc598b33db97fdc1db1ae9259a0aeb..035469f31c8d0c9e2c855eb59e1a48189cde7456 100644 (file)
@@ -1183,3 +1183,139 @@ 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.total_sect;
+
+       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 archive 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 62165d5c57010c8bd4d665fd977c0c0fbbecbe44..099540f38a10461a3bc2c7410293ab7c8db5a953 100644 (file)
--- 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
index a236451add591d0665ef45e83ac46da4f06e1d1a..0fe3eaa8f7c7a7117b180f3cad88963b87f5d275 100644 (file)
@@ -203,5 +203,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_ */