diff --git a/include/fs.h b/include/fs.h index c2fea3300d2..de35d7a5957 100644 --- a/include/fs.h +++ b/include/fs.h @@ -8,23 +8,26 @@ #define _FS_H_ #include +#include #include #ifdef __cplusplus extern "C" { #endif -/* Create a fs_file_t type similar to FILE for familiarity */ -typedef struct _fs_file_object fs_file_t; - -/* Create a fs_dir_t type similar to DIR for familiarity */ -typedef struct _fs_dir_object fs_dir_t; +struct fs_file_system_t; enum fs_dir_entry_type { - FS_DIR_ENTRY_FILE, + FS_DIR_ENTRY_FILE = 0, FS_DIR_ENTRY_DIR }; +enum fs_type { + FS_FATFS = 0, + FS_NFFS, + FS_TYPE_END, +}; + /** * @brief File System * @defgroup file_system File System @@ -39,13 +42,27 @@ enum fs_dir_entry_type { * @{ */ -/** @var fs_file_t - * @brief File object representing an open file - */ - -/** @var fs_dir_t - * @brief Directory object representing an open directory +/** + * @brief File system mount info structure + * + * @param node Entry for the fs_mount_list list + * @param type File system type + * @param mnt_point Mount point directory name (ex: "/fatfs") + * @param fs_data Pointer to file system specific data + * @param storage_dev Pointer to backend storage device + * @param mountp_len Length of Mount point string + * @param fs Pointer to File system interface of the mount point */ +struct fs_mount_t { + sys_dnode_t node; + enum fs_type type; + const char *mnt_point; + void *fs_data; + struct device *storage_dev; + /* fields filled by file system core */ + size_t mountp_len; + const struct fs_file_system_t *fs; +}; /** * @brief Structure to receive file or directory information @@ -83,6 +100,56 @@ struct fs_statvfs { unsigned long f_bfree; }; +/** + * @brief File System interface structure + * + * @param open Opens an existing file or create a new one + * @param read Reads items of data of size bytes long + * @param write Writes items of data of size bytes long + * @param lseek Moves the file position to a new location in the file + * @param tell Retrieves the current position in the file + * @param truncate Truncates the file to the new length + * @param sync Flush the cache of an open file + * @param close Flushes the associated stream and closes the file + * @param opendir Opens an existing directory specified by the path + * @param readdir Reads directory entries of a open directory + * @param closedir Closes an open directory + * @param mount Mount a file system + * @param unmount Unmount a file system + * @param unlink Deletes the specified file or directory + * @param rename Renames a file or directory + * @param mkdir Creates a new directory using specified path + * @param stat Checks the status of a file or directory specified by the path + * @param statvfs Returns the total and available space in the filesystem volume + */ +struct fs_file_system_t { + /* File operations */ + int (*open)(struct fs_file_t *filp, const char *fs_path); + ssize_t (*read)(struct fs_file_t *filp, void *dest, size_t nbytes); + ssize_t (*write)(struct fs_file_t *filp, + const void *src, size_t nbytes); + int (*lseek)(struct fs_file_t *filp, off_t off, int whence); + off_t (*tell)(struct fs_file_t *filp); + int (*truncate)(struct fs_file_t *filp, off_t length); + int (*sync)(struct fs_file_t *filp); + int (*close)(struct fs_file_t *filp); + /* Directory operations */ + int (*opendir)(struct fs_dir_t *dirp, const char *fs_path); + int (*readdir)(struct fs_dir_t *dirp, struct fs_dirent *entry); + int (*closedir)(struct fs_dir_t *dirp); + /* File system level operations */ + int (*mount)(struct fs_mount_t *mountp); + int (*unmount)(struct fs_mount_t *mountp); + int (*unlink)(struct fs_mount_t *mountp, const char *name); + int (*rename)(struct fs_mount_t *mountp, const char *from, + const char *to); + int (*mkdir)(struct fs_mount_t *mountp, const char *name); + int (*stat)(struct fs_mount_t *mountp, const char *path, + struct fs_dirent *entry); + int (*statvfs)(struct fs_mount_t *mountp, const char *path, + struct fs_statvfs *stat); +}; + /** * @} */ @@ -116,7 +183,7 @@ struct fs_statvfs { * @retval 0 Success * @retval -ERRNO errno code if error */ -int fs_open(fs_file_t *zfp, const char *file_name); +int fs_open(struct fs_file_t *zfp, const char *file_name); /** * @brief File close @@ -129,7 +196,7 @@ int fs_open(fs_file_t *zfp, const char *file_name); * @retval 0 Success * @retval -ERRNO errno code if error */ -int fs_close(fs_file_t *zfp); +int fs_close(struct fs_file_t *zfp); /** * @brief File unlink @@ -143,6 +210,26 @@ int fs_close(fs_file_t *zfp); */ int fs_unlink(const char *path); +/** + * @brief File o directory rename + * + * Performs a rename and / or move of the specified source path to the + * specified destination. The source path can refer to either a file or a + * directory. All intermediate directories in the destination path must + * already exist. If the source path refers to a file, the destination path + * must contain a full filename path, rather than just the new parent + * directory. If an object already exists at the specified destination path, + * this function causes it to be unlinked prior to the rename (i.e., the + * estination gets clobbered). + * + * @param from The source path. + * @param to The destination path. + * + * @retval 0 Success; + * @retval -ERRNO errno code if error + */ +int fs_rename(const char *from, const char *to); + /** * @brief File read * @@ -157,7 +244,7 @@ int fs_unlink(const char *path); * requested if there are not enough bytes available in file. Will return * -ERRNO code on error. */ -ssize_t fs_read(fs_file_t *zfp, void *ptr, size_t size); +ssize_t fs_read(struct fs_file_t *zfp, void *ptr, size_t size); /** * @brief File write @@ -178,7 +265,7 @@ ssize_t fs_read(fs_file_t *zfp, void *ptr, size_t size); * In that case, it returns less number of bytes written than requested, but * not a negative -ERRNO value as in regular error case. */ -ssize_t fs_write(fs_file_t *zfp, const void *ptr, size_t size); +ssize_t fs_write(struct fs_file_t *zfp, const void *ptr, size_t size); /** * @brief File seek @@ -196,7 +283,7 @@ ssize_t fs_write(fs_file_t *zfp, const void *ptr, size_t size); * @retval 0 Success * @retval -ERRNO errno code if error. */ -int fs_seek(fs_file_t *zfp, off_t offset, int whence); +int fs_seek(struct fs_file_t *zfp, off_t offset, int whence); /** * @brief Get current file position. @@ -208,7 +295,7 @@ int fs_seek(fs_file_t *zfp, off_t offset, int whence); * @retval position Current position in file * Current revision does not validate the file object. */ -off_t fs_tell(fs_file_t *zfp); +off_t fs_tell(struct fs_file_t *zfp); /** * @brief Change the size of an open file @@ -228,7 +315,7 @@ off_t fs_tell(fs_file_t *zfp); * @retval 0 Success * @retval -ERRNO errno code if error */ -int fs_truncate(fs_file_t *zfp, off_t length); +int fs_truncate(struct fs_file_t *zfp, off_t length); /** * @brief Flushes any cached write of an open file @@ -244,7 +331,7 @@ int fs_truncate(fs_file_t *zfp, off_t length); * @retval 0 Success * @retval -ERRNO errno code if error */ -int fs_sync(fs_file_t *zfp); +int fs_sync(struct fs_file_t *zfp); /** * @brief Directory create @@ -269,7 +356,7 @@ int fs_mkdir(const char *path); * @retval 0 Success * @retval -ERRNO errno code if error */ -int fs_opendir(fs_dir_t *zdp, const char *path); +int fs_opendir(struct fs_dir_t *zdp, const char *path); /** * @brief Directory read entry @@ -284,7 +371,7 @@ int fs_opendir(fs_dir_t *zdp, const char *path); * @return In end-of-dir condition, this will return 0 and set * entry->name[0] = 0 */ -int fs_readdir(fs_dir_t *zdp, struct fs_dirent *entry); +int fs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry); /** * @brief Directory close @@ -296,7 +383,36 @@ int fs_readdir(fs_dir_t *zdp, struct fs_dirent *entry); * @retval 0 Success * @retval -ERRNO errno code if error */ -int fs_closedir(fs_dir_t *zdp); +int fs_closedir(struct fs_dir_t *zdp); + +/** + * @brief Mount filesystem + * + * Perform steps needed for mounting a file system like + * calling the file system specific mount function and adding + * the mount point to mounted file system list. + * + * @param mp Pointer to the fs_mount_t structure + * + * @retval 0 Success + * @retval -ERRNO errno code if error + */ +int fs_mount(struct fs_mount_t *mp); + +/** + * @brief Unmount filesystem + * + * Perform steps needed for unmounting a file system like + * calling the file system specific unmount function and removing + * the mount point from mounted file system list. + * + * + * @param mp Pointer to the fs_mount_t structure + * + * @retval 0 Success + * @retval -ERRNO errno code if error + */ +int fs_unmount(struct fs_mount_t *mp); /** * @brief File or directory status @@ -317,17 +433,45 @@ int fs_stat(const char *path, struct fs_dirent *entry); * * Returns the total and available space in the file system volume. * + * @param path Path to the mounted directory * @param stat Pointer to zfs_statvfs structure to receive the fs statistics * * @retval 0 Success * @retval -ERRNO errno code if error */ -int fs_statvfs(struct fs_statvfs *stat); +int fs_statvfs(const char *path, struct fs_statvfs *stat); + +/** + * @brief Register a file system + * + * Register file system with virtual file system. + * + * @param type Type of file system (ex: FS_FATFS) + * @param fs Pointer to File system + * + * @retval 0 Success + * @retval -ERRNO errno code if error + */ +int fs_register(enum fs_type type, struct fs_file_system_t *fs); + +/** + * @brief Unregister a file system + * + * Unregister file system from virtual file system. + * + * @param type Type of file system (ex: FS_FATFS) + * @param fs Pointer to File system + * + * @retval 0 Success + * @retval -ERRNO errno code if error + */ +int fs_unregister(enum fs_type type, struct fs_file_system_t *fs); /** * @} */ + #ifdef __cplusplus } #endif diff --git a/include/fs/fat_fs.h b/include/fs/fat_fs.h deleted file mode 100644 index 8bc3842fc90..00000000000 --- a/include/fs/fat_fs.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2016 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _FAT_FS_H_ -#define _FAT_FS_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -FS_FILE_DEFINE(FIL fp); -FS_DIR_DEFINE(DIR dp); - -#define MAX_FILE_NAME 12 /* Uses 8.3 SFN */ - -static inline off_t fs_tell(struct _fs_file_object *zfp) -{ - return f_tell(&zfp->fp); -} - -#ifdef __cplusplus -} -#endif - -#endif /* _FAT_FS_H_ */ diff --git a/include/fs/fs_interface.h b/include/fs/fs_interface.h index d47c698a359..7b4f02d575d 100644 --- a/include/fs/fs_interface.h +++ b/include/fs/fs_interface.h @@ -7,46 +7,64 @@ #ifndef _FS_INTERFACE_H_ #define _FS_INTERFACE_H_ +#ifdef CONFIG_FAT_FILESYSTEM_ELM +#include +#endif + +#ifdef CONFIG_FILE_SYSTEM_NFFS +#include +#endif + #ifdef __cplusplus extern "C" { #endif -/* - * @brief Macro to define _zfile_object structure - * - * This structure contains information about the open files. This - * structure will be passed to the api functions as an opaque - * pointer. - * - * @param _file_object File structure used by underlying file system - */ - -#define FS_FILE_DEFINE(_file_object) \ - struct _fs_file_object { \ - _file_object; \ - } - -/* - * @brief Macro to define _zdir_object structure - * - * This structure contains information about the open directories. This - * structure will be passed to the directory api functions as an opaque - * pointer. - * - * @param _dir_object Directory structure used by underlying file system - */ - -#define FS_DIR_DEFINE(_dir_object) \ - struct _fs_dir_object { \ - _dir_object; \ - } - -#ifdef CONFIG_FAT_FILESYSTEM_ELM -#include -#elif CONFIG_FILE_SYSTEM_NFFS -#include +#ifdef CONFIG_FILE_SYSTEM_NFFS +#define MAX_FILE_NAME 256 +#else /* FAT_FS */ +#define MAX_FILE_NAME 12 /* Uses 8.3 SFN */ #endif +struct fs_mount_t; + +/** + * @brief File object representing an open file + * + * @param fatfs_fp FATFS file object structure + * @param nffs_fp NFFS file object structure + * @param mp Pointer to mount point structure + */ +struct fs_file_t { + union { +#ifdef CONFIG_FAT_FILESYSTEM_ELM + FIL fatfs_fp; +#endif +#ifdef CONFIG_FILE_SYSTEM_NFFS + struct nffs_file *nffs_fp; +#endif + }; + const struct fs_mount_t *mp; +}; + +/** + * @brief Directory object representing an open directory + * + * @param fatfs_dp FATFS directory object structure + * @param nffs_dp NFFS directory object structure + * @param mp Pointer to mount point structure + */ +struct fs_dir_t { + union { +#ifdef CONFIG_FAT_FILESYSTEM_ELM + DIR fatfs_dp; +#endif +#ifdef CONFIG_FILE_SYSTEM_NFFS + struct nffs_dir *nffs_dp; +#endif + }; + const struct fs_mount_t *mp; +}; + #ifdef __cplusplus } #endif diff --git a/include/fs/nffs_fs.h b/include/fs/nffs_fs.h deleted file mode 100644 index b4ecd901e80..00000000000 --- a/include/fs/nffs_fs.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2017 Codecoup - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef _NFFS_FS_H_ -#define _NFFS_FS_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -FS_FILE_DEFINE(struct nffs_file *fp); -FS_DIR_DEFINE(struct nffs_dir *dp); - -#define MAX_FILE_NAME 256 - -#ifdef __cplusplus -} -#endif - -#endif /* _NFFS_FS_H_ */ diff --git a/subsys/fs/CMakeLists.txt b/subsys/fs/CMakeLists.txt index 5f2be846ac8..7af5db294ee 100644 --- a/subsys/fs/CMakeLists.txt +++ b/subsys/fs/CMakeLists.txt @@ -3,6 +3,7 @@ if(CONFIG_FILE_SYSTEM) zephyr_link_interface_ifdef(CONFIG_FILE_SYSTEM_NFFS NFFS) zephyr_library() + zephyr_library_sources(fs.c) zephyr_library_sources_ifdef(CONFIG_FAT_FILESYSTEM_ELM fat_fs.c) zephyr_library_sources_ifdef(CONFIG_FILE_SYSTEM_NFFS nffs_fs.c) zephyr_library_sources_ifdef(CONFIG_FILE_SYSTEM_SHELL shell.c) diff --git a/subsys/fs/fat_fs.c b/subsys/fs/fat_fs.c index 151825a3e21..2d8b0d6795c 100644 --- a/subsys/fs/fat_fs.c +++ b/subsys/fs/fat_fs.c @@ -9,11 +9,10 @@ #include #include #include -#include #include #include -static FATFS fat_fs; /* FatFs work area */ +#define FATFS_MAX_FILE_NAME 12 /* Uses 8.3 SFN */ static int translate_error(int error) { @@ -54,28 +53,28 @@ static int translate_error(int error) return -EIO; } -int fs_open(fs_file_t *zfp, const char *file_name) +static int fatfs_open(struct fs_file_t *zfp, const char *file_name) { FRESULT res; u8_t fs_mode; fs_mode = FA_READ | FA_WRITE | FA_OPEN_ALWAYS; - res = f_open(&zfp->fp, file_name, fs_mode); + res = f_open(&zfp->fatfs_fp, file_name, fs_mode); return translate_error(res); } -int fs_close(fs_file_t *zfp) +static int fatfs_close(struct fs_file_t *zfp) { FRESULT res; - res = f_close(&zfp->fp); + res = f_close(&zfp->fatfs_fp); return translate_error(res); } -int fs_unlink(const char *path) +static int fatfs_unlink(struct fs_mount_t *mountp, const char *path) { FRESULT res; @@ -84,12 +83,12 @@ int fs_unlink(const char *path) return translate_error(res); } -ssize_t fs_read(fs_file_t *zfp, void *ptr, size_t size) +static ssize_t fatfs_read(struct fs_file_t *zfp, void *ptr, size_t size) { FRESULT res; unsigned int br; - res = f_read(&zfp->fp, ptr, size, &br); + res = f_read(&zfp->fatfs_fp, ptr, size, &br); if (res != FR_OK) { return translate_error(res); } @@ -97,12 +96,12 @@ ssize_t fs_read(fs_file_t *zfp, void *ptr, size_t size) return br; } -ssize_t fs_write(fs_file_t *zfp, const void *ptr, size_t size) +static ssize_t fatfs_write(struct fs_file_t *zfp, const void *ptr, size_t size) { FRESULT res; unsigned int bw; - res = f_write(&zfp->fp, ptr, size, &bw); + res = f_write(&zfp->fatfs_fp, ptr, size, &bw); if (res != FR_OK) { return translate_error(res); } @@ -110,7 +109,7 @@ ssize_t fs_write(fs_file_t *zfp, const void *ptr, size_t size) return bw; } -int fs_seek(fs_file_t *zfp, off_t offset, int whence) +static int fatfs_seek(struct fs_file_t *zfp, off_t offset, int whence) { FRESULT res = FR_OK; off_t pos; @@ -120,46 +119,51 @@ int fs_seek(fs_file_t *zfp, off_t offset, int whence) pos = offset; break; case FS_SEEK_CUR: - pos = f_tell(&zfp->fp) + offset; + pos = f_tell(&zfp->fatfs_fp) + offset; break; case FS_SEEK_END: - pos = f_size(&zfp->fp) + offset; + pos = f_size(&zfp->fatfs_fp) + offset; break; default: return -EINVAL; } - if ((pos < 0) || (pos > f_size(&zfp->fp))) { + if ((pos < 0) || (pos > f_size(&zfp->fatfs_fp))) { return -EINVAL; } - res = f_lseek(&zfp->fp, pos); + res = f_lseek(&zfp->fatfs_fp, pos); return translate_error(res); } -int fs_truncate(fs_file_t *zfp, off_t length) +static off_t fatfs_tell(struct fs_file_t *zfp) +{ + return f_tell(&zfp->fatfs_fp); +} + +static int fatfs_truncate(struct fs_file_t *zfp, off_t length) { FRESULT res = FR_OK; - off_t cur_length = f_size(&zfp->fp); + off_t cur_length = f_size(&zfp->fatfs_fp); /* f_lseek expands file if new position is larger than file size */ - res = f_lseek(&zfp->fp, length); + res = f_lseek(&zfp->fatfs_fp, length); if (res != FR_OK) { return translate_error(res); } if (length < cur_length) { - res = f_truncate(&zfp->fp); + res = f_truncate(&zfp->fatfs_fp); } else { /* * Get actual length after expansion. This could be * less if there was not enough space in the volume * to expand to the requested length */ - length = f_tell(&zfp->fp); + length = f_tell(&zfp->fatfs_fp); - res = f_lseek(&zfp->fp, cur_length); + res = f_lseek(&zfp->fatfs_fp, cur_length); if (res != FR_OK) { return translate_error(res); } @@ -174,7 +178,7 @@ int fs_truncate(fs_file_t *zfp, off_t length) u8_t c = 0; for (int i = cur_length; i < length; i++) { - res = f_write(&zfp->fp, &c, 1, &bw); + res = f_write(&zfp->fatfs_fp, &c, 1, &bw); if (res != FR_OK) { break; } @@ -184,16 +188,16 @@ int fs_truncate(fs_file_t *zfp, off_t length) return translate_error(res); } -int fs_sync(fs_file_t *zfp) +static int fatfs_sync(struct fs_file_t *zfp) { FRESULT res = FR_OK; - res = f_sync(&zfp->fp); + res = f_sync(&zfp->fatfs_fp); return translate_error(res); } -int fs_mkdir(const char *path) +static int fatfs_mkdir(struct fs_mount_t *mountp, const char *path) { FRESULT res; @@ -202,21 +206,21 @@ int fs_mkdir(const char *path) return translate_error(res); } -int fs_opendir(fs_dir_t *zdp, const char *path) +static int fatfs_opendir(struct fs_dir_t *zdp, const char *path) { FRESULT res; - res = f_opendir(&zdp->dp, path); + res = f_opendir(&zdp->fatfs_dp, path); return translate_error(res); } -int fs_readdir(fs_dir_t *zdp, struct fs_dirent *entry) +static int fatfs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry) { FRESULT res; FILINFO fno; - res = f_readdir(&zdp->dp, &fno); + res = f_readdir(&zdp->fatfs_dp, &fno); if (res == FR_OK) { entry->type = ((fno.fattrib & AM_DIR) ? FS_DIR_ENTRY_DIR : FS_DIR_ENTRY_FILE); @@ -227,16 +231,17 @@ int fs_readdir(fs_dir_t *zdp, struct fs_dirent *entry) return translate_error(res); } -int fs_closedir(fs_dir_t *zdp) +static int fatfs_closedir(struct fs_dir_t *zdp) { FRESULT res; - res = f_closedir(&zdp->dp); + res = f_closedir(&zdp->fatfs_dp); return translate_error(res); } -int fs_stat(const char *path, struct fs_dirent *entry) +static int fatfs_stat(struct fs_mount_t *mountp, + const char *path, struct fs_dirent *entry) { FRESULT res; FILINFO fno; @@ -252,7 +257,8 @@ int fs_stat(const char *path, struct fs_dirent *entry) return translate_error(res); } -int fs_statvfs(struct fs_statvfs *stat) +static int fatfs_statvfs(struct fs_mount_t *mountp, + const char *path, struct fs_statvfs *stat) { FATFS *fs; FRESULT res; @@ -273,13 +279,11 @@ int fs_statvfs(struct fs_statvfs *stat) return translate_error(res); } -static int fs_init(struct device *dev) +static int fatfs_mount(struct fs_mount_t *mountp) { FRESULT res; - ARG_UNUSED(dev); - - res = f_mount(&fat_fs, "", 1); + res = f_mount((FATFS *)mountp->fs_data, "", 1); /* If no file system found then create one */ if (res == FR_NO_FILESYSTEM) { @@ -287,13 +291,41 @@ static int fs_init(struct device *dev) res = f_mkfs("", (FM_FAT | FM_SFD), 0, work, sizeof(work)); if (res == FR_OK) { - res = f_mount(&fat_fs, "", 1); + res = f_mount((FATFS *)mountp->fs_data, "", 1); } } __ASSERT((res == FR_OK), "FS init failed (%d)", translate_error(res)); return translate_error(res); + } -SYS_INIT(fs_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +/* File system interface */ +static struct fs_file_system_t fatfs_fs = { + .open = fatfs_open, + .close = fatfs_close, + .read = fatfs_read, + .write = fatfs_write, + .lseek = fatfs_seek, + .tell = fatfs_tell, + .truncate = fatfs_truncate, + .sync = fatfs_sync, + .opendir = fatfs_opendir, + .readdir = fatfs_readdir, + .closedir = fatfs_closedir, + .mount = fatfs_mount, + .unlink = fatfs_unlink, + .mkdir = fatfs_mkdir, + .stat = fatfs_stat, + .statvfs = fatfs_statvfs, +}; + +static int fatfs_init(struct device *dev) +{ + ARG_UNUSED(dev); + + return fs_register(FS_FATFS, &fatfs_fs); +} + +SYS_INIT(fatfs_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/subsys/fs/fs.c b/subsys/fs/fs.c new file mode 100644 index 00000000000..5d4689d9ca2 --- /dev/null +++ b/subsys/fs/fs.c @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_FS_LEVEL +#include + +/* list of mounted file systems */ +static sys_dlist_t fs_mnt_list; + +/* lock to protect mount list operations */ +static struct k_mutex mutex; + +/* file system map table */ +static struct fs_file_system_t *fs_map[FS_TYPE_END]; + +int get_mnt_point(struct fs_mount_t **mnt_pntp, + const char *name, size_t *match_len) +{ + struct fs_mount_t *mnt_p = NULL, *itr; + size_t longest_match = 0; + size_t len, name_len = strlen(name); + sys_dnode_t *node; + + k_mutex_lock(&mutex, K_FOREVER); + SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) { + itr = CONTAINER_OF(node, struct fs_mount_t, node); + len = itr->mountp_len; + + /* + * Move to next node if mount point length is + * shorter than longest_match match or if path + * name is shorter than the mount point name. + */ + if ((len < longest_match) || (len > name_len)) { + continue; + } + + /* + * Move to next node if name does not have a directory + * separator where mount point name ends. + */ + if ((len > 1) && (name[len] != '/') && (name[len] != '\0')) { + continue; + } + + /* Check for mount point match */ + if (strncmp(name, itr->mnt_point, len) == 0) { + mnt_p = itr; + longest_match = len; + } + } + k_mutex_unlock(&mutex); + + if (mnt_p == NULL) { + return -ENOENT; + } + + *mnt_pntp = mnt_p; + *match_len = mnt_p->mountp_len; + return 0; +} + +/* File operations */ +int fs_open(struct fs_file_t *zfp, const char *file_name) +{ + struct fs_mount_t *mp; + size_t match_len; + int rc = -EINVAL; + + if ((file_name == NULL) || + (strlen(file_name) <= 1) || (file_name[0] != '/')) { + SYS_LOG_ERR("invalid file name!!"); + return -EINVAL; + } + + rc = get_mnt_point(&mp, file_name, &match_len); + if (rc < 0) { + SYS_LOG_ERR("%s:mount point not found!!", __func__); + return rc; + } + + zfp->mp = mp; + + if (zfp->mp->fs->open != NULL) { + rc = zfp->mp->fs->open(zfp, &file_name[match_len]); + if (rc < 0) { + SYS_LOG_ERR("file open error (%d)", rc); + return rc; + } + } + + return rc; +} + +int fs_close(struct fs_file_t *zfp) +{ + int rc = -EINVAL; + + if (zfp->mp->fs->close != NULL) { + rc = zfp->mp->fs->close(zfp); + if (rc < 0) { + SYS_LOG_ERR("file close error (%d)", rc); + return rc; + } + } + + zfp->mp = NULL; + + return rc; +} + +ssize_t fs_read(struct fs_file_t *zfp, void *ptr, size_t size) +{ + int rc = -EINVAL; + + if (zfp->mp->fs->read != NULL) { + rc = zfp->mp->fs->read(zfp, ptr, size); + if (rc < 0) { + SYS_LOG_ERR("file read error (%d)", rc); + } + } + + return rc; +} + +ssize_t fs_write(struct fs_file_t *zfp, const void *ptr, size_t size) +{ + int rc = -EINVAL; + + if (zfp->mp->fs->write != NULL) { + rc = zfp->mp->fs->write(zfp, ptr, size); + if (rc < 0) { + SYS_LOG_ERR("file write error (%d)", rc); + } + } + + return rc; +} + +int fs_seek(struct fs_file_t *zfp, off_t offset, int whence) +{ + int rc = -EINVAL; + + if (zfp->mp->fs->lseek != NULL) { + rc = zfp->mp->fs->lseek(zfp, offset, whence); + if (rc < 0) { + SYS_LOG_ERR("file seek error (%d)", rc); + } + } + + return rc; +} + +off_t fs_tell(struct fs_file_t *zfp) +{ + int rc = -EINVAL; + + if (zfp->mp->fs->tell != NULL) { + rc = zfp->mp->fs->tell(zfp); + if (rc < 0) { + SYS_LOG_ERR("file tell error (%d)", rc); + } + } + + return rc; +} + +int fs_truncate(struct fs_file_t *zfp, off_t length) +{ + int rc = -EINVAL; + + if (zfp->mp->fs->truncate != NULL) { + rc = zfp->mp->fs->truncate(zfp, length); + if (rc < 0) { + SYS_LOG_ERR("file truncate error (%d)", rc); + } + } + + return rc; +} + +int fs_sync(struct fs_file_t *zfp) +{ + int rc = -EINVAL; + + if (zfp->mp->fs->sync != NULL) { + rc = zfp->mp->fs->sync(zfp); + if (rc < 0) { + SYS_LOG_ERR("file sync error (%d)", rc); + } + } + + return rc; +} + +/* Directory operations */ +int fs_opendir(struct fs_dir_t *zdp, const char *abs_path) +{ + struct fs_mount_t *mp; + size_t match_len; + int rc = -EINVAL; + + if ((abs_path == NULL) || + (strlen(abs_path) <= 1) || (abs_path[0] != '/')) { + SYS_LOG_ERR("invalid file name!!"); + return -EINVAL; + } + + rc = get_mnt_point(&mp, abs_path, &match_len); + if (rc < 0) { + SYS_LOG_ERR("%s:mount point not found!!", __func__); + return rc; + } + + zdp->mp = mp; + + if (zdp->mp->fs->opendir != NULL) { + rc = zdp->mp->fs->opendir(zdp, &abs_path[match_len]); + if (rc < 0) { + SYS_LOG_ERR("directory open error (%d)", rc); + } + } + + return rc; +} + +int fs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry) +{ + int rc = -EINVAL; + + if (zdp->mp->fs->readdir != NULL) { + rc = zdp->mp->fs->readdir(zdp, entry); + if (rc < 0) { + SYS_LOG_ERR("directory read error (%d)", rc); + } + } + return rc; +} + +int fs_closedir(struct fs_dir_t *zdp) +{ + int rc = -EINVAL; + + if (zdp->mp->fs->closedir != NULL) { + rc = zdp->mp->fs->closedir(zdp); + if (rc < 0) { + SYS_LOG_ERR("directory close error (%d)", rc); + return rc; + } + } + + zdp->mp = NULL; + return rc; +} + +/* Filesystem operations */ +int fs_mkdir(const char *abs_path) +{ + struct fs_mount_t *mp; + size_t match_len; + int rc = -EINVAL; + + if ((abs_path == NULL) || + (strlen(abs_path) <= 1) || (abs_path[0] != '/')) { + SYS_LOG_ERR("invalid file name!!"); + return -EINVAL; + } + + rc = get_mnt_point(&mp, abs_path, &match_len); + if (rc < 0) { + SYS_LOG_ERR("%s:mount point not found!!", __func__); + return rc; + } + + if (mp->fs->mkdir != NULL) { + rc = mp->fs->mkdir(mp, &abs_path[match_len]); + if (rc < 0) { + SYS_LOG_ERR("failed to create directory (%d)", rc); + } + } + + return rc; +} + +int fs_unlink(const char *abs_path) +{ + struct fs_mount_t *mp; + size_t match_len; + int rc = -EINVAL; + + if ((abs_path == NULL) || + (strlen(abs_path) <= 1) || (abs_path[0] != '/')) { + SYS_LOG_ERR("invalid file name!!"); + return -EINVAL; + } + + rc = get_mnt_point(&mp, abs_path, &match_len); + if (rc < 0) { + SYS_LOG_ERR("%s:mount point not found!!", __func__); + return rc; + } + + if (mp->fs->unlink != NULL) { + rc = mp->fs->unlink(mp, &abs_path[match_len]); + if (rc < 0) { + SYS_LOG_ERR("failed to unlink path (%d)", rc); + } + } + + return rc; +} + +int fs_rename(const char *from, const char *to) +{ + struct fs_mount_t *mp; + size_t match_len; + int rc = -EINVAL; + + if ((from == NULL) || (strlen(from) <= 1) || (from[0] != '/') || + (to == NULL) || (strlen(to) <= 1) || (to[0] != '/')) { + SYS_LOG_ERR("invalid file name!!"); + return -EINVAL; + } + + rc = get_mnt_point(&mp, from, &match_len); + if (rc < 0) { + SYS_LOG_ERR("%s:mount point not found!!", __func__); + return rc; + } + + /* Make sure both files are mounted on the same path */ + if (strncmp(from, to, match_len) != 0) { + SYS_LOG_ERR("mount point not same!!"); + return -EINVAL; + } + + if (mp->fs->rename != NULL) { + rc = mp->fs->rename(mp, &from[match_len], &to[match_len]); + if (rc < 0) { + SYS_LOG_ERR("failed to rename file or dir (%d)", rc); + } + } + + return rc; +} + +int fs_stat(const char *abs_path, struct fs_dirent *entry) +{ + struct fs_mount_t *mp; + size_t match_len; + int rc = -EINVAL; + + if ((abs_path == NULL) || + (strlen(abs_path) <= 1) || (abs_path[0] != '/')) { + SYS_LOG_ERR("invalid file name!!"); + return -EINVAL; + } + + rc = get_mnt_point(&mp, abs_path, &match_len); + if (rc < 0) { + SYS_LOG_ERR("%s:mount point not found!!", __func__); + return rc; + } + + if (mp->fs->stat != NULL) { + rc = mp->fs->stat(mp, &abs_path[match_len], entry); + if (rc < 0) { + SYS_LOG_ERR("failed get file or dir stat (%d)", rc); + } + } + return rc; +} + +int fs_statvfs(const char *abs_path, struct fs_statvfs *stat) +{ + struct fs_mount_t *mp; + size_t match_len; + int rc; + + if ((abs_path == NULL) || + (strlen(abs_path) <= 1) || (abs_path[0] != '/')) { + SYS_LOG_ERR("invalid file name!!"); + return -EINVAL; + } + + rc = get_mnt_point(&mp, abs_path, &match_len); + if (rc < 0) { + SYS_LOG_ERR("%s:mount point not found!!", __func__); + return rc; + } + + if (mp->fs->statvfs != NULL) { + rc = mp->fs->statvfs(mp, &abs_path[match_len], stat); + if (rc < 0) { + SYS_LOG_ERR("failed get file or dir stat (%d)", rc); + } + } + + return rc; +} + +int fs_mount(struct fs_mount_t *mp) +{ + struct fs_mount_t *itr; + struct fs_file_system_t *fs; + sys_dnode_t *node; + int rc = -EINVAL; + + if ((mp == NULL) || (mp->mnt_point == NULL)) { + SYS_LOG_ERR("mount point not initialized!!"); + return -EINVAL; + } + + k_mutex_lock(&mutex, K_FOREVER); + /* Check if requested file system is registered */ + if (mp->type >= FS_TYPE_END || fs_map[mp->type] == NULL) { + SYS_LOG_ERR("requested file system not registered!!"); + rc = -ENOENT; + goto mount_err; + } + + /* Get fs interface from file system map */ + fs = fs_map[mp->type]; + mp->mountp_len = strlen(mp->mnt_point); + + if ((mp->mnt_point[0] != '/') || + (strlen(mp->mnt_point) <= 1)) { + SYS_LOG_ERR("invalid mount point!!"); + rc = -EINVAL; + goto mount_err; + } + + if (fs->mount == NULL) { + SYS_LOG_ERR("fs ops functions not set!!"); + rc = -EINVAL; + goto mount_err; + } + + /* Check if mount point already exists */ + SYS_DLIST_FOR_EACH_NODE(&fs_mnt_list, node) { + itr = CONTAINER_OF(node, struct fs_mount_t, node); + /* continue if length does not match */ + if (mp->mountp_len != itr->mountp_len) { + continue; + } + + if (strncmp(mp->mnt_point, itr->mnt_point, + mp->mountp_len) == 0) { + SYS_LOG_ERR("mount Point already exists!!"); + rc = -EBUSY; + goto mount_err; + } + } + + + rc = fs->mount(mp); + if (rc < 0) { + SYS_LOG_ERR("fs mount error (%d)", rc); + goto mount_err; + } + + /* set mount point fs interface */ + mp->fs = fs; + + /* append to the mount list */ + sys_dlist_append(&fs_mnt_list, &mp->node); + SYS_LOG_DBG("fs mouted, mount point:%s", mp->mnt_point); + +mount_err: + k_mutex_unlock(&mutex); + return rc; +} + + +int fs_unmount(struct fs_mount_t *mp) +{ + int rc = -EINVAL; + + if ((mp == NULL) || (mp->mnt_point == NULL) || + (strlen(mp->mnt_point) <= 1)) { + SYS_LOG_ERR("invalid mount point!!"); + return -EINVAL; + } + + k_mutex_lock(&mutex, K_FOREVER); + if ((mp->fs == NULL) || mp->fs->unmount == NULL) { + SYS_LOG_ERR("fs ops functions not set!!"); + rc = -EINVAL; + goto unmount_err; + } + + rc = mp->fs->unmount(mp); + if (rc < 0) { + SYS_LOG_ERR("fs unmount error (%d)", rc); + goto unmount_err; + } + + /* clear file system interface */ + mp->fs = NULL; + + /* remove mount node from the list */ + sys_dlist_remove(&mp->node); + SYS_LOG_DBG("fs unmouted, mount point:%s", mp->mnt_point); + +unmount_err: + k_mutex_unlock(&mutex); + return rc; +} + +/* Register File system */ +int fs_register(enum fs_type type, struct fs_file_system_t *fs) +{ + int rc = 0; + + k_mutex_lock(&mutex, K_FOREVER); + if (type >= FS_TYPE_END) { + SYS_LOG_ERR("failed to register File system!!"); + rc = -EINVAL; + goto reg_err; + } + fs_map[type] = fs; + SYS_LOG_DBG("fs registered of type(%u)", type); +reg_err: + k_mutex_unlock(&mutex); + return rc; +} + +/* Unregister File system */ +int fs_unregister(enum fs_type type, struct fs_file_system_t *fs) +{ + int rc = 0; + + k_mutex_lock(&mutex, K_FOREVER); + if ((type >= FS_TYPE_END) || + (fs_map[type] != fs)) { + SYS_LOG_ERR("failed to unregister File system!!"); + rc = -EINVAL; + goto unreg_err; + } + fs_map[type] = NULL; + SYS_LOG_DBG("fs unregistered of type(%u)", type); +unreg_err: + k_mutex_unlock(&mutex); + return rc; +} + +static int fs_init(struct device *dev) +{ + k_mutex_init(&mutex); + sys_dlist_init(&fs_mnt_list); + return 0; +} + +SYS_INIT(fs_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/subsys/fs/nffs_fs.c b/subsys/fs/nffs_fs.c index 165d594239d..78c61c725d1 100644 --- a/subsys/fs/nffs_fs.c +++ b/subsys/fs/nffs_fs.c @@ -14,9 +14,10 @@ #include #include #include -#include #include +#define NFFS_MAX_FILE_NAME 256 + /* * NFFS code keeps fs state in RAM but access to these structures is not * thread-safe - we need global lock for each fs operation to guarantee two @@ -24,8 +25,11 @@ */ static struct k_mutex nffs_lock; +/* + * TODO: Get rid of global flash_dev which limits + * system to have multiple instances of NFFS. + */ static struct device *flash_dev; -static struct nffs_flash_desc flash_desc; K_MEM_SLAB_DEFINE(nffs_file_pool, sizeof(struct nffs_file), CONFIG_FS_NFFS_NUM_FILES, 4); @@ -218,20 +222,20 @@ static int inode_to_dirent(struct nffs_inode_entry *inode, return rc; } -int fs_open(fs_file_t *zfp, const char *file_name) +static int nffs_open(struct fs_file_t *zfp, const char *file_name) { int rc; k_mutex_lock(&nffs_lock, K_FOREVER); - zfp->fp = NULL; + zfp->nffs_fp = NULL; if (!nffs_misc_ready()) { k_mutex_unlock(&nffs_lock); return -ENODEV; } - rc = nffs_file_open(&zfp->fp, file_name, + rc = nffs_file_open(&zfp->nffs_fp, file_name, FS_ACCESS_READ | FS_ACCESS_WRITE); k_mutex_unlock(&nffs_lock); @@ -239,15 +243,15 @@ int fs_open(fs_file_t *zfp, const char *file_name) return translate_error(rc); } -int fs_close(fs_file_t *zfp) +static int nffs_close(struct fs_file_t *zfp) { int rc; k_mutex_lock(&nffs_lock, K_FOREVER); - rc = nffs_file_close(zfp->fp); + rc = nffs_file_close(zfp->nffs_fp); if (!rc) { - zfp->fp = NULL; + zfp->nffs_fp = NULL; } k_mutex_unlock(&nffs_lock); @@ -255,7 +259,7 @@ int fs_close(fs_file_t *zfp) return translate_error(rc); } -int fs_unlink(const char *path) +static int nffs_unlink(struct fs_mount_t *mountp, const char *path) { int rc; @@ -268,14 +272,14 @@ int fs_unlink(const char *path) return translate_error(rc); } -ssize_t fs_read(fs_file_t *zfp, void *ptr, size_t size) +static ssize_t nffs_read(struct fs_file_t *zfp, void *ptr, size_t size) { uint32_t br; int rc; k_mutex_lock(&nffs_lock, K_FOREVER); - rc = nffs_file_read(zfp->fp, size, ptr, &br); + rc = nffs_file_read(zfp->nffs_fp, size, ptr, &br); k_mutex_unlock(&nffs_lock); @@ -286,13 +290,13 @@ ssize_t fs_read(fs_file_t *zfp, void *ptr, size_t size) return br; } -ssize_t fs_write(fs_file_t *zfp, const void *ptr, size_t size) +static ssize_t nffs_write(struct fs_file_t *zfp, const void *ptr, size_t size) { int rc; k_mutex_lock(&nffs_lock, K_FOREVER); - rc = nffs_write_to_file(zfp->fp, ptr, size); + rc = nffs_write_to_file(zfp->nffs_fp, ptr, size); k_mutex_unlock(&nffs_lock); @@ -304,7 +308,7 @@ ssize_t fs_write(fs_file_t *zfp, const void *ptr, size_t size) return size; } -int fs_seek(fs_file_t *zfp, off_t offset, int whence) +static int nffs_seek(struct fs_file_t *zfp, off_t offset, int whence) { uint32_t len; u32_t pos; @@ -317,10 +321,10 @@ int fs_seek(fs_file_t *zfp, off_t offset, int whence) pos = offset; break; case FS_SEEK_CUR: - pos = zfp->fp->nf_offset + offset; + pos = zfp->nffs_fp->nf_offset + offset; break; case FS_SEEK_END: - rc = nffs_inode_data_len(zfp->fp->nf_inode_entry, &len); + rc = nffs_inode_data_len(zfp->nffs_fp->nf_inode_entry, &len); if (rc) { k_mutex_unlock(&nffs_lock); return -EINVAL; @@ -332,32 +336,32 @@ int fs_seek(fs_file_t *zfp, off_t offset, int whence) return -EINVAL; } - rc = nffs_file_seek(zfp->fp, pos); + rc = nffs_file_seek(zfp->nffs_fp, pos); k_mutex_unlock(&nffs_lock); return translate_error(rc); } -off_t fs_tell(fs_file_t *zfp) +static off_t nffs_tell(struct fs_file_t *zfp) { u32_t offset; k_mutex_lock(&nffs_lock, K_FOREVER); - if (!zfp->fp) { + if (!zfp->nffs_fp) { return -EIO; k_mutex_unlock(&nffs_lock); } - offset = zfp->fp->nf_offset; + offset = zfp->nffs_fp->nf_offset; k_mutex_unlock(&nffs_lock); return offset; } -int fs_truncate(fs_file_t *zfp, off_t length) +static int nffs_truncate(struct fs_file_t *zfp, off_t length) { /* * FIXME: @@ -369,7 +373,7 @@ int fs_truncate(fs_file_t *zfp, off_t length) return -ENOTSUP; } -int fs_sync(fs_file_t *zfp) +static int nffs_sync(struct fs_file_t *zfp) { /* * Files are written to flash immediately so we do not need to support @@ -379,7 +383,7 @@ int fs_sync(fs_file_t *zfp) return 0; } -int fs_mkdir(const char *path) +static int nffs_mkdir(struct fs_mount_t *mountp, const char *path) { int rc; @@ -397,34 +401,34 @@ int fs_mkdir(const char *path) return translate_error(rc); } -int fs_opendir(fs_dir_t *zdp, const char *path) +static int nffs_opendir(struct fs_dir_t *zdp, const char *path) { int rc; k_mutex_lock(&nffs_lock, K_FOREVER); - zdp->dp = NULL; + zdp->nffs_dp = NULL; if (!nffs_misc_ready()) { k_mutex_unlock(&nffs_lock); return -ENODEV; } - rc = nffs_dir_open(path, &zdp->dp); + rc = nffs_dir_open(path, &zdp->nffs_dp); k_mutex_unlock(&nffs_lock); return translate_error(rc); } -int fs_readdir(fs_dir_t *zdp, struct fs_dirent *entry) +static int nffs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry) { struct nffs_dirent *dirent; int rc; k_mutex_lock(&nffs_lock, K_FOREVER); - rc = nffs_dir_read(zdp->dp, &dirent); + rc = nffs_dir_read(zdp->nffs_dp, &dirent); switch (rc) { case 0: rc = inode_to_dirent(dirent->nde_inode_entry, entry); @@ -442,15 +446,15 @@ int fs_readdir(fs_dir_t *zdp, struct fs_dirent *entry) return translate_error(rc); } -int fs_closedir(fs_dir_t *zdp) +static int nffs_closedir(struct fs_dir_t *zdp) { int rc; k_mutex_lock(&nffs_lock, K_FOREVER); - rc = nffs_dir_close(zdp->dp); + rc = nffs_dir_close(zdp->nffs_dp); if (!rc) { - zdp->dp = NULL; + zdp->nffs_dp = NULL; } k_mutex_unlock(&nffs_lock); @@ -458,7 +462,8 @@ int fs_closedir(fs_dir_t *zdp) return translate_error(rc); } -int fs_stat(const char *path, struct fs_dirent *entry) +static int nffs_stat(struct fs_mount_t *mountp, + const char *path, struct fs_dirent *entry) { struct nffs_path_parser parser; struct nffs_inode_entry *parent; @@ -479,7 +484,8 @@ int fs_stat(const char *path, struct fs_dirent *entry) return translate_error(rc); } -int fs_statvfs(struct fs_statvfs *stat) +static int nffs_statvfs(struct fs_mount_t *mountp, + const char *path, struct fs_statvfs *stat) { /* * FIXME: @@ -489,25 +495,22 @@ int fs_statvfs(struct fs_statvfs *stat) return -ENOTSUP; } -static int fs_init(struct device *dev) +static int nffs_mount(struct fs_mount_t *mountp) { struct nffs_area_desc descs[CONFIG_NFFS_FILESYSTEM_MAX_AREAS + 1]; + struct nffs_flash_desc *flash_desc = + (struct nffs_flash_desc *)mountp->fs_data; int cnt; int rc; - ARG_UNUSED(dev); + /* Set flash device */ + flash_dev = mountp->storage_dev; - k_mutex_init(&nffs_lock); - - flash_dev = device_get_binding(CONFIG_FS_NFFS_FLASH_DEV_NAME); - if (!flash_dev) { - return -ENODEV; - } - - flash_desc.id = 0; - flash_desc.sector_count = flash_get_page_count(flash_dev); - flash_desc.area_offset = FLASH_AREA_NFFS_OFFSET; - flash_desc.area_size = FLASH_AREA_NFFS_SIZE; + /* Set flash descriptor fields */ + flash_desc->id = 0; + flash_desc->sector_count = flash_get_page_count(flash_dev); + flash_desc->area_offset = FLASH_AREA_NFFS_OFFSET; + flash_desc->area_size = FLASH_AREA_NFFS_SIZE; rc = nffs_misc_reset(); if (rc) { @@ -515,7 +518,7 @@ static int fs_init(struct device *dev) } cnt = CONFIG_NFFS_FILESYSTEM_MAX_AREAS; - rc = nffs_misc_desc_from_flash_area(&flash_desc, &cnt, descs); + rc = nffs_misc_desc_from_flash_area(flash_desc, &cnt, descs); if (rc) { return -EIO; } @@ -537,4 +540,33 @@ static int fs_init(struct device *dev) return 0; } -SYS_INIT(fs_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +/* File system interface */ +static struct fs_file_system_t nffs_fs = { + .open = nffs_open, + .close = nffs_close, + .read = nffs_read, + .write = nffs_write, + .lseek = nffs_seek, + .tell = nffs_tell, + .truncate = nffs_truncate, + .sync = nffs_sync, + .opendir = nffs_opendir, + .readdir = nffs_readdir, + .closedir = nffs_closedir, + .mount = nffs_mount, + .unlink = nffs_unlink, + .mkdir = nffs_mkdir, + .stat = nffs_stat, + .statvfs = nffs_statvfs, +}; + +static int nffs_init(struct device *dev) +{ + ARG_UNUSED(dev); + + k_mutex_init(&nffs_lock); + + return fs_register(FS_NFFS, &nffs_fs); +} + +SYS_INIT(nffs_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);