From aff1874300d3e4184ef7a2a18128ec1b49e6a351 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Sat, 31 May 2025 18:48:07 +0200 Subject: [PATCH 1/7] fs/fs_cli: Register commands statically Now fs cli commands are register at link time to reduce memory footprint. No change in functionality. Signed-off-by: Jerzy Kasenberg --- fs/fs/pkg.yml | 2 ++ fs/fs/src/fs_cli.c | 42 ++++++------------------------------------ fs/fs/src/fs_mount.c | 11 ----------- fs/fs/src/fs_priv.h | 3 --- 4 files changed, 8 insertions(+), 50 deletions(-) diff --git a/fs/fs/pkg.yml b/fs/fs/pkg.yml index d08fd18dea..10c68746e5 100644 --- a/fs/fs/pkg.yml +++ b/fs/fs/pkg.yml @@ -34,3 +34,5 @@ pkg.deps.FS_CLI: pkg.deps.FS_MGMT: - "@apache-mynewt-mcumgr/cmd/fs_mgmt/port/mynewt" + +pkg.whole_archive: true diff --git a/fs/fs/src/fs_cli.c b/fs/fs/src/fs_cli.c index 257586093e..9fa932a222 100644 --- a/fs/fs/src/fs_cli.c +++ b/fs/fs/src/fs_cli.c @@ -29,33 +29,6 @@ #include "fs/fs.h" -static int fs_ls_cmd(int argc, char **argv); -static int fs_rm_cmd(int argc, char **argv); -static int fs_mkdir_cmd(int argc, char **argv); -static int fs_mv_cmd(int argc, char **argv); -static int fs_cat_cmd(int argc, char **argv); - -static struct shell_cmd fs_ls_struct = { - .sc_cmd = "ls", - .sc_cmd_func = fs_ls_cmd -}; -static struct shell_cmd fs_rm_struct = { - .sc_cmd = "rm", - .sc_cmd_func = fs_rm_cmd -}; -static struct shell_cmd fs_mkdir_struct = { - .sc_cmd = "mkdir", - .sc_cmd_func = fs_mkdir_cmd -}; -static struct shell_cmd fs_mv_struct = { - .sc_cmd = "mv", - .sc_cmd_func = fs_mv_cmd -}; -static struct shell_cmd fs_cat_struct = { - .sc_cmd = "cat", - .sc_cmd_func = fs_cat_cmd -}; - static void fs_ls_file(const char *name, struct fs_file *file) { @@ -220,13 +193,10 @@ fs_cat_cmd(int argc, char **argv) return 0; } -void -fs_cli_init(void) -{ - shell_cmd_register(&fs_ls_struct); - shell_cmd_register(&fs_rm_struct); - shell_cmd_register(&fs_mkdir_struct); - shell_cmd_register(&fs_mv_struct); - shell_cmd_register(&fs_cat_struct); -} +MAKE_SHELL_CMD(ls, fs_ls_cmd, NULL) +MAKE_SHELL_CMD(rm, fs_rm_cmd, NULL) +MAKE_SHELL_CMD(mkdir, fs_mkdir_cmd, NULL) +MAKE_SHELL_CMD(mv, fs_mv_cmd, NULL) +MAKE_SHELL_CMD(cat, fs_cat_cmd, NULL) + #endif /* MYNEWT_VAL(FS_CLI) */ diff --git a/fs/fs/src/fs_mount.c b/fs/fs/src/fs_mount.c index 5319aed7bc..c687cf47c8 100644 --- a/fs/fs/src/fs_mount.c +++ b/fs/fs/src/fs_mount.c @@ -28,10 +28,6 @@ static SLIST_HEAD(, fs_ops) root_fops = SLIST_HEAD_INITIALIZER(); -#if MYNEWT_VAL(FS_CLI) -static uint8_t g_cli_initialized; -#endif - #if MYNEWT_VAL(FS_MGMT) static uint8_t g_mgmt_initialized; #endif @@ -49,13 +45,6 @@ fs_register(struct fs_ops *fops) SLIST_INSERT_HEAD(&root_fops, fops, sc_next); -#if MYNEWT_VAL(FS_CLI) - if (!g_cli_initialized) { - fs_cli_init(); - g_cli_initialized = 1; - } -#endif - #if MYNEWT_VAL(FS_MGMT) if (!g_mgmt_initialized) { fs_mgmt_register_group(); diff --git a/fs/fs/src/fs_priv.h b/fs/fs/src/fs_priv.h index 0e6345db57..d5138c938c 100644 --- a/fs/fs/src/fs_priv.h +++ b/fs/fs/src/fs_priv.h @@ -29,9 +29,6 @@ struct fs_ops; struct fs_ops *fs_ops_for(const char *fs_name); struct fs_ops *safe_fs_ops_for(const char *fs_name); -#if MYNEWT_VAL(FS_CLI) -void fs_cli_init(void); -#endif #ifdef __cplusplus } From 0a49e72768c81b7ddd655c75c59573486046f4c5 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Sat, 21 Jun 2025 10:33:03 +0200 Subject: [PATCH 2/7] fs/disks: Rework disk interface Disk interface tightly coupled to file system and could not be used for exposing disk to something else then code in fs/fs. With this change new disk_listener interface allows code to be informed about disks being inserted and removed. Listeners in turn can mount file systems from disk or for example expose disk to USB host via MSC. Signed-off-by: Jerzy Kasenberg --- fs/disk/include/disk/disk.h | 198 ++++++++++++++++++++++++++++++++++-- fs/disk/pkg.yml | 5 +- fs/disk/src/disk.c | 141 ++++--------------------- 3 files changed, 213 insertions(+), 131 deletions(-) diff --git a/fs/disk/include/disk/disk.h b/fs/disk/include/disk/disk.h index cf2849629d..544d22c95e 100644 --- a/fs/disk/include/disk/disk.h +++ b/fs/disk/include/disk/disk.h @@ -22,7 +22,8 @@ #include #include -#include "os/mynewt.h" +#include +#include #ifdef __cplusplus extern "C" { @@ -35,19 +36,194 @@ extern "C" { #define DISK_EOS 4 /* OS error */ #define DISK_EUNINIT 5 /* File system not initialized */ -struct disk_ops { - int (*read)(uint8_t, uint32_t, void *, uint32_t); - int (*write)(uint8_t, uint32_t, const void *, uint32_t); - int (*ioctl)(uint8_t, uint32_t, void *); +typedef struct disk disk_t; +typedef struct disk_info disk_info_t; +typedef struct disk_listener disk_listener_t; - SLIST_ENTRY(disk_ops) sc_next; +/** + * Disk information + */ +struct disk_info { + /* Disk name (information only) */ + const char *name; + /* Disk block (sector) count */ + uint32_t block_count; + /* Block size (usually 512) */ + uint16_t block_size; + /* Set to 1 if disk is present */ + uint16_t present : 1; +}; + +typedef struct disk_ops { + /** Get basic information about disk + * + * @param disk - disk to query + * @param info - disk information to fill + * @return 0 on success, SYS_EINVAL if arguments are incorrect + */ + int (*get_info)(const struct disk *disk, struct disk_info *info); + + /** + * Inform driver that disk was just removed + * @param disk - disk that was ejected + * @return 0 on success, SYS_EINVAL if arguments are incorrect + */ + int (*eject)(struct disk *disk); + /** + * Read disk block + * @param disk - dist to read from + * @param lba - block to read + * @param buf - buffer for data + * @param block_count - number for blocks to read + * @return 0 on success + */ + int (*read)(struct disk *disk, uint32_t lba, void *buf, uint32_t block_count); + /** + * Write disk block + * @param disk - dist to write to + * @param lba - block to write to + * @param buf - data buffer + * @param block_count - number of blocks to write + * @return 0 on success + */ + int (*write)(struct disk *disk, uint32_t lba, const void *buf, uint32_t block_count); +} disk_ops_t; + +/* Disk listener operations */ +typedef struct disk_listener_ops { + /* New disk was inserted to driver and could be mounter */ + int (*disk_added)(struct disk_listener *listener, struct disk *disk); + /* Disk was ejected and should be unmounted */ + int (*disk_removed)(struct disk_listener *listener, struct disk *disk); +} disk_listener_ops_t; + +/* Disk listener */ +struct disk_listener { + const disk_listener_ops_t *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); -char *disk_name_from_path(const char *path); -char *disk_filepath_from_path(const char *path); +/* Base for disks */ +struct disk { + const disk_ops_t *ops; +}; + +/** + * Function called when disk was inserted into a driver + * and system could mount it or otherwise be aware that new + * disk could be used + * + * @param disk - disk that was inserted + * + * @return 0 - for success + */ +int mn_disk_inserted(disk_t *disk); + +/** + * Function called when disk was removed, if disk was + * mounted it file system can be unmounted. If disk + * was present to MSC it can no longer be advertised + * as present. + * + * @param disk - disk that was remove from driver + * + * @return 0 -for success + */ +int mn_disk_ejected(disk_t *disk); + +/** + * Function return 1 if disk is present + * + * @param disk - disk to check for presence + * @return 1 - disk is present, 0 - disk is not present + */ +static inline int disk_present(disk_t *disk) +{ + disk_info_t di; + disk->ops->get_info(disk, &di); + + return di.present; +} + +/** + * Get disk information + * Disk information consist of size information + * + * @param disk - disk to get information from + * @param di - pointer to data to received disk information + * + * @return 0 - for success + */ +static inline int mn_disk_info_get(disk_t *disk, disk_info_t *di) +{ + return disk->ops->get_info(disk, di); +} + +/** + * Read sector(s) from disk + * + * @param disk - disk to read data from + * @param lba - sector number + * @param buf - buffer to be filled with data from disk + * @param block_count - number of sectors to read + * @return 0 - for success + */ +static inline int mn_disk_read(disk_t *disk, uint32_t lba, void *buf, uint32_t block_count) +{ + return disk->ops->read(disk, lba, buf, block_count); +} + +/** + * Write sector(s) to disk + * + * @param disk - disk to write to + * @param lba - first sector to write to + * @param buf - buffer with data + * @param block_count - number of sectors to write + * @return 0 - for success + */ +static inline int mn_disk_write(disk_t *disk, uint32_t lba, const void *buf, uint32_t block_count) +{ + return disk->ops->write(disk, lba, buf, block_count); +} + +/** + * Eject disk + * + * Calling this function will result in calling disk listeners about + * disk being removed via disk_removed(). This may result in file + * system being unmounted. + * + * @param disk - disk to eject + * @return 0 - for success + */ +static inline int mn_disk_eject(disk_t *disk) +{ + return disk->ops->eject(disk); +} + +/** + * Link time table to hold all available disk listeners + * that will be informed when disk is available and + * can be mounted or used in other ways. + */ +LINK_TABLE(disk_listener_t *, disk_listeners) + +/** + * @brief Macros to put disk_listener in link table + * + * i.e. + * // Define disk_listener_t structure + * disk_listener_t mounter = { + * .opt = &mounter_ops, + * }; + * + * DISK_LISTENER(mounter_entry, mounter) + * + * @param listener_entry - new pointer variable name that will be put in disk_listeners table + * @param listener - object of type disk_listener_t + */ +#define DISK_LISTENER(listener_entry, listener) \ + LINK_TABLE_ELEMENT(disk_listeners, listener_entry) = &listener; #ifdef __cplusplus } diff --git a/fs/disk/pkg.yml b/fs/disk/pkg.yml index 52a0f7f112..1157f15e92 100644 --- a/fs/disk/pkg.yml +++ b/fs/disk/pkg.yml @@ -18,10 +18,13 @@ # pkg.name: fs/disk -pkg.description: Disk management layer to glue filesystems to disk devices. +pkg.description: Disk management layer to disk devices. pkg.author: "Apache Mynewt " pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" + +pkg.link_tables: + - disk_listeners diff --git a/fs/disk/src/disk.c b/fs/disk/src/disk.c index 93a2741fd2..910985375f 100644 --- a/fs/disk/src/disk.c +++ b/fs/disk/src/disk.c @@ -17,135 +17,38 @@ * under the License. */ -#include -#include -#include "os/mynewt.h" +#include +#include +#include #include -struct disk_info { - const char *disk_name; - const char *fs_name; - struct disk_ops *dops; +#define DISK_EOK 0 /* Success */ +#define DISK_EHW 1 /* Error accessing storage medium */ +#define DISK_ENOMEM 2 /* Insufficient memory */ +#define DISK_ENOENT 3 /* No such file or directory */ +#define DISK_EOS 4 /* OS error */ +#define DISK_EUNINIT 5 /* File system not initialized */ - SLIST_ENTRY(disk_info) sc_next; -}; - -static SLIST_HEAD(, disk_info) disks = SLIST_HEAD_INITIALIZER(); - -/** - * - */ -int disk_register(const char *disk_name, const char *fs_name, struct disk_ops *dops) +int +mn_disk_inserted(disk_t *disk) { - struct disk_info *info = NULL; - struct disk_info *sc; - - SLIST_FOREACH(sc, &disks, sc_next) { - if (strcmp(sc->disk_name, disk_name) == 0) { - return DISK_ENOENT; - } - } + int count = LINK_TABLE_SIZE(disk_listeners); - info = malloc(sizeof(struct disk_info)); - if (!info) { - return DISK_ENOMEM; + for (int i = 0; i < count; ++i) { + disk_listener_t *listener = disk_listeners[i]; + listener->ops->disk_added(listener, disk); } - - info->disk_name = disk_name; - info->fs_name = fs_name; - info->dops = dops; - - SLIST_INSERT_HEAD(&disks, info, sc_next); - return 0; } -struct disk_ops * -disk_ops_for(const char *disk_name) +int +mn_disk_ejected(disk_t *disk) { - struct disk_info *sc; + int count = LINK_TABLE_SIZE(disk_listeners); - if (disk_name) { - SLIST_FOREACH(sc, &disks, sc_next) { - if (strcmp(sc->disk_name, disk_name) == 0) { - return sc->dops; - } - } + for (int i = 0; i < count; ++i) { + disk_listener_t *listener = disk_listeners[i]; + listener->ops->disk_removed(listener, disk); } - - return NULL; -} - -char * -disk_fs_for(const char *disk_name) -{ - struct disk_info *sc; - - if (disk_name) { - SLIST_FOREACH(sc, &disks, sc_next) { - if (strcmp(sc->disk_name, disk_name) == 0) { - return ((char *) sc->fs_name); - } - } - } - - return NULL; -} - -char * -disk_name_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; -} - -/** - * @brief Returns the path with the disk prefix removed (if found) - * - * Paths should be given in the form disk:/path. This routine - * will parse and return only the path, removing the disk information. - */ -char * -disk_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 + 1); - memcpy(filepath, colon, len); - filepath[len] = '\0'; - } - - return filepath; + return 0; } From 34929a4243105c35667194df51cb8de49b70bb53 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Sat, 21 Jun 2025 10:50:26 +0200 Subject: [PATCH 3/7] fs: Introduce file system entity File system was represented by fs_ops that consisted of bunch of file system functions, name, and pointer to link file system ops in chain. Most of the date was constant and there is was no reason to waste RAM for callback pointer. This introduce file_system object that has ops but can be extended to hold file system specific data. Same file system ops can be used for more then one file system. File system can be mounted and that what littlefs and other file systems will. This change mostly changes filesystem_ops to const in most places. Signed-off-by: Jerzy Kasenberg --- fs/fs/include/fs/fs_if.h | 77 +++++++++++++++++++--- fs/fs/pkg.yml | 3 - fs/fs/src/fs_dirent.c | 19 +++--- fs/fs/src/fs_file.c | 72 ++++++++++----------- fs/fs/src/fs_mkdir.c | 25 ++++++-- fs/fs/src/fs_mount.c | 134 +++++++++++++++++++++++++++++---------- fs/fs/src/fs_priv.h | 4 +- fs/fs/syscfg.yml | 7 ++ 8 files changed, 241 insertions(+), 100 deletions(-) diff --git a/fs/fs/include/fs/fs_if.h b/fs/fs/include/fs/fs_if.h index 567561f21a..120c386ac5 100644 --- a/fs/fs/include/fs/fs_if.h +++ b/fs/fs/include/fs/fs_if.h @@ -26,6 +26,16 @@ extern "C" { #include "os/mynewt.h" +typedef struct file_system { + const struct fs_ops *ops; + const char *name; +} file_system_t; + +struct mount_point { + const char *mount_point; + const file_system_t *fs; +}; + /* * Common interface filesystem(s) provide. */ @@ -53,10 +63,8 @@ struct fs_ops { int (*f_dirent_name)(const struct fs_dirent *dirent, size_t max_len, char *out_name, uint8_t *out_name_len); int (*f_dirent_is_dir)(const struct fs_dirent *dirent); - - const char *f_name; - - SLIST_ENTRY(fs_ops) sc_next; + int (*f_mount)(const file_system_t *fs); + int (*f_umount)(const file_system_t *fs); }; struct fops_container { @@ -78,18 +86,67 @@ int fs_register(struct fs_ops *fops); * * @return fops if there's only one registered filesystem, NULL otherwise. */ -struct fs_ops *fs_ops_try_unique(void); +const struct fs_ops *fs_ops_try_unique(void); + +const struct fs_ops *fs_ops_from_container(struct fops_container *container); + +/** + * Mount file system + * + * @param fs - file system to mount + * @param path - path to mount i.e. 0:, nffs: + * @return 0 on success + */ +int fs_mount(const file_system_t *fs, const char *path); + +/** + * Unmount file system by mount point + * + * @param mount_point - mount point to unmount i.e. 0:, nffs: + * @return 0 on success + */ +const file_system_t *fs_unmount_mount_point(const char *mount_point); + +/** + * Unmount file system + * + * @param fs - mounted file system to unmount + * @return 0 on success + */ +int fs_unmount_file_system(const file_system_t *fs); /** - * Retrieve a filesystem's operations table + * Get file system mount point path + * + * For given path it will return mount point and file system + * i.e.: + * For 0:/DIREC/FIL.TXT function will return "0:" and fs + * will be filled with pointer to valid file_system_t structure. * - * @param name Name of the filesystem to retrieve fs_ops for + * @param path - file or directory name + * @param fs - on success file system + * @return file system mount point string + */ +const char *file_system_path(const char *path, const file_system_t **fs); + +/** + * Return the only file system mounted * - * @return valid pointer on success, NULL on failure + * It there is only one file system mounted it will be returned by this + * function. If two file system were mounted funciton will return NULL. + * @return non-NULL if exactly one file system is mounted, otherwise NULL */ -struct fs_ops *fs_ops_for(const char *name); +const file_system_t *get_only_file_system(void); -struct fs_ops *fs_ops_from_container(struct fops_container *container); +/** + * Get file system and file system mount point + * + * Usually + * @param path - file system path + * @param fs - file system for path + * @param fs_path - mount point (usually prefix of file path) + */ +void get_file_system_path(const char *path, const file_system_t **fs, const char **fs_path); #ifdef __cplusplus } diff --git a/fs/fs/pkg.yml b/fs/fs/pkg.yml index 10c68746e5..fc3e1eeaae 100644 --- a/fs/fs/pkg.yml +++ b/fs/fs/pkg.yml @@ -26,9 +26,6 @@ pkg.keywords: - filesystem - ffs -pkg.deps: - - "@apache-mynewt-core/fs/disk" - pkg.deps.FS_CLI: - "@apache-mynewt-core/sys/shell" diff --git a/fs/fs/src/fs_dirent.c b/fs/fs/src/fs_dirent.c index c9e46369b6..306a82258a 100644 --- a/fs/fs/src/fs_dirent.c +++ b/fs/fs/src/fs_dirent.c @@ -22,13 +22,13 @@ struct fs_ops *fops_from_filename(const char *); -static struct fs_ops * +static const struct fs_ops * fops_from_dir(const struct fs_dir *dir) { return fs_ops_from_container((struct fops_container *) dir); } -static inline struct fs_ops * +static inline const struct fs_ops * fops_from_dirent(const struct fs_dirent *dirent) { return fs_ops_from_container((struct fops_container *) dirent); @@ -37,21 +37,24 @@ fops_from_dirent(const struct fs_dirent *dirent) int fs_opendir(const char *path, struct fs_dir **out_dir) { - struct fs_ops *fops = fops_from_filename(path); - return fops->f_opendir(path, out_dir); + const file_system_t *fs; + const char *fs_path; + get_file_system_path(path, &fs, &fs_path); + + return fs->ops->f_opendir(fs_path, out_dir); } int fs_readdir(struct fs_dir *dir, struct fs_dirent **out_dirent) { - struct fs_ops *fops = fops_from_dir(dir); + const 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 = fops_from_dir(dir); + const struct fs_ops *fops = fops_from_dir(dir); return fops->f_closedir(dir); } @@ -59,13 +62,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 = fops_from_dirent(dirent); + const 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 = fops_from_dirent(dirent); + const struct fs_ops *fops = fops_from_dirent(dirent); return fops->f_dirent_is_dir(dirent); } diff --git a/fs/fs/src/fs_file.c b/fs/fs/src/fs_file.c index 320a4eacc0..33fee7df40 100644 --- a/fs/fs/src/fs_file.c +++ b/fs/fs/src/fs_file.c @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -123,7 +122,7 @@ fake_dirent_is_dir(const struct fs_dirent *dirent) return FS_EUNINIT; } -struct fs_ops not_initialized_ops = { +const struct fs_ops not_initialized_ops = { .f_open = &fake_open, .f_close = &fake_close, .f_read = &fake_read, @@ -140,13 +139,17 @@ struct fs_ops not_initialized_ops = { .f_closedir = &fake_closedir, .f_dirent_name = &fake_dirent_name, .f_dirent_is_dir = &fake_dirent_is_dir, - .f_name = "fakefs", }; -struct fs_ops * +const file_system_t fake_fs = { + .ops = ¬_initialized_ops, + .name = "fakefs", +}; + +const struct fs_ops * safe_fs_ops_for(const char *fs_name) { - struct fs_ops *fops; + const struct fs_ops *fops; fops = fs_ops_for(fs_name); if (fops == NULL) { @@ -156,31 +159,20 @@ safe_fs_ops_for(const char *fs_name) return fops; } -struct fs_ops * -fops_from_filename(const char *filename) -{ - char *disk; - char *fs_name = NULL; - struct fs_ops *unique; - - disk = disk_name_from_path(filename); - if (disk) { - fs_name = disk_fs_for(disk); - free(disk); - } else { - /** - * special case: if only one fs was ever registered, - * return that fs' ops. - */ - if ((unique = fs_ops_try_unique()) != NULL) { - return unique; +void +get_file_system_path(const char *path, const file_system_t **fs, const char **fs_path) +{ + *fs_path = file_system_path(path, fs); + if (*fs_path == NULL) { + *fs = get_only_file_system(); + if (*fs == NULL) { + *fs = &fake_fs; } + *fs_path = path; } - - return safe_fs_ops_for(fs_name); } -static inline struct fs_ops * +static inline const struct fs_ops * fops_from_file(const struct fs_file *file) { return fs_ops_from_container((struct fops_container *) file); @@ -189,62 +181,68 @@ fops_from_file(const struct fs_file *file) int fs_open(const char *filename, uint8_t access_flags, struct fs_file **out_file) { - struct fs_ops *fops = fops_from_filename(filename); - return fops->f_open(filename, access_flags, out_file); + const file_system_t *fs; + const char *fs_filename; + + get_file_system_path(filename, &fs, &fs_filename); + return fs->ops->f_open(fs_filename, access_flags, out_file); } int fs_close(struct fs_file *file) { - struct fs_ops *fops = fops_from_file(file); + const 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 = fops_from_file(file); + const 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 = fops_from_file(file); + const 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 = fops_from_file(file); + const 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 = fops_from_file(file); + const 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 = fops_from_file(file); + const 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 = fops_from_filename(filename); - return fops->f_unlink(filename); + const file_system_t *fs; + const char *fs_filename; + + get_file_system_path(filename, &fs, &fs_filename); + return fs->ops->f_unlink(fs_filename); } int fs_flush(struct fs_file *file) { - struct fs_ops *fops = fops_from_file(file); + const struct fs_ops *fops = fops_from_file(file); return fops->f_flush(file); } diff --git a/fs/fs/src/fs_mkdir.c b/fs/fs/src/fs_mkdir.c index aca27f59f1..223b5527b9 100644 --- a/fs/fs/src/fs_mkdir.c +++ b/fs/fs/src/fs_mkdir.c @@ -21,18 +21,31 @@ #include "fs_priv.h" -struct fs_ops *fops_from_filename(const char *); - int fs_rename(const char *from, const char *to) { - struct fs_ops *fops = fops_from_filename(from); - return fops->f_rename(from, to); + const file_system_t *fs1; + const file_system_t *fs2; + const char *fs_from; + const char *fs_to; + + get_file_system_path(from, &fs1, &fs_from); + get_file_system_path(to, &fs2, &fs_to); + + if (fs1 == fs2) { + return fs1->ops->f_rename(fs_from, fs_to); + } + + return FS_EINVAL; } int fs_mkdir(const char *path) { - struct fs_ops *fops = fops_from_filename(path); - return fops->f_mkdir(path); + const file_system_t *fs; + const char *fs_path; + + get_file_system_path(path, &fs, &fs_path); + + return fs->ops->f_mkdir(fs_path); } diff --git a/fs/fs/src/fs_mount.c b/fs/fs/src/fs_mount.c index c687cf47c8..567c1f469a 100644 --- a/fs/fs/src/fs_mount.c +++ b/fs/fs/src/fs_mount.c @@ -26,68 +26,134 @@ #include #endif -static SLIST_HEAD(, fs_ops) root_fops = SLIST_HEAD_INITIALIZER(); +#define MAX_MOUNT_POINTS MYNEWT_VAL_FS_MAX_MOUNT_POINTS -#if MYNEWT_VAL(FS_MGMT) -static uint8_t g_mgmt_initialized; -#endif +struct mount_point mount_points[MAX_MOUNT_POINTS]; int -fs_register(struct fs_ops *fops) +fs_mount(const file_system_t *fs, const char *mount_point) { - struct fs_ops *sc; + int free_slot = -1; + int rc = FS_EOK; - SLIST_FOREACH(sc, &root_fops, sc_next) { - if (strcmp(sc->f_name, fops->f_name) == 0) { - return FS_EEXIST; + for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) { + if (mount_points[i].mount_point == NULL) { + if (free_slot < 0) { + free_slot = i; + } + } else if (strcmp(mount_point, mount_points[i].mount_point) == 0) { + rc = FS_EEXIST; + goto end; + } + } + if (free_slot >= 0) { + mount_points[free_slot].mount_point = mount_point; + mount_points[free_slot].fs = fs; + rc = fs->ops->f_mount ? fs->ops->f_mount(fs) : 0; + if (rc) { + mount_points[free_slot].mount_point = NULL; + mount_points[free_slot].fs = NULL; } + } else { + rc = FS_ENOMEM; } +end: + return rc; +} - SLIST_INSERT_HEAD(&root_fops, fops, sc_next); +const file_system_t * +fs_unmount_mount_point(const char *mount_point) +{ + const file_system_t *fs = NULL; + + for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) { + if (strcmp(mount_point, mount_points[i].mount_point) == 0) { + fs = mount_points[i].fs; + mount_points[i].mount_point = NULL; + mount_points[i].fs = NULL; + break; + } + } -#if MYNEWT_VAL(FS_MGMT) - if (!g_mgmt_initialized) { - fs_mgmt_register_group(); - g_mgmt_initialized = 1; + return fs; +} + +int +fs_unmount_file_system(const file_system_t *fs) +{ + int rc = FS_EINVAL; + + for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) { + if (mount_points[i].fs == fs) { + mount_points[i].mount_point = NULL; + mount_points[i].fs = NULL; + rc = 0; + break; + } } + + return rc; +} + +#if MYNEWT_VAL(FS_MGMT) +static uint8_t g_mgmt_initialized; #endif - return FS_EOK; +int +fs_register(struct fs_ops *fops) +{ + return FS_EINVAL; } -struct fs_ops * -fs_ops_try_unique(void) +const file_system_t * +get_only_file_system(void) { - struct fs_ops *fops = SLIST_FIRST(&root_fops); + const file_system_t *fs = NULL; - if (fops && !SLIST_NEXT(fops, sc_next)) { - return fops; + for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) { + if (mount_points[i].mount_point == NULL) { + continue; + } + if (fs != NULL) { + fs = NULL; + break; + } + fs = mount_points[i].fs; } - return NULL; + return fs; } -struct fs_ops * -fs_ops_for(const char *fs_name) +const char * +file_system_path(const char *uri, const file_system_t **fs) { - struct fs_ops *fops = NULL; - struct fs_ops *sc; - - if (fs_name) { - SLIST_FOREACH(sc, &root_fops, sc_next) { - if (strcmp(sc->f_name, fs_name) == 0) { - fops = sc; + const char *fs_path = NULL; + const char *m; + + for (int i = 0; i < ARRAY_SIZE(mount_points); ++i) { + if (mount_points[i].mount_point != NULL) { + fs_path = uri; + m = mount_points[i].mount_point; + while (*fs_path == *m) { + ++fs_path; + ++m; + } + /* Reached end of mount point path ? */ + if (*m == '\0') { + if (fs) { + *fs = mount_points[i].fs; + } break; } + fs_path = NULL; } } - - return fops; + return fs_path; } -extern struct fs_ops not_initialized_ops; +extern const struct fs_ops not_initialized_ops; -struct fs_ops * +const struct fs_ops * fs_ops_from_container(struct fops_container *container) { if (!container) { diff --git a/fs/fs/src/fs_priv.h b/fs/fs/src/fs_priv.h index d5138c938c..a2a3da15ee 100644 --- a/fs/fs/src/fs_priv.h +++ b/fs/fs/src/fs_priv.h @@ -26,8 +26,8 @@ extern "C" { #endif struct fs_ops; -struct fs_ops *fs_ops_for(const char *fs_name); -struct fs_ops *safe_fs_ops_for(const char *fs_name); +const struct fs_ops *fs_ops_for(const char *fs_name); +const struct fs_ops *safe_fs_ops_for(const char *fs_name); #ifdef __cplusplus diff --git a/fs/fs/syscfg.yml b/fs/fs/syscfg.yml index cc676340c1..4cf97388fa 100644 --- a/fs/fs/syscfg.yml +++ b/fs/fs/syscfg.yml @@ -27,6 +27,13 @@ syscfg.defs: description: 'Enables file system mgmt commands.' value: 0 + FS_MAX_MOUNT_POINTS: + description: > + Number of mount point tha can be used. + There should be one mount point for each file system that + could be mounted. + value: 2 + FS_UPLOAD_MAX_CHUNK_SIZE: description: > The maximum amount of file data that can fit in a From ce0e16942f350ce10f49301c6fb70df4b5581158 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Sat, 21 Jun 2025 10:51:55 +0200 Subject: [PATCH 4/7] fs/littlefs: Use mount points This updates littlefs to use fs_mount instead of fs_register. Signed-off-by: Jerzy Kasenberg --- fs/littlefs/src/mynewt_glue.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/littlefs/src/mynewt_glue.c b/fs/littlefs/src/mynewt_glue.c index 9f269d8521..1a72da38d2 100644 --- a/fs/littlefs/src/mynewt_glue.c +++ b/fs/littlefs/src/mynewt_glue.c @@ -23,7 +23,6 @@ #include #include "os/mynewt.h" #include -#include #include #include "lfs.h" @@ -91,8 +90,6 @@ static struct fs_ops littlefs_ops = { .f_dirent_name = littlefs_dirent_name, .f_dirent_is_dir = littlefs_dirent_is_dir, - - .f_name = "littlefs" }; static int @@ -785,6 +782,11 @@ littlefs_reformat(void) return lfs_format(g_lfs, &g_lfs_cfg); } +static const file_system_t littlefs_fs0 = { + .ops = &littlefs_ops, + .name = "littlefs" +}; + int littlefs_init(void) { @@ -816,7 +818,7 @@ littlefs_init(void) } if (!rc) { - fs_register(&littlefs_ops); + fs_mount(&littlefs_fs0, "lfs0:"); } return rc; From f9a2e6ca128dbd2b54f40708b1eb0fa9d6f7b870 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Sat, 21 Jun 2025 21:47:59 +0200 Subject: [PATCH 5/7] fs/nffs: Use mount points This updates nffs to use fs_mount instead of fs_register. Signed-off-by: Jerzy Kasenberg --- fs/nffs/src/nffs.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/fs/nffs/src/nffs.c b/fs/nffs/src/nffs.c index 1dc9c778f7..5315f9354f 100644 --- a/fs/nffs/src/nffs.c +++ b/fs/nffs/src/nffs.c @@ -30,7 +30,6 @@ #include "nffs_priv.h" #include "nffs/nffs.h" #include "fs/fs_if.h" -#include "disk/disk.h" struct nffs_area *nffs_areas; uint8_t nffs_num_areas; @@ -98,8 +97,11 @@ struct fs_ops nffs_ops = { .f_dirent_name = nffs_dirent_name, .f_dirent_is_dir = nffs_dirent_is_dir, +}; - .f_name = "nffs" +const file_system_t nffs_fs0 = { + .ops = &nffs_ops, + .name = "nffs", }; STATS_SECT_DECL(nffs_stats) nffs_stats; @@ -190,7 +192,6 @@ nffs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file) { int rc; struct nffs_file *out_file; - char *filepath = NULL; nffs_lock(); @@ -199,17 +200,12 @@ nffs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file) goto done; } - filepath = disk_filepath_from_path(path); - - rc = nffs_file_open(&out_file, filepath, access_flags); + rc = nffs_file_open(&out_file, path, access_flags); if (rc != 0) { goto done; } *out_fs_file = (struct fs_file *)out_file; done: - if (filepath) { - free(filepath); - } nffs_unlock(); if (rc != 0) { *out_fs_file = NULL; @@ -512,7 +508,6 @@ nffs_opendir(const char *path, struct fs_dir **out_fs_dir) { int rc; struct nffs_dir **out_dir = (struct nffs_dir **)out_fs_dir; - char *filepath = NULL; nffs_lock(); @@ -521,14 +516,9 @@ nffs_opendir(const char *path, struct fs_dir **out_fs_dir) goto done; } - filepath = disk_filepath_from_path(path); - - rc = nffs_dir_open(filepath, out_dir); + rc = nffs_dir_open(path, out_dir); done: - if (filepath) { - free(filepath); - } nffs_unlock(); if (rc != 0) { *out_dir = NULL; @@ -764,7 +754,8 @@ nffs_init(void) return rc; } - fs_register(&nffs_ops); + fs_mount(&nffs_fs0, "nffs:"); + return 0; } From 1046df34a5d11aaf22ac8af7f146caea1a5cc228 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Sat, 21 Jun 2025 22:17:29 +0200 Subject: [PATCH 6/7] fs/fs: Add mount cli command This adds command to show mounted file systems Signed-off-by: Jerzy Kasenberg --- fs/fs/src/fs_cli.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/fs/fs/src/fs_cli.c b/fs/fs/src/fs_cli.c index 9fa932a222..cddfe54d0c 100644 --- a/fs/fs/src/fs_cli.c +++ b/fs/fs/src/fs_cli.c @@ -28,6 +28,7 @@ #include #include "fs/fs.h" +#include "fs/fs_if.h" static void fs_ls_file(const char *name, struct fs_file *file) @@ -160,6 +161,21 @@ fs_mv_cmd(int argc, char **argv) return 0; } +extern struct mount_point mount_points[]; + +static int +fs_mount_cmd(int argc, char **argv) +{ + console_printf("mount points:\n"); + for (int i = 0; i < MYNEWT_VAL_FS_MAX_MOUNT_POINTS; ++i) { + if (mount_points[i].fs) { + console_printf("%s %s\n", mount_points[i].mount_point, mount_points[i].fs->name); + } + } + + return 0; +} + static int fs_cat_cmd(int argc, char **argv) { @@ -198,5 +214,6 @@ MAKE_SHELL_CMD(rm, fs_rm_cmd, NULL) MAKE_SHELL_CMD(mkdir, fs_mkdir_cmd, NULL) MAKE_SHELL_CMD(mv, fs_mv_cmd, NULL) MAKE_SHELL_CMD(cat, fs_cat_cmd, NULL) +MAKE_SHELL_CMD(mount, fs_mount_cmd, NULL) #endif /* MYNEWT_VAL(FS_CLI) */ From 91a964a71d96418d8222d671c53c7a61aae96397 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Sat, 21 Jun 2025 22:30:17 +0200 Subject: [PATCH 7/7] fs/fatfs: Rework to use file system api This adds file disk listener that can mount fatfs disk (like sdcard) if it contains FAT data. Fixes problem with accessing disk grater then 2GB. Previous disk interface (that is now removed) used 32 bit to address bytes of disk. Now disk access uses sectors as it the code for disk. Further more file name conversion from sd0: to 0: is now removed. FATFS driver wants to use 0: volumes and mynewt wanted to have sd0: Now disk will be mounted as 0: removing need for conversion and heap allocations. Signed-off-by: Jerzy Kasenberg --- fs/fatfs/pkg.yml | 8 +- fs/fatfs/src/mynewt_glue.c | 412 ++++++++++++++++--------------------- fs/fatfs/syscfg.yml | 6 + 3 files changed, 187 insertions(+), 239 deletions(-) diff --git a/fs/fatfs/pkg.yml b/fs/fatfs/pkg.yml index 01cef770df..6b389f60f2 100644 --- a/fs/fatfs/pkg.yml +++ b/fs/fatfs/pkg.yml @@ -30,11 +30,11 @@ pkg.deps: - "@apache-mynewt-core/util/crc" - "@apache-mynewt-core/hw/hal" - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/test/testutil" - - "@apache-mynewt-core/sys/flash_map" pkg.req_apis: - log - stats -pkg.init: - fatfs_pkg_init: 'MYNEWT_VAL(FATFS_SYSINIT_STAGE)' +pkg.whole_archive: true + +pkg.cflags: + - -Wno-unused-variable diff --git a/fs/fatfs/src/mynewt_glue.c b/fs/fatfs/src/mynewt_glue.c index 0fbefeb47c..36ef72cacf 100644 --- a/fs/fatfs/src/mynewt_glue.c +++ b/fs/fatfs/src/mynewt_glue.c @@ -22,11 +22,9 @@ #include #include #include -#include "os/mynewt.h" +#include #include -#include #include -#include #include #include @@ -53,17 +51,12 @@ static int fatfs_closedir(struct fs_dir *dir); 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 +static int fatfs_mount(const file_system_t *fs); +static int fatfs_umount(const file_system_t *fs); struct fatfs_file { struct fs_ops *fops; - FIL *file; -}; - -struct fatfs_dir { - struct fs_ops *fops; - FATFS_DIR *dir; + FIL fil; }; struct fatfs_dirent { @@ -71,11 +64,10 @@ struct fatfs_dirent { 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 struct fatfs_dirent dirent; +struct fatfs_dir { + struct fatfs_dirent dirent; + FATFS_DIR dir; +}; static struct fs_ops fatfs_ops = { .f_open = fatfs_open, @@ -99,9 +91,19 @@ static struct fs_ops fatfs_ops = { .f_dirent_name = fatfs_dirent_name, .f_dirent_is_dir = fatfs_dirent_is_dir, - .f_name = "fatfs" + .f_mount = fatfs_mount, + .f_umount = fatfs_umount, }; +typedef struct fat_disk { + file_system_t fs; + char vol[4]; + FATFS fatfs; + disk_t *disk; +} fat_disk_t; + +static fat_disk_t *fat_vol[_VOLUMES]; + int fatfs_to_vfs_error(FRESULT res) { int rc = FS_EOS; @@ -171,112 +173,22 @@ int fatfs_to_vfs_error(FRESULT res) return rc; } -struct mounted_disk { - char *disk_name; - int disk_number; - struct disk_ops *dops; - - 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[6]; - - 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:", (uint8_t)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; - new_disk->dops = disk_ops_for(disk_name); - SLIST_INSERT_HEAD(&mounted_disks, new_disk, sc_next); - - return disk_number; -} - -/** - * Converts fs path to fatfs path - * - * Function changes mmc0:/dir/file.ext to 0:/dir/file.ext - * - * @param fs_path - * @return pointer to allocated memory with fatfs path - */ -static char * -fatfs_path_from_fs_path(const char *fs_path) -{ - char *disk; - int drive_number; - char *file_path = NULL; - char *fatfs_path = NULL; - - disk = disk_name_from_path(fs_path); - if (disk == NULL) { - goto err; - } - drive_number = drivenumber_from_disk(disk); - free(disk); - file_path = disk_filepath_from_path(fs_path); - - if (file_path == NULL) { - goto err; - } - - fatfs_path = malloc(strlen(file_path) + 3); - if (fatfs_path == NULL) { - goto err; - } - sprintf(fatfs_path, "%d:%s", drive_number, file_path); -err: - free(file_path); - return fatfs_path; -} - static int fatfs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file) { FRESULT res; - FIL *out_file = NULL; BYTE mode; struct fatfs_file *file = NULL; - char *fatfs_path = NULL; int rc; FATFS_LOG_DEBUG("Open file %s", path); - file = malloc(sizeof(struct fatfs_file)); + file = os_malloc(sizeof(struct fatfs_file)); if (!file) { rc = FS_ENOMEM; goto out; } - out_file = malloc(sizeof(FIL)); - if (!out_file) { - rc = FS_ENOMEM; - goto out; - } - mode = FA_OPEN_EXISTING; if (access_flags & FS_ACCESS_READ) { mode |= FA_READ; @@ -292,29 +204,21 @@ fatfs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file) mode |= FA_CREATE_ALWAYS; } - fatfs_path = fatfs_path_from_fs_path(path); - if (fatfs_path == NULL) { - rc = FS_ENOMEM; - goto out; - } - res = f_open(out_file, fatfs_path, mode); + res = f_open(&file->fil, path, mode); if (res != FR_OK) { rc = fatfs_to_vfs_error(res); goto out; } - file->file = out_file; file->fops = &fatfs_ops; *out_fs_file = (struct fs_file *) file; rc = FS_EOK; out: - free(fatfs_path); if (rc != FS_EOK) { FATFS_LOG_ERROR("File %s open failed %d", path, rc); if (file) free(file); - if (out_file) free(out_file); } else { FATFS_LOG_DEBUG("File %s opened %p", path, *out_fs_file); } @@ -324,15 +228,12 @@ fatfs_open(const char *path, uint8_t access_flags, struct fs_file **out_fs_file) static int fatfs_close(struct fs_file *fs_file) { - FRESULT res = FR_OK; - FIL *file = ((struct fatfs_file *) fs_file)->file; + struct fatfs_file *fat_file = (struct fatfs_file *)fs_file; + FRESULT res; - FATFS_LOG_DEBUG("Open file %p", fs_file); + FATFS_LOG_DEBUG("Close file %p", fs_file); - if (file != NULL) { - res = f_close(file); - free(file); - } + res = f_close(&fat_file->fil); free(fs_file); return fatfs_to_vfs_error(res); @@ -342,7 +243,7 @@ static int fatfs_seek(struct fs_file *fs_file, uint32_t offset) { FRESULT res; - FIL *file = ((struct fatfs_file *) fs_file)->file; + FIL *file = &((struct fatfs_file *)fs_file)->fil; FATFS_LOG_DEBUG("File %p seek %u", fs_file, offset); @@ -354,7 +255,7 @@ static uint32_t fatfs_getpos(const struct fs_file *fs_file) { uint32_t offset; - FIL *file = ((struct fatfs_file *) fs_file)->file; + FIL *file = &((struct fatfs_file *)fs_file)->fil; offset = (uint32_t) f_tell(file); return offset; @@ -363,7 +264,7 @@ fatfs_getpos(const struct fs_file *fs_file) static int fatfs_file_len(const struct fs_file *fs_file, uint32_t *out_len) { - FIL *file = ((struct fatfs_file *) fs_file)->file; + FIL *file = &((struct fatfs_file *) fs_file)->fil; *out_len = (uint32_t) f_size(file); @@ -377,7 +278,7 @@ fatfs_read(struct fs_file *fs_file, uint32_t len, void *out_data, uint32_t *out_len) { FRESULT res; - FIL *file = ((struct fatfs_file *) fs_file)->file; + FIL *file = &((struct fatfs_file *)fs_file)->fil; UINT uint_len; FATFS_LOG_DEBUG("File %p read %u", fs_file, len); @@ -392,7 +293,7 @@ fatfs_write(struct fs_file *fs_file, const void *data, int len) { FRESULT res; UINT out_len; - FIL *file = ((struct fatfs_file *) fs_file)->file; + FIL *file = &((struct fatfs_file *)fs_file)->fil; FATFS_LOG_DEBUG("File %p write %u", fs_file, len); @@ -407,7 +308,7 @@ static int fatfs_flush(struct fs_file *fs_file) { FRESULT res; - FIL *file = ((struct fatfs_file *)fs_file)->file; + FIL *file = &((struct fatfs_file *)fs_file)->fil; FATFS_LOG_DEBUG("Flush %p", fs_file); @@ -420,17 +321,10 @@ static int fatfs_unlink(const char *path) { FRESULT res; - char *fatfs_path; FATFS_LOG_INFO("Unlink %s", path); - fatfs_path = fatfs_path_from_fs_path(path); - - if (fatfs_path == NULL) { - return FS_ENOMEM; - } - res = f_unlink(fatfs_path); - free(fatfs_path); + res = f_unlink(path); return fatfs_to_vfs_error(res); } @@ -439,23 +333,10 @@ static int fatfs_rename(const char *from, const char *to) { FRESULT res; - char *fatfs_src_path; - char *fatfs_dst_path; FATFS_LOG_INFO("Rename %s to %s", from, to); - fatfs_src_path = fatfs_path_from_fs_path(from); - fatfs_dst_path = fatfs_path_from_fs_path(to); - - if (fatfs_src_path == NULL || fatfs_dst_path == NULL) { - free(fatfs_src_path); - free(fatfs_dst_path); - return FS_ENOMEM; - } - - res = f_rename(fatfs_src_path, fatfs_dst_path); - free(fatfs_src_path); - free(fatfs_dst_path); + res = f_rename(from, to); return fatfs_to_vfs_error(res); } @@ -464,17 +345,10 @@ static int fatfs_mkdir(const char *path) { FRESULT res; - char *fatfs_path; FATFS_LOG_INFO("Mkdir %s", path); - fatfs_path = fatfs_path_from_fs_path(path); - - if (fatfs_path == NULL) { - return FS_ENOMEM; - } - - res = f_mkdir(fatfs_path); + res = f_mkdir(path); return fatfs_to_vfs_error(res); } @@ -482,45 +356,34 @@ static int fatfs_opendir(const char *path, struct fs_dir **out_fs_dir) { FRESULT res; - FATFS_DIR *out_dir = NULL; struct fatfs_dir *dir = NULL; - char *fatfs_path = NULL; int rc; - dir = malloc(sizeof(struct fatfs_dir)); + dir = os_malloc(sizeof(struct fatfs_dir)); if (!dir) { rc = FS_ENOMEM; goto out; } + dir->dirent.fops = &fatfs_ops; - out_dir = malloc(sizeof(FATFS_DIR)); - if (!out_dir) { - rc = FS_ENOMEM; - goto out; - } - - fatfs_path = fatfs_path_from_fs_path(path); - - res = f_opendir(out_dir, fatfs_path); + res = f_opendir(&dir->dir, path); if (res != FR_OK) { 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; FATFS_LOG_INFO("Open dir %s -> %p", path, *out_fs_dir); out: - free(fatfs_path); if (rc != FS_EOK) { FATFS_LOG_ERROR("Open dir %s failed %d", path, rc); - if (dir) free(dir); - if (out_dir) free(out_dir); + if (dir) { + os_free(dir); + } } return rc; } @@ -529,18 +392,18 @@ static int fatfs_readdir(struct fs_dir *fs_dir, struct fs_dirent **out_fs_dirent) { FRESULT res; - FATFS_DIR *dir = ((struct fatfs_dir *) fs_dir)->dir; + struct fatfs_dir *fat_dir = ((struct fatfs_dir *)fs_dir); + FATFS_DIR *dir = &fat_dir->dir; FATFS_LOG_DEBUG("Read dir %p", fs_dir); - dirent.fops = &fatfs_ops; - res = f_readdir(dir, &dirent.filinfo); + res = f_readdir(dir, &fat_dir->dirent.filinfo); if (res != FR_OK) { return fatfs_to_vfs_error(res); } - *out_fs_dirent = (struct fs_dirent *) &dirent; - if (!dirent.filinfo.fname[0]) { + *out_fs_dirent = (struct fs_dirent *)&fat_dir->dirent; + if (!fat_dir->dirent.filinfo.fname[0]) { return FS_ENOENT; } return FS_EOK; @@ -550,13 +413,13 @@ static int fatfs_closedir(struct fs_dir *fs_dir) { FRESULT res; - FATFS_DIR *dir = ((struct fatfs_dir *) fs_dir)->dir; + FATFS_DIR *dir = &((struct fatfs_dir *) fs_dir)->dir; FATFS_LOG_INFO("Close dir %p", fs_dir); res = f_closedir(dir); - free(dir); - free(fs_dir); + + os_free(fs_dir); return fatfs_to_vfs_error(res); } @@ -585,6 +448,30 @@ fatfs_dirent_is_dir(const struct fs_dirent *fs_dirent) return filinfo->fattrib & AM_DIR; } +static int +fatfs_mount(const file_system_t *fs) +{ + int rc; + fat_disk_t *fat_disk = (fat_disk_t *)fs; + + /* Pass to FAT driver */ + rc = f_mount(&fat_disk->fatfs, fat_disk->vol, 0); + + return rc; +} + +static int +fatfs_umount(const file_system_t *fs) +{ + int rc; + fat_disk_t *fat_disk = (fat_disk_t *)fs; + + /* Pass to FAT driver */ + rc = f_mount(NULL, fat_disk->vol, 0); + + return rc; +} + DSTATUS disk_initialize(BYTE pdrv) { @@ -599,67 +486,40 @@ disk_status(BYTE pdrv) return RES_OK; } -static struct disk_ops *dops_from_handle(BYTE pdrv) -{ - struct mounted_disk *sc; - - SLIST_FOREACH(sc, &mounted_disks, sc_next) { - if (sc->disk_number == pdrv) { - return sc->dops; - } - } - - return NULL; -} - DRESULT disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { int rc; - uint32_t address; - uint32_t num_bytes; - struct disk_ops *dops; - - /* NOTE: safe to assume sector size as 512 for now, see ffconf.h */ - address = (uint32_t) sector * 512; - num_bytes = (uint32_t) count * 512; - - dops = dops_from_handle(pdrv); - if (dops == NULL) { - return STA_NOINIT; - } + struct fat_disk *fat_disk = fat_vol[pdrv]; - rc = dops->read(pdrv, address, (void *) buff, num_bytes); - if (rc < 0) { - return STA_NOINIT; + if (fat_disk != NULL) { + rc = mn_disk_read(fat_disk->disk, sector, buff, count); + if (rc != 0) { + rc = FR_NOT_READY; + } + } else { + rc = FR_NOT_READY; } - return RES_OK; + return rc; } DRESULT disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { int rc; - uint32_t address; - uint32_t num_bytes; - struct disk_ops *dops; - - /* NOTE: safe to assume sector size as 512 for now, see ffconf.h */ - address = (uint32_t) sector * 512; - num_bytes = (uint32_t) count * 512; - - dops = dops_from_handle(pdrv); - if (dops == NULL) { - return STA_NOINIT; - } + struct fat_disk *fat_disk = fat_vol[pdrv]; - rc = dops->write(pdrv, address, (const void *) buff, num_bytes); - if (rc < 0) { - return STA_NOINIT; + if (fat_disk != NULL) { + rc = mn_disk_write(fat_disk->disk, sector, buff, count); + if (rc != 0) { + rc = FR_NOT_READY; + } + } else { + rc = FR_NOT_READY; } - return RES_OK; + return rc; } DRESULT @@ -742,11 +602,93 @@ ff_wtoupper(WCHAR chr) return toupper(chr); } -void -fatfs_pkg_init(void) +#if MYNEWT_VAL_FATFS_AUTO_MOUNT_DISKS +int fatfs_disk_added(struct disk_listener *listener, struct disk *disk) +{ + fat_disk_t *fat_disk; + int i; + int rc; + + for (i = 0; i < _VOLUMES; ++i) { + if (fat_vol[i] == NULL) { + break; + } + } + if (i >= _VOLUMES) { + fat_disk = NULL; + FATFS_LOG_ERROR("Can mount additional volumes"); + goto end; + } + fat_disk = os_malloc(sizeof(*fat_disk)); + + if (fat_disk == NULL) { + FATFS_LOG_ERROR("No enough heap for FAT file system"); + goto end; + } + + if (mn_disk_read(disk, 0, fat_disk->fatfs.win, 1) == 0) { + disk_info_t di; + uint8_t fs_type = fat_disk->fatfs.win[450]; + mn_disk_info_get(disk, &di); + + /* Check if first partition is FAT */ + if (fs_type == 0x0C || fs_type == 0x0B || (_FS_EXFAT && fs_type == 0x07)) { + fat_disk->disk = disk; + fat_disk->fs.ops = &fatfs_ops; + fat_disk->fs.name = "fatfs"; + fat_disk->vol[0] = '0' + i; + fat_disk->vol[1] = ':'; + fat_disk->vol[2] = '\0'; + + /* Associate in mynewt */ + rc = fs_mount(&fat_disk->fs, fat_disk->vol); + if (rc != 0) { + FATFS_LOG_ERROR("Can't mount FAT file system"); + } else { + fat_vol[i] = fat_disk; + /* Disk successfully mounted, prevent from being freed */ + FATFS_LOG_INFO("Mounted FAT partition from %s at %s", di.name, fat_disk->vol); + fat_disk = NULL; + } + } else { + FATFS_LOG_INFO("Disk %s not with FAT file system", di.name); + } + } +end: + if (fat_disk) { + os_free(fat_disk); + } + return 0; +} + +int fatfs_disk_removed(struct disk_listener *listener, struct disk *disk) { - /* Ensure this function only gets called by sysinit. */ - SYSINIT_ASSERT_ACTIVE(); + int i; + int rc = FS_EINVAL; + struct fat_disk *fat_disk; - fs_register(&fatfs_ops); + for (i = 0; i < _VOLUMES; ++i) { + fat_disk = fat_vol[i]; + if (fat_disk->disk == disk) { + fs_unmount_file_system(&fat_disk->fs); + fat_vol[i] = NULL; + os_free(fat_disk); + rc = 0; + break; + } + } + return rc; } + +const disk_listener_ops_t fatfs_disk_listener_ops = { + .disk_added = fatfs_disk_added, + .disk_removed = fatfs_disk_removed, +}; + +disk_listener_t fatfs_disk_listener = { + .ops = &fatfs_disk_listener_ops, +}; + +DISK_LISTENER(fatfs_disk_listener_ptr, fatfs_disk_listener) + +#endif diff --git a/fs/fatfs/syscfg.yml b/fs/fatfs/syscfg.yml index 66035279b4..93c85f9476 100644 --- a/fs/fatfs/syscfg.yml +++ b/fs/fatfs/syscfg.yml @@ -48,6 +48,12 @@ syscfg.defs: Timout for locking file system object. value: 1000 + FATFS_AUTO_MOUNT_DISKS: + description: > + If 1 package tries to read every disks that is inserted + and if it's FAT disk, mounts it automatically. + value: 1 + FATFS_LOG_MODULE: description: 'Numeric module ID to use for FATFS log messages.' value: 253