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 = &not_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);
 }

Reply via email to