FAT support for working with multi-disk interface
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/ca1b4915 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/ca1b4915 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/ca1b4915 Branch: refs/heads/develop Commit: ca1b4915cea82b54570d4b7bc2ad68bdf1240aae Parents: 6e9213f Author: Fabio Utzig <[email protected]> Authored: Mon Dec 19 21:15:22 2016 -0200 Committer: Fabio Utzig <[email protected]> Committed: Thu Jan 12 10:51:46 2017 -0200 ---------------------------------------------------------------------- fs/disk/include/disk/disk.h | 2 + fs/disk/src/disk.c | 36 +++++++ fs/fatfs/src/mynewt_glue.c | 219 +++++++++++++++++++++++++++++++++------ fs/fs/include/fs/fs.h | 3 + fs/fs/src/fs_dirent.c | 26 ++++- fs/fs/src/fs_file.c | 69 ++++++++++-- 6 files changed, 309 insertions(+), 46 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ca1b4915/fs/disk/include/disk/disk.h ---------------------------------------------------------------------- diff --git a/fs/disk/include/disk/disk.h b/fs/disk/include/disk/disk.h index e87fc7b..49b9dde 100644 --- a/fs/disk/include/disk/disk.h +++ b/fs/disk/include/disk/disk.h @@ -44,6 +44,8 @@ struct disk_ops { }; int disk_register(const char *disk_name, const char *fs_name, struct disk_ops *dops); +struct disk_ops *disk_ops_for(const char *disk_name); +char *disk_fs_for(const char *disk_name); #ifdef __cplusplus } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ca1b4915/fs/disk/src/disk.c ---------------------------------------------------------------------- diff --git a/fs/disk/src/disk.c b/fs/disk/src/disk.c index 803e1a5..846c44d 100644 --- a/fs/disk/src/disk.c +++ b/fs/disk/src/disk.c @@ -60,3 +60,39 @@ int disk_register(const char *disk_name, const char *fs_name, struct disk_ops *d return 0; } + +struct disk_ops * +disk_ops_for(const char *disk_name) +{ + struct disk_ops *dops = NULL; + struct disk_info *sc; + + if (disk_name) { + SLIST_FOREACH(sc, &disks, sc_next) { + if (strcmp(sc->disk_name, disk_name) == 0) { + dops = sc->dops; + break; + } + } + } + + return dops; +} + +char * +disk_fs_for(const char *disk_name) +{ + char *fs_name = NULL; + struct disk_info *sc; + + if (disk_name) { + SLIST_FOREACH(sc, &disks, sc_next) { + if (strcmp(sc->disk_name, disk_name) == 0) { + fs_name = (char *) sc->fs_name; + break; + } + } + } + + return fs_name; +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ca1b4915/fs/fatfs/src/mynewt_glue.c ---------------------------------------------------------------------- diff --git a/fs/fatfs/src/mynewt_glue.c b/fs/fatfs/src/mynewt_glue.c index f64bbb2..c622ffb 100644 --- a/fs/fatfs/src/mynewt_glue.c +++ b/fs/fatfs/src/mynewt_glue.c @@ -32,11 +32,28 @@ static int fatfs_dirent_name(const struct fs_dirent *fs_dirent, size_t max_len, char *out_name, uint8_t *out_name_len); static int fatfs_dirent_is_dir(const struct fs_dirent *fs_dirent); +#define DRIVE_LEN 4 + +struct fatfs_file { + struct fs_ops *fops; + FIL *file; +}; + +struct fatfs_dir { + struct fs_ops *fops; + FATFS_DIR *dir; +}; + +struct fatfs_dirent { + struct fs_ops *fops; + FILINFO filinfo; +}; + /* NOTE: to ease memory management of dirent structs, this single static * variable holds the latest entry found by readdir. This limits FAT to * working on a single thread, single opendir -> closedir cycle. */ -static FILINFO filinfo; +static struct fatfs_dirent dirent; static struct fs_ops fatfs_ops = { .f_open = fatfs_open, @@ -131,16 +148,102 @@ int fatfs_to_vfs_error(FRESULT res) return rc; } +struct mounted_disk { + char *disk_name; + int disk_number; + + SLIST_ENTRY(mounted_disk) sc_next; +}; + +static SLIST_HEAD(, mounted_disk) mounted_disks = SLIST_HEAD_INITIALIZER(); + +static int +drivenumber_from_disk(char *disk_name) +{ + struct mounted_disk *sc; + struct mounted_disk *new_disk; + int disk_number; + FATFS *fs; + char path[DRIVE_LEN]; + + disk_number = 0; + if (disk_name) { + SLIST_FOREACH(sc, &mounted_disks, sc_next) { + if (strcmp(sc->disk_name, disk_name) == 0) { + return sc->disk_number; + } + disk_number++; + } + } + + /* XXX: check for errors? */ + fs = malloc(sizeof(FATFS)); + sprintf(path, "%d:", disk_number); + f_mount(fs, path, 1); + + /* FIXME */ + new_disk = malloc(sizeof(struct mounted_disk)); + new_disk->disk_name = strdup(disk_name); + new_disk->disk_number = disk_number; + SLIST_INSERT_HEAD(&mounted_disks, new_disk, sc_next); + + return disk_number; +} + +/** + * @brief Returns the path with the disk prefix removed (if found) + * + * Paths should be given in the form disk<number>:/path. This routine + * will parse and return only the path, removing the disk information. + */ +char * +filepath_from_path(const char *path) +{ + char *colon; + char *filepath; + size_t len; + + colon = (char *) path; + while (*colon && *colon != ':') { + colon++; + } + + if (*colon != ':') { + filepath = strdup(path); + } else { + colon++; + len = strlen(colon); + filepath = malloc(len); + memcpy(filepath, colon, len); + filepath[len] = '\0'; + } + + return filepath; +} + static int fatfs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file) { FRESULT res; - FIL *out_file; + FIL *out_file = NULL; BYTE mode; + struct fatfs_file *file = NULL; + char *disk; + int number; + char *filepath; + char drivepath[255 + DRIVE_LEN]; /* FIXME */ + int rc; + + file = malloc(sizeof(struct fatfs_file)); + if (!file) { + rc = FS_ENOMEM; + goto out; + } out_file = malloc(sizeof(FIL)); if (!out_file) { - return FS_ENOMEM; + rc = FS_ENOMEM; + goto out; } mode = FA_OPEN_EXISTING; @@ -158,20 +261,36 @@ fatfs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file) mode |= FA_CREATE_ALWAYS; } - res = f_open(out_file, path, mode); + disk = disk_from_path(path); + number = drivenumber_from_disk(disk); + filepath = filepath_from_path(path); + sprintf(drivepath, "%d:%s", number, filepath); + free(filepath); + + res = f_open(out_file, drivepath, mode); if (res != FR_OK) { - free(out_file); - return fatfs_to_vfs_error(res); + rc = fatfs_to_vfs_error(res); + goto out; } - *out_fs_file = (struct fs_file *)out_file; - return FS_EOK; + + file->file = out_file; + file->fops = &fatfs_ops; + *out_fs_file = (struct fs_file *) file; + rc = FS_EOK; + +out: + if (rc != FS_EOK) { + if (file) free(file); + if (out_file) free(out_file); + } + return rc; } static int fatfs_close(struct fs_file *fs_file) { FRESULT res; - FIL *file = (FIL *)fs_file; + FIL *file = ((struct fatfs_file *) fs_file)->file; if (file == NULL) { return FS_EOK; @@ -186,7 +305,7 @@ static int fatfs_seek(struct fs_file *fs_file, uint32_t offset) { FRESULT res; - FIL *file = (FIL *)fs_file; + FIL *file = ((struct fatfs_file *) fs_file)->file; res = f_lseek(file, offset); return fatfs_to_vfs_error(res); @@ -196,7 +315,7 @@ static uint32_t fatfs_getpos(const struct fs_file *fs_file) { uint32_t offset; - FIL *file = (FIL *)fs_file; + FIL *file = ((struct fatfs_file *) fs_file)->file; offset = (uint32_t) f_tell(file); return offset; @@ -206,7 +325,7 @@ static int fatfs_file_len(const struct fs_file *fs_file, uint32_t *out_len) { uint32_t offset; - FIL *file = (FIL *)fs_file; + FIL *file = ((struct fatfs_file *) fs_file)->file; offset = (uint32_t) f_size(file); return offset; @@ -217,7 +336,7 @@ fatfs_read(struct fs_file *fs_file, uint32_t len, void *out_data, uint32_t *out_len) { FRESULT res; - FIL *file = (FIL *)fs_file; + FIL *file = ((struct fatfs_file *) fs_file)->file; res = f_read(file, out_data, len, (UINT *)out_len); return fatfs_to_vfs_error(res); @@ -228,7 +347,7 @@ fatfs_write(struct fs_file *fs_file, const void *data, int len) { FRESULT res; UINT out_len; - FIL *file = (FIL *)fs_file; + FIL *file = ((struct fatfs_file *) fs_file)->file; res = f_write(file, data, len, &out_len); if (len != out_len) { @@ -242,6 +361,7 @@ fatfs_unlink(const char *path) { FRESULT res; + //FIXME: handle disk res = f_unlink(path); return fatfs_to_vfs_error(res); } @@ -251,6 +371,7 @@ fatfs_rename(const char *from, const char *to) { FRESULT res; + //FIXME: handle disk res = f_rename(from, to); return fatfs_to_vfs_error(res); } @@ -268,18 +389,48 @@ static int fatfs_opendir(const char *path, struct fs_dir **out_fs_dir) { FRESULT res; - FATFS_DIR *out_dir; + FATFS_DIR *out_dir = NULL; + struct fatfs_dir *dir = NULL; + char *disk; + int number; + char *filepath; + char drivepath[255 + DRIVE_LEN]; /* FIXME */ + int rc; + + dir = malloc(sizeof(struct fatfs_dir)); + if (!dir) { + rc = FS_ENOMEM; + goto out; + } out_dir = malloc(sizeof(FATFS_DIR)); if (!out_dir) { - return FS_ENOMEM; + rc = FS_ENOMEM; + goto out; } - res = f_opendir(out_dir, path); + disk = disk_from_path(path); + number = drivenumber_from_disk(disk); + filepath = filepath_from_path(path); + sprintf(drivepath, "%d:%s", number, filepath); + free(filepath); + + res = f_opendir(out_dir, drivepath); if (res != FR_OK) { - return fatfs_to_vfs_error(res); + rc = fatfs_to_vfs_error(res); + goto out; + } + + dir->dir = out_dir; + dir->fops = &fatfs_ops; + *out_fs_dir = (struct fs_dir *)dir; + rc = FS_EOK; + +out: + if (rc != FS_EOK) { + if (dir) free(dir); + if (out_dir) free(out_dir); } - *out_fs_dir = (struct fs_dir *)out_dir; return FS_EOK; } @@ -287,15 +438,16 @@ static int fatfs_readdir(struct fs_dir *fs_dir, struct fs_dirent **out_fs_dirent) { FRESULT res; - FATFS_DIR *dir = (FATFS_DIR *)fs_dir; + FATFS_DIR *dir = ((struct fatfs_dir *) fs_dir)->dir; - res = f_readdir(dir, &filinfo); + dirent.fops = &fatfs_ops; + res = f_readdir(dir, &dirent.filinfo); if (res != FR_OK) { return fatfs_to_vfs_error(res); } - *out_fs_dirent = (struct fs_dirent *)&filinfo; - if (!filinfo.fname[0]) { + *out_fs_dirent = (struct fs_dirent *) &dirent; + if (!dirent.filinfo.fname[0]) { return FS_ENOENT; } return FS_EOK; @@ -305,7 +457,7 @@ static int fatfs_closedir(struct fs_dir *fs_dir) { FRESULT res; - FATFS_DIR *dir = (FATFS_DIR *)fs_dir; + FATFS_DIR *dir = ((struct fatfs_dir *) fs_dir)->dir; res = f_closedir(dir); free(dir); @@ -316,12 +468,14 @@ static int fatfs_dirent_name(const struct fs_dirent *fs_dirent, size_t max_len, char *out_name, uint8_t *out_name_len) { - const FILINFO *dirent = (const FILINFO *)fs_dirent; + + FILINFO *filinfo; size_t out_len; - assert(dirent != NULL); - out_len = max_len < sizeof(dirent->fname) ? max_len : sizeof(dirent->fname); - memcpy(out_name, dirent->fname, out_len); + assert(fs_dirent != NULL); + filinfo = &(((struct fatfs_dirent *)fs_dirent)->filinfo); + out_len = max_len < sizeof(filinfo->fname) ? max_len : sizeof(filinfo->fname); + memcpy(out_name, filinfo->fname, out_len); *out_name_len = out_len; return FS_EOK; } @@ -329,10 +483,10 @@ fatfs_dirent_name(const struct fs_dirent *fs_dirent, size_t max_len, static int fatfs_dirent_is_dir(const struct fs_dirent *fs_dirent) { - const FILINFO *dirent = (const FILINFO *)fs_dirent; - - assert(dirent != NULL); - return dirent->fattrib & AM_DIR; + FILINFO *filinfo; + assert(fs_dirent != NULL); + filinfo = &(((struct fatfs_dirent *)fs_dirent)->filinfo); + return filinfo->fattrib & AM_DIR; } DSTATUS @@ -349,6 +503,7 @@ disk_status(BYTE pdrv) return RES_OK; } +/* FIXME */ static struct disk_ops *disk_ops_from_handle(BYTE pdrv) { return &mmc_ops; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ca1b4915/fs/fs/include/fs/fs.h ---------------------------------------------------------------------- diff --git a/fs/fs/include/fs/fs.h b/fs/fs/include/fs/fs.h index b44f624..f823b32 100644 --- a/fs/fs/include/fs/fs.h +++ b/fs/fs/include/fs/fs.h @@ -53,6 +53,9 @@ int fs_dirent_name(const struct fs_dirent *, size_t max_len, char *out_name, uint8_t *out_name_len); int fs_dirent_is_dir(const struct fs_dirent *); +/* Helper functions */ +char *disk_from_path(const char *path); + /* * File access flags. */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ca1b4915/fs/fs/src/fs_dirent.c ---------------------------------------------------------------------- diff --git a/fs/fs/src/fs_dirent.c b/fs/fs/src/fs_dirent.c index b5fd6c5..ec26745 100644 --- a/fs/fs/src/fs_dirent.c +++ b/fs/fs/src/fs_dirent.c @@ -20,24 +20,40 @@ #include <fs/fs_if.h> #include "fs_priv.h" +struct fs_ops *fops_from_filename(const char *); + +static struct fs_ops * +fops_from_dir(const struct fs_dir *dir) +{ + /* NOTE: fs_ops must always be the first field for any fs_file */ + return (struct fs_ops *) *((uint32_t *)dir); +} + +static struct fs_ops * +fops_from_dirent(const struct fs_dirent *dirent) +{ + /* NOTE: fs_ops must always be the first field for any fs_file */ + return (struct fs_ops *) *((uint32_t *)dirent); +} + int fs_opendir(const char *path, struct fs_dir **out_dir) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_filename(path); return fops->f_opendir(path, out_dir); } int fs_readdir(struct fs_dir *dir, struct fs_dirent **out_dirent) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_dir(dir); return fops->f_readdir(dir, out_dirent); } int fs_closedir(struct fs_dir *dir) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_dir(dir); return fops->f_closedir(dir); } @@ -45,13 +61,13 @@ int fs_dirent_name(const struct fs_dirent *dirent, size_t max_len, char *out_name, uint8_t *out_name_len) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_dirent(dirent); return fops->f_dirent_name(dirent, max_len, out_name, out_name_len); } int fs_dirent_is_dir(const struct fs_dirent *dirent) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_dirent(dirent); return fops->f_dirent_is_dir(dirent); } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/ca1b4915/fs/fs/src/fs_file.c ---------------------------------------------------------------------- diff --git a/fs/fs/src/fs_file.c b/fs/fs/src/fs_file.c index a18d0ba..35c7fe7 100644 --- a/fs/fs/src/fs_file.c +++ b/fs/fs/src/fs_file.c @@ -19,6 +19,11 @@ #include <fs/fs.h> #include <fs/fs_if.h> +#include <disk/disk.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + #include "fs_priv.h" static int @@ -137,7 +142,7 @@ safe_fs_ops_for(const char *fs_name) { struct fs_ops *fops; - fops = fs_ops_for("fatfs"); + fops = fs_ops_for(fs_name); if (fops == NULL) { fops = ¬_initialized_ops; } @@ -145,58 +150,104 @@ safe_fs_ops_for(const char *fs_name) return fops; } +char *disk_from_path(const char *path) +{ + char *colon; + uint8_t len; + char *disk; + + colon = (char *) path; + while (*colon && *colon != ':') { + colon++; + } + + if (*colon != ':') { + return NULL; + } + + len = colon - path; + disk = malloc(len + 1); + if (!disk) { + return NULL; + } + memcpy(disk, path, len); + disk[len] = '\0'; + + return disk; +} + +struct fs_ops * +fops_from_filename(const char *filename) +{ + char *disk; + char *fs_name = NULL; + + disk = disk_from_path(filename); + if (disk) { + fs_name = disk_fs_for(disk); + } + return safe_fs_ops_for(fs_name); +} + +static struct fs_ops * +fops_from_file(const struct fs_file *file) +{ + /* NOTE: fs_ops must always be the first field for any fs_file */ + return (struct fs_ops *) *((uint32_t *)file); +} + int fs_open(const char *filename, uint8_t access_flags, struct fs_file **out_file) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_filename(filename); return fops->f_open(filename, access_flags, out_file); } int fs_close(struct fs_file *file) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_file(file); return fops->f_close(file); } int fs_read(struct fs_file *file, uint32_t len, void *out_data, uint32_t *out_len) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_file(file); return fops->f_read(file, len, out_data, out_len); } int fs_write(struct fs_file *file, const void *data, int len) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_file(file); return fops->f_write(file, data, len); } int fs_seek(struct fs_file *file, uint32_t offset) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_file(file); return fops->f_seek(file, offset); } uint32_t fs_getpos(const struct fs_file *file) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_file(file); return fops->f_getpos(file); } int fs_filelen(const struct fs_file *file, uint32_t *out_len) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_file(file); return fops->f_filelen(file, out_len); } int fs_unlink(const char *filename) { - struct fs_ops *fops = safe_fs_ops_for("fatfs"); + struct fs_ops *fops = fops_from_filename(filename); return fops->f_unlink(filename); }
