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.aka...@linaro.org>
---
 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_ */
-- 
2.17.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to