From b6a9acfc071b53b392ddfd233f166f45bdddace6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Thu, 27 Jun 2024 10:38:13 +0200 Subject: [PATCH 01/11] feat(storage/vfs): Add minified vfs implementation --- components/vfs/include/esp_vfs.h | 20 +- components/vfs/include/esp_vfs_minified.h | 276 ++++++++++++ .../vfs/private_include/esp_vfs_private.h | 3 +- components/vfs/vfs.c | 400 ++++++++++++++---- 4 files changed, 611 insertions(+), 88 deletions(-) create mode 100644 components/vfs/include/esp_vfs_minified.h diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 655bbf5790..42c6a1199a 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -29,6 +29,8 @@ #include #include "sdkconfig.h" +#include "esp_vfs_minified.h" + #ifdef __cplusplus extern "C" { #endif @@ -62,20 +64,11 @@ extern "C" { */ #define ESP_VFS_FLAG_READONLY_FS (1 << 2) -/* - * @brief VFS identificator used for esp_vfs_register_with_id() - */ -typedef int esp_vfs_id_t; - /** - * @brief VFS semaphore type for select() - * + * Flag which indicates that VFS structure should be freed upon unregistering. + * @note Free if false, do not free if true */ -typedef struct -{ - bool is_sem_local; /*!< type of "sem" is SemaphoreHandle_t when true, defined by socket driver otherwise */ - void *sem; /*!< semaphore instance */ -} esp_vfs_select_sem_t; +#define ESP_VFS_FLAG_STATIC (1 << 3) /** * @brief VFS definition structure @@ -259,6 +252,8 @@ typedef struct #endif // CONFIG_VFS_SUPPORT_SELECT || defined __DOXYGEN__ } esp_vfs_t; + + /** * Register a virtual filesystem for given path prefix. * @@ -284,7 +279,6 @@ typedef struct */ esp_err_t esp_vfs_register(const char* base_path, const esp_vfs_t* vfs, void* ctx); - /** * Special case function for registering a VFS that uses a method other than * open() to open new file descriptors from the interval +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "esp_err.h" +#include +#include +#include +#include +#include +#include +#ifdef __clang__ // TODO LLVM-330 +#include +#else +#include +#endif +#include +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _SYS_TYPES_FD_SET +#error "VFS should be used with FD_SETSIZE and FD_SET from sys/types.h" +#endif + +/* + * @brief VFS identificator used for esp_vfs_register_with_id() + */ +typedef int esp_vfs_id_t; + +/** + * @brief VFS semaphore type for select() + * + */ +typedef struct +{ + bool is_sem_local; /*!< type of "sem" is SemaphoreHandle_t when true, defined by socket driver otherwise */ + void *sem; /*!< semaphore instance */ +} esp_vfs_select_sem_t; + +#ifdef CONFIG_VFS_SUPPORT_DIR + +typedef struct { + union { + int (*stat_p)(void* ctx, const char * path, struct stat * st); /*!< stat with context pointer */ + int (*stat)(const char * path, struct stat * st); /*!< stat without context pointer */ + }; + union { + int (*link_p)(void* ctx, const char* n1, const char* n2); /*!< link with context pointer */ + int (*link)(const char* n1, const char* n2); /*!< link without context pointer */ + }; + union { + int (*unlink_p)(void* ctx, const char *path); /*!< unlink with context pointer */ + int (*unlink)(const char *path); /*!< unlink without context pointer */ + }; + union { + int (*rename_p)(void* ctx, const char *src, const char *dst); /*!< rename with context pointer */ + int (*rename)(const char *src, const char *dst); /*!< rename without context pointer */ + }; + union { + DIR* (*opendir_p)(void* ctx, const char* name); /*!< opendir with context pointer */ + DIR* (*opendir)(const char* name); /*!< opendir without context pointer */ + }; + union { + struct dirent* (*readdir_p)(void* ctx, DIR* pdir); /*!< readdir with context pointer */ + struct dirent* (*readdir)(DIR* pdir); /*!< readdir without context pointer */ + }; + union { + int (*readdir_r_p)(void* ctx, DIR* pdir, struct dirent* entry, struct dirent** out_dirent); /*!< readdir_r with context pointer */ + int (*readdir_r)(DIR* pdir, struct dirent* entry, struct dirent** out_dirent); /*!< readdir_r without context pointer */ + }; + union { + long (*telldir_p)(void* ctx, DIR* pdir); /*!< telldir with context pointer */ + long (*telldir)(DIR* pdir); /*!< telldir without context pointer */ + }; + union { + void (*seekdir_p)(void* ctx, DIR* pdir, long offset); /*!< seekdir with context pointer */ + void (*seekdir)(DIR* pdir, long offset); /*!< seekdir without context pointer */ + }; + union { + int (*closedir_p)(void* ctx, DIR* pdir); /*!< closedir with context pointer */ + int (*closedir)(DIR* pdir); /*!< closedir without context pointer */ + }; + union { + int (*mkdir_p)(void* ctx, const char* name, mode_t mode); /*!< mkdir with context pointer */ + int (*mkdir)(const char* name, mode_t mode); /*!< mkdir without context pointer */ + }; + union { + int (*rmdir_p)(void* ctx, const char* name); /*!< rmdir with context pointer */ + int (*rmdir)(const char* name); /*!< rmdir without context pointer */ + }; + union { + int (*access_p)(void* ctx, const char *path, int amode); /*!< access with context pointer */ + int (*access)(const char *path, int amode); /*!< access without context pointer */ + }; + union { + int (*truncate_p)(void* ctx, const char *path, off_t length); /*!< truncate with context pointer */ + int (*truncate)(const char *path, off_t length); /*!< truncate without context pointer */ + }; + union { + int (*ftruncate_p)(void* ctx, int fd, off_t length); /*!< ftruncate with context pointer */ + int (*ftruncate)(int fd, off_t length); /*!< ftruncate without context pointer */ + }; + union { + int (*utime_p)(void* ctx, const char *path, const struct utimbuf *times); /*!< utime with context pointer */ + int (*utime)(const char *path, const struct utimbuf *times); /*!< utime without context pointer */ + }; +} esp_vfs_dir_t; + +#endif // CONFIG_VFS_SUPPORT_DIR + +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + +typedef struct { + union { + int (*tcsetattr_p)(void *ctx, int fd, int optional_actions, const struct termios *p); /*!< tcsetattr with context pointer */ + int (*tcsetattr)(int fd, int optional_actions, const struct termios *p); /*!< tcsetattr without context pointer */ + }; + union { + int (*tcgetattr_p)(void *ctx, int fd, struct termios *p); /*!< tcgetattr with context pointer */ + int (*tcgetattr)(int fd, struct termios *p); /*!< tcgetattr without context pointer */ + }; + union { + int (*tcdrain_p)(void *ctx, int fd); /*!< tcdrain with context pointer */ + int (*tcdrain)(int fd); /*!< tcdrain without context pointer */ + }; + union { + int (*tcflush_p)(void *ctx, int fd, int select); /*!< tcflush with context pointer */ + int (*tcflush)(int fd, int select); /*!< tcflush without context pointer */ + }; + union { + int (*tcflow_p)(void *ctx, int fd, int action); /*!< tcflow with context pointer */ + int (*tcflow)(int fd, int action); /*!< tcflow without context pointer */ + }; + union { + pid_t (*tcgetsid_p)(void *ctx, int fd); /*!< tcgetsid with context pointer */ + pid_t (*tcgetsid)(int fd); /*!< tcgetsid without context pointer */ + }; + union { + int (*tcsendbreak_p)(void *ctx, int fd, int duration); /*!< tcsendbreak with context pointer */ + int (*tcsendbreak)(int fd, int duration); /*!< tcsendbreak without context pointer */ + }; +} esp_vfs_termios_t; + +#endif // CONFIG_VFS_SUPPORT_TERMIOS + +#ifdef CONFIG_VFS_SUPPORT_SELECT + +typedef struct { + /** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */ + esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args); + + /** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */ + int (*socket_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); + + /** called by VFS to interrupt the socket_select call when select is activated from a non-socket VFS driver; set only for the socket driver */ + void (*stop_socket_select)(void *sem); + + /** stop_socket_select which can be called from ISR; set only for the socket driver */ + void (*stop_socket_select_isr)(void *sem, BaseType_t *woken); + + /** end_select is called to stop the I/O multiplexing and deinitialize the environment created by start_select for the given VFS */ + void* (*get_socket_select_semaphore)(void); + + /** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */ + esp_err_t (*end_select)(void *end_select_args); +} esp_vfs_select_t; + +#endif // CONFIG_VFS_SUPPORT_SELECT + +typedef struct { + union { + ssize_t (*write_p)(void* p, int fd, const void * data, size_t size); /*!< Write with context pointer */ + ssize_t (*write)(int fd, const void * data, size_t size); /*!< Write without context pointer */ + }; + union { + off_t (*lseek_p)(void* p, int fd, off_t size, int mode); /*!< Seek with context pointer */ + off_t (*lseek)(int fd, off_t size, int mode); /*!< Seek without context pointer */ + }; + union { + ssize_t (*read_p)(void* ctx, int fd, void * dst, size_t size); /*!< Read with context pointer */ + ssize_t (*read)(int fd, void * dst, size_t size); /*!< Read without context pointer */ + }; + union { + ssize_t (*pread_p)(void *ctx, int fd, void * dst, size_t size, off_t offset); /*!< pread with context pointer */ + ssize_t (*pread)(int fd, void * dst, size_t size, off_t offset); /*!< pread without context pointer */ + }; + union { + ssize_t (*pwrite_p)(void *ctx, int fd, const void *src, size_t size, off_t offset); /*!< pwrite with context pointer */ + ssize_t (*pwrite)(int fd, const void *src, size_t size, off_t offset); /*!< pwrite without context pointer */ + }; + union { + int (*open_p)(void* ctx, const char * path, int flags, int mode); /*!< open with context pointer */ + int (*open)(const char * path, int flags, int mode); /*!< open without context pointer */ + }; + union { + int (*close_p)(void* ctx, int fd); /*!< close with context pointer */ + int (*close)(int fd); /*!< close without context pointer */ + }; + union { + int (*fstat_p)(void* ctx, int fd, struct stat * st); /*!< fstat with context pointer */ + int (*fstat)(int fd, struct stat * st); /*!< fstat without context pointer */ + }; + union { + int (*fcntl_p)(void* ctx, int fd, int cmd, int arg); /*!< fcntl with context pointer */ + int (*fcntl)(int fd, int cmd, int arg); /*!< fcntl without context pointer */ + }; + union { + int (*ioctl_p)(void* ctx, int fd, int cmd, va_list args); /*!< ioctl with context pointer */ + int (*ioctl)(int fd, int cmd, va_list args); /*!< ioctl without context pointer */ + }; + union { + int (*fsync_p)(void* ctx, int fd); /*!< fsync with context pointer */ + int (*fsync)(int fd); /*!< fsync without context pointer */ + }; + +#ifdef CONFIG_VFS_SUPPORT_DIR + esp_vfs_dir_t *dir; +#endif + +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + esp_vfs_termios_t *termios; +#endif + +#if CONFIG_VFS_SUPPORT_SELECT || defined __DOXYGEN__ + esp_vfs_select_t *select; +#endif + +} esp_vfs_minified_t; + +/** + * Register a virtual filesystem for given path prefix. + * + * @param base_path file path prefix associated with the filesystem. + * Must be a zero-terminated C string, may be empty. + * If not empty, must be up to ESP_VFS_PATH_MAX + * characters long, and at least 2 characters long. + * Name must start with a "/" and must not end with "/". + * For example, "/data" or "/dev/spi" are valid. + * These VFSes would then be called to handle file paths such as + * "/data/myfile.txt" or "/dev/spi/0". + * In the special case of an empty base_path, a "fallback" + * VFS is registered. Such VFS will handle paths which are not + * matched by any other registered VFS. + * @param vfs Pointer to esp_vfs_t, a structure which maps syscalls to + * the filesystem driver functions. VFS component doesn't + * assume ownership of this pointer. + * @param ctx If vfs->flags has ESP_VFS_FLAG_CONTEXT_PTR set, a pointer + * which should be passed to VFS functions. Otherwise, NULL. + * + * @return ESP_OK if successful, ESP_ERR_NO_MEM if too many VFSes are + * registered. + */ +esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minified_t* vfs, int flags, void* ctx); + +esp_err_t esp_vfs_register_minified_with_id(const esp_vfs_minified_t* vfs, int flags, void* ctx, int* id); + +esp_err_t esp_vfs_unregister_minified(const char* base_path); + +esp_err_t esp_vfs_unregister_minified_with_id(esp_vfs_id_t id); + +#ifdef __cplusplus +} +#endif diff --git a/components/vfs/private_include/esp_vfs_private.h b/components/vfs/private_include/esp_vfs_private.h index fda3e9712b..b211f842a2 100644 --- a/components/vfs/private_include/esp_vfs_private.h +++ b/components/vfs/private_include/esp_vfs_private.h @@ -19,7 +19,8 @@ extern "C" { #endif typedef struct vfs_entry_ { - esp_vfs_t vfs; // contains pointers to VFS functions + int flags; /*!< ESP_VFS_FLAG_CONTEXT_PTR and/or ESP_VFS_FLAG_READONLY_FS or ESP_VFS_FLAG_DEFAULT */ + const esp_vfs_minified_t *vfs; // contains pointers to VFS functions char path_prefix[ESP_VFS_PATH_MAX]; // path prefix mapped to this VFS size_t path_prefix_len; // micro-optimization to avoid doing extra strlen void* ctx; // optional pointer which can be passed to VFS diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index 906e8684d9..7e494b90ef 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -19,6 +19,7 @@ #include "freertos/semphr.h" #include "esp_vfs.h" #include "esp_vfs_private.h" +#include "include/esp_vfs.h" #include "sdkconfig.h" // Warn about using deprecated option @@ -75,8 +76,189 @@ static size_t s_vfs_count = 0; static fd_table_t s_fd_table[MAX_FDS] = { [0 ... MAX_FDS-1] = FD_TABLE_ENTRY_UNUSED }; static _lock_t s_fd_table_lock; -esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_vfs_t* vfs, void* ctx, int *vfs_index) +static ssize_t esp_get_free_index(void) { + for (ssize_t i = 0; i < MAX_FDS; i++) { + if (s_vfs[i] == NULL) { + return i; + } + } + return -1; +} + +static void esp_free_minified_vfs(esp_vfs_minified_t *vfs) { +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + free(vfs->termios); +#endif + +#ifdef CONFIG_VFS_SUPPORT_DIR + free(vfs->dir); +#endif + +#ifdef CONFIG_VFS_SUPPORT_SELECT + free(vfs->select); +#endif + + free(vfs); +} + +static esp_vfs_minified_t *esp_alloc_minified_vfs(void) { + esp_vfs_minified_t *main = (esp_vfs_minified_t*) heap_caps_malloc(sizeof(esp_vfs_minified_t), VFS_MALLOC_FLAGS); + if (main == NULL) { + return NULL; + } + + // Initialize all fields to NULL + memset(main, 0, sizeof(esp_vfs_minified_t)); + +#ifdef CONFIG_VFS_SUPPORT_DIR + main->dir = (esp_vfs_dir_t*) heap_caps_malloc(sizeof(esp_vfs_dir_t), VFS_MALLOC_FLAGS); + if (main->dir == NULL) { + goto fail; + } +#endif + +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + main->termios = (esp_vfs_termios_t*) heap_caps_malloc(sizeof(esp_vfs_termios_t), VFS_MALLOC_FLAGS); + if (main->termios == NULL) { + goto fail; + } +#endif + +#ifdef CONFIG_VFS_SUPPORT_SELECT + main->select = (esp_vfs_select_t*) heap_caps_malloc(sizeof(esp_vfs_select_t), VFS_MALLOC_FLAGS); + if (main->select == NULL) { + goto fail; + } +#endif + + return main; + +#if defined(CONFIG_VFS_SUPPORT_SELECT) || defined(CONFIG_VFS_SUPPORT_TERMIOS) || defined(CONFIG_VFS_SUPPORT_DIR) +fail: + + esp_free_minified_vfs(main); + return NULL; +#endif +} + +static void esp_vfs_free_entry(vfs_entry_t *entry) { + if (entry == NULL) { // Necessary because of the following flags check + return; + } + + if (!(entry->flags & ESP_VFS_FLAG_STATIC)) { + esp_free_minified_vfs((esp_vfs_minified_t*)entry->vfs); // const cast, but we know it's not static from the flag + } + + free(entry); +} + +static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_minified_t *min) { + if (vfs == NULL) { + ESP_LOGE(TAG, "Cannot minify NULL VFS"); + assert(vfs != NULL); // Show stack trace + abort(); // Ensure we don't continue with a NULL VFS when assert is disabled + } + + if (min == NULL) { + ESP_LOGE(TAG, "Cannot minify VFS to NULL"); + assert(min != NULL); // Show stack trace + abort(); // Ensure we don't continue with a NULL VFS when assert is disabled + } + + *min = (esp_vfs_minified_t) { + .write = vfs->write, + .lseek = vfs->lseek, + .read = vfs->read, + .pread = vfs->pread, + .pwrite = vfs->pwrite, + .open = vfs->open, + .close = vfs->close, + .fstat = vfs->fstat, + .fcntl = vfs->fcntl, + .ioctl = vfs->ioctl, + .fsync = vfs->fsync, +#ifdef CONFIG_VFS_SUPPORT_DIR + .dir = min->dir, +#endif +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + .termios = min->termios, +#endif +#ifdef CONFIG_VFS_SUPPORT_SELECT + .select = min->select, +#endif + }; + +#ifdef CONFIG_VFS_SUPPORT_DIR + if (min->dir == NULL) { + ESP_LOGE(TAG, "Dir subcomponent is not allocated"); + assert(min->dir != NULL); // Show stack trace + abort(); // Ensure we don't continue with a NULL VFS when assert is disabled + } + *(min->dir) = (esp_vfs_dir_t) { + .stat = vfs->stat, + .link = vfs->link, + .unlink = vfs->unlink, + .rename = vfs->rename, + .opendir = vfs->opendir, + .readdir = vfs->readdir, + .readdir_r = vfs->readdir_r, + .telldir = vfs->telldir, + .seekdir = vfs->seekdir, + .closedir = vfs->closedir, + .mkdir = vfs->mkdir, + .rmdir = vfs->rmdir, + .access = vfs->access, + .truncate = vfs->truncate, + .ftruncate = vfs->ftruncate, + .utime = vfs->utime, + }; +#endif // CONFIG_VFS_SUPPORT_DIR + +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + if (min->termios == NULL) { + ESP_LOGE(TAG, "Termios subcomponent is not allocated"); + assert(min->termios != NULL); // Show stack trace + abort(); // Ensure we don't continue with a NULL VFS when assert is disabled + } + + *(min->termios) = (esp_vfs_termios_t) { + .tcsetattr = vfs->tcsetattr, + .tcgetattr = vfs->tcgetattr, + .tcdrain = vfs->tcdrain, + .tcflush = vfs->tcflush, + .tcflow = vfs->tcflow, + .tcgetsid = vfs->tcgetsid, + .tcsendbreak = vfs->tcsendbreak, + }; +#endif // CONFIG_VFS_SUPPORT_TERMIOS + +#ifdef CONFIG_VFS_SUPPORT_SELECT + if (min->select == NULL) { + ESP_LOGE(TAG, "Select subcomponent is not allocated"); + assert(min->select != NULL); // Show stack trace + abort(); // Ensure we don't continue with a NULL VFS when assert is disabled + } + + *(min->select) = (esp_vfs_select_t) { + .start_select = vfs->start_select, + .socket_select = vfs->socket_select, + .stop_socket_select = vfs->stop_socket_select, + .stop_socket_select_isr = vfs->stop_socket_select_isr, + .get_socket_select_semaphore = vfs->get_socket_select_semaphore, + .end_select = vfs->end_select, + }; +#endif // CONFIG_VFS_SUPPORT_SELECT + +} + +static esp_err_t esp_vfs_register_minified_common(const char* base_path, size_t len, const esp_vfs_minified_t* vfs, int flags, void* ctx, int *vfs_index) { + if (vfs == NULL) { + ESP_LOGE(TAG, "VFS is NULL"); + return ESP_ERR_INVALID_ARG; + } + if (len != LEN_PATH_PREFIX_IGNORED) { /* empty prefix is allowed, "/" is not allowed */ if ((len == 1) || (len > ESP_VFS_PATH_MAX)) { @@ -87,33 +269,36 @@ esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_v return ESP_ERR_INVALID_ARG; } } + + ssize_t index = esp_get_free_index(); + if (index < 0) { + return ESP_ERR_NO_MEM; + } + + if (s_vfs[index] != NULL) { + return ESP_ERR_INVALID_STATE; + } + + if (index == s_vfs_count) { + s_vfs_count++; + } + vfs_entry_t *entry = (vfs_entry_t*) heap_caps_malloc(sizeof(vfs_entry_t), VFS_MALLOC_FLAGS); if (entry == NULL) { return ESP_ERR_NO_MEM; } - size_t index; - for (index = 0; index < s_vfs_count; ++index) { - if (s_vfs[index] == NULL) { - break; - } - } - if (index == s_vfs_count) { - if (s_vfs_count >= VFS_MAX_COUNT) { - free(entry); - return ESP_ERR_NO_MEM; - } - ++s_vfs_count; - } + s_vfs[index] = entry; if (len != LEN_PATH_PREFIX_IGNORED) { strcpy(entry->path_prefix, base_path); // we have already verified argument length } else { bzero(entry->path_prefix, sizeof(entry->path_prefix)); } - memcpy(&entry->vfs, vfs, sizeof(esp_vfs_t)); - entry->path_prefix_len = len; + entry->path_prefix_len = strlen(base_path); + entry->vfs = vfs; entry->ctx = ctx; entry->offset = index; + entry->flags = flags; if (vfs_index) { *vfs_index = index; @@ -122,6 +307,58 @@ esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_v return ESP_OK; } +esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minified_t* vfs, int flags, void* ctx) +{ + if (vfs == NULL) { + ESP_LOGE(TAG, "VFS is NULL"); + return ESP_ERR_INVALID_ARG; + } + + if ((flags & ESP_VFS_FLAG_STATIC)) { + return esp_vfs_register_minified_common(base_path, strlen(base_path), vfs, flags, ctx, NULL); + } + + esp_vfs_minified_t *_vfs = esp_alloc_minified_vfs(); + if (_vfs == NULL) { + return ESP_ERR_NO_MEM; + } + + esp_err_t ret = esp_vfs_register_minified_common(base_path, strlen(base_path), _vfs, flags, ctx, NULL); + if (ret != ESP_OK) { + esp_free_minified_vfs(_vfs); + } + + return ESP_OK; +} + +esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_vfs_t* vfs, void* ctx, int *vfs_index) +{ + if (vfs == NULL) { + ESP_LOGE(TAG, "VFS is NULL"); + return ESP_ERR_INVALID_ARG; + } + + if (vfs->flags & ESP_VFS_FLAG_STATIC) { + ESP_LOGE(TAG, "ESP_VFS_FLAG_STATIC is not supported for esp_vfs_t, use esp_vfs_register_minified instead"); + return ESP_ERR_INVALID_ARG; + } + + esp_vfs_minified_t *_vfs = esp_alloc_minified_vfs(); + if (_vfs == NULL) { + return ESP_ERR_NO_MEM; + } + + // Minify the VFS + esp_minify_vfs(vfs, _vfs); + + esp_err_t ret = esp_vfs_register_minified_common(base_path, len, _vfs, vfs->flags, ctx, vfs_index); + if (ret != ESP_OK) { + esp_free_minified_vfs(_vfs); + } + + return ESP_OK; +} + esp_err_t esp_vfs_register(const char* base_path, const esp_vfs_t* vfs, void* ctx) { return esp_vfs_register_common(base_path, strlen(base_path), vfs, ctx, NULL); @@ -134,7 +371,7 @@ esp_err_t esp_vfs_register_fd_range(const esp_vfs_t *vfs, void *ctx, int min_fd, return ESP_ERR_INVALID_ARG; } - int index = -1; + int index = 0; esp_err_t ret = esp_vfs_register_common("", LEN_PATH_PREFIX_IGNORED, vfs, ctx, &index); if (ret == ESP_OK) { @@ -164,6 +401,16 @@ esp_err_t esp_vfs_register_fd_range(const esp_vfs_t *vfs, void *ctx, int min_fd, return ret; } +esp_err_t esp_vfs_register_minified_with_id(const esp_vfs_minified_t *vfs, int flags, void *ctx, esp_vfs_id_t *vfs_id) +{ + if (vfs_id == NULL) { + return ESP_ERR_INVALID_ARG; + } + + *vfs_id = -1; + return esp_vfs_register_minified_common("", LEN_PATH_PREFIX_IGNORED, vfs, flags, ctx, vfs_id); +} + esp_err_t esp_vfs_register_with_id(const esp_vfs_t *vfs, void *ctx, esp_vfs_id_t *vfs_id) { if (vfs_id == NULL) { @@ -180,7 +427,7 @@ esp_err_t esp_vfs_unregister_with_id(esp_vfs_id_t vfs_id) return ESP_ERR_INVALID_ARG; } vfs_entry_t* vfs = s_vfs[vfs_id]; - free(vfs); + esp_vfs_free_entry(vfs); s_vfs[vfs_id] = NULL; _lock_acquire(&s_fd_table_lock); @@ -193,8 +440,11 @@ esp_err_t esp_vfs_unregister_with_id(esp_vfs_id_t vfs_id) _lock_release(&s_fd_table_lock); return ESP_OK; + } +esp_err_t esp_vfs_unregister_minified_with_id(esp_vfs_id_t vfs_id) __attribute__((alias("esp_vfs_unregister_with_id"))); + esp_err_t esp_vfs_unregister(const char* base_path) { const size_t base_path_len = strlen(base_path); @@ -211,6 +461,8 @@ esp_err_t esp_vfs_unregister(const char* base_path) return ESP_ERR_INVALID_STATE; } +esp_err_t esp_vfs_unregister_minified(const char* base_path) __attribute__((alias("esp_vfs_unregister"))); + esp_err_t esp_vfs_register_fd(esp_vfs_id_t vfs_id, int *fd) { return esp_vfs_register_fd_with_local_fd(vfs_id, -1, true, fd); @@ -306,7 +558,7 @@ esp_err_t esp_vfs_set_readonly_flag(const char* base_path) } if (base_path_len == vfs->path_prefix_len && memcmp(base_path, vfs->path_prefix, vfs->path_prefix_len) == 0) { - vfs->vfs.flags |= ESP_VFS_FLAG_READONLY_FS; + vfs->flags |= ESP_VFS_FLAG_READONLY_FS; return ESP_OK; } } @@ -411,37 +663,37 @@ const vfs_entry_t* get_vfs_for_path(const char* path) * It is enough to check just one of them for NULL, as both variants are part of a union. */ #define CHECK_AND_CALL(ret, r, pvfs, func, ...) \ - if (pvfs->vfs.func == NULL) { \ + if (pvfs->vfs->func == NULL) { \ __errno_r(r) = ENOSYS; \ return -1; \ } \ - if (pvfs->vfs.flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ - ret = (*pvfs->vfs.func ## _p)(pvfs->ctx, __VA_ARGS__); \ + if (pvfs->flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ + ret = (*pvfs->vfs->func ## _p)(pvfs->ctx, __VA_ARGS__); \ } else { \ - ret = (*pvfs->vfs.func)(__VA_ARGS__);\ + ret = (*pvfs->vfs->func)(__VA_ARGS__);\ } #define CHECK_AND_CALLV(r, pvfs, func, ...) \ - if (pvfs->vfs.func == NULL) { \ + if (pvfs->vfs->func == NULL) { \ __errno_r(r) = ENOSYS; \ return; \ } \ - if (pvfs->vfs.flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ - (*pvfs->vfs.func ## _p)(pvfs->ctx, __VA_ARGS__); \ + if (pvfs->flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ + (*pvfs->vfs->func ## _p)(pvfs->ctx, __VA_ARGS__); \ } else { \ - (*pvfs->vfs.func)(__VA_ARGS__);\ + (*pvfs->vfs->func)(__VA_ARGS__);\ } #define CHECK_AND_CALLP(ret, r, pvfs, func, ...) \ - if (pvfs->vfs.func == NULL) { \ + if (pvfs->vfs->func == NULL) { \ __errno_r(r) = ENOSYS; \ return NULL; \ } \ - if (pvfs->vfs.flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ - ret = (*pvfs->vfs.func ## _p)(pvfs->ctx, __VA_ARGS__); \ + if (pvfs->flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ + ret = (*pvfs->vfs->func ## _p)(pvfs->ctx, __VA_ARGS__); \ } else { \ - ret = (*pvfs->vfs.func)(__VA_ARGS__);\ + ret = (*pvfs->vfs->func)(__VA_ARGS__);\ } #define CHECK_VFS_READONLY_FLAG(flags) \ @@ -459,7 +711,7 @@ int esp_vfs_open(struct _reent *r, const char * path, int flags, int mode) } int acc_mode = flags & O_ACCMODE; - int ro_filesystem = vfs->vfs.flags & ESP_VFS_FLAG_READONLY_FS; + int ro_filesystem = vfs->flags & ESP_VFS_FLAG_READONLY_FS; if (acc_mode != O_RDONLY && ro_filesystem) { __errno_r(r) = EROFS; return -1; @@ -648,7 +900,7 @@ int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st) } const char* path_within_vfs = translate_path(vfs, path); int ret; - CHECK_AND_CALL(ret, r, vfs, stat, path_within_vfs, st); + CHECK_AND_CALL(ret, r, vfs, dir->stat, path_within_vfs, st); return ret; } @@ -662,7 +914,7 @@ int esp_vfs_utime(const char *path, const struct utimbuf *times) return -1; } const char* path_within_vfs = translate_path(vfs, path); - CHECK_AND_CALL(ret, r, vfs, utime, path_within_vfs, times); + CHECK_AND_CALL(ret, r, vfs, dir->utime, path_within_vfs, times); return ret; } @@ -679,12 +931,12 @@ int esp_vfs_link(struct _reent *r, const char* n1, const char* n2) return -1; } - CHECK_VFS_READONLY_FLAG(vfs2->vfs.flags); + CHECK_VFS_READONLY_FLAG(vfs2->flags); const char* path1_within_vfs = translate_path(vfs, n1); const char* path2_within_vfs = translate_path(vfs, n2); int ret; - CHECK_AND_CALL(ret, r, vfs, link, path1_within_vfs, path2_within_vfs); + CHECK_AND_CALL(ret, r, vfs, dir->link, path1_within_vfs, path2_within_vfs); return ret; } @@ -696,11 +948,11 @@ int esp_vfs_unlink(struct _reent *r, const char *path) return -1; } - CHECK_VFS_READONLY_FLAG(vfs->vfs.flags); + CHECK_VFS_READONLY_FLAG(vfs->flags); const char* path_within_vfs = translate_path(vfs, path); int ret; - CHECK_AND_CALL(ret, r, vfs, unlink, path_within_vfs); + CHECK_AND_CALL(ret, r, vfs, dir->unlink, path_within_vfs); return ret; } @@ -712,7 +964,7 @@ int esp_vfs_rename(struct _reent *r, const char *src, const char *dst) return -1; } - CHECK_VFS_READONLY_FLAG(vfs->vfs.flags); + CHECK_VFS_READONLY_FLAG(vfs->flags); const vfs_entry_t* vfs_dst = get_vfs_for_path(dst); if (vfs != vfs_dst) { @@ -720,12 +972,12 @@ int esp_vfs_rename(struct _reent *r, const char *src, const char *dst) return -1; } - CHECK_VFS_READONLY_FLAG(vfs_dst->vfs.flags); + CHECK_VFS_READONLY_FLAG(vfs_dst->flags); const char* src_within_vfs = translate_path(vfs, src); const char* dst_within_vfs = translate_path(vfs, dst); int ret; - CHECK_AND_CALL(ret, r, vfs, rename, src_within_vfs, dst_within_vfs); + CHECK_AND_CALL(ret, r, vfs, dir->rename, src_within_vfs, dst_within_vfs); return ret; } @@ -739,7 +991,7 @@ DIR* esp_vfs_opendir(const char* name) } const char* path_within_vfs = translate_path(vfs, name); DIR* ret; - CHECK_AND_CALLP(ret, r, vfs, opendir, path_within_vfs); + CHECK_AND_CALLP(ret, r, vfs, dir->opendir, path_within_vfs); if (ret != NULL) { ret->dd_vfs_idx = vfs->offset; } @@ -755,7 +1007,7 @@ struct dirent* esp_vfs_readdir(DIR* pdir) return NULL; } struct dirent* ret; - CHECK_AND_CALLP(ret, r, vfs, readdir, pdir); + CHECK_AND_CALLP(ret, r, vfs, dir->readdir, pdir); return ret; } @@ -768,7 +1020,7 @@ int esp_vfs_readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_diren return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, readdir_r, pdir, entry, out_dirent); + CHECK_AND_CALL(ret, r, vfs, dir->readdir_r, pdir, entry, out_dirent); return ret; } @@ -781,7 +1033,7 @@ long esp_vfs_telldir(DIR* pdir) return -1; } long ret; - CHECK_AND_CALL(ret, r, vfs, telldir, pdir); + CHECK_AND_CALL(ret, r, vfs, dir->telldir, pdir); return ret; } @@ -793,7 +1045,7 @@ void esp_vfs_seekdir(DIR* pdir, long loc) errno = EBADF; return; } - CHECK_AND_CALLV(r, vfs, seekdir, pdir, loc); + CHECK_AND_CALLV(r, vfs, dir->seekdir, pdir, loc); } void esp_vfs_rewinddir(DIR* pdir) @@ -810,7 +1062,7 @@ int esp_vfs_closedir(DIR* pdir) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, closedir, pdir); + CHECK_AND_CALL(ret, r, vfs, dir->closedir, pdir); return ret; } @@ -823,11 +1075,11 @@ int esp_vfs_mkdir(const char* name, mode_t mode) return -1; } - CHECK_VFS_READONLY_FLAG(vfs->vfs.flags); + CHECK_VFS_READONLY_FLAG(vfs->flags); const char* path_within_vfs = translate_path(vfs, name); int ret; - CHECK_AND_CALL(ret, r, vfs, mkdir, path_within_vfs, mode); + CHECK_AND_CALL(ret, r, vfs, dir->mkdir, path_within_vfs, mode); return ret; } @@ -840,11 +1092,11 @@ int esp_vfs_rmdir(const char* name) return -1; } - CHECK_VFS_READONLY_FLAG(vfs->vfs.flags); + CHECK_VFS_READONLY_FLAG(vfs->flags); const char* path_within_vfs = translate_path(vfs, name); int ret; - CHECK_AND_CALL(ret, r, vfs, rmdir, path_within_vfs); + CHECK_AND_CALL(ret, r, vfs, dir->rmdir, path_within_vfs); return ret; } @@ -858,7 +1110,7 @@ int esp_vfs_access(const char *path, int amode) return -1; } const char* path_within_vfs = translate_path(vfs, path); - CHECK_AND_CALL(ret, r, vfs, access, path_within_vfs, amode); + CHECK_AND_CALL(ret, r, vfs, dir->access, path_within_vfs, amode); return ret; } @@ -872,10 +1124,10 @@ int esp_vfs_truncate(const char *path, off_t length) return -1; } - CHECK_VFS_READONLY_FLAG(vfs->vfs.flags); + CHECK_VFS_READONLY_FLAG(vfs->flags); const char* path_within_vfs = translate_path(vfs, path); - CHECK_AND_CALL(ret, r, vfs, truncate, path_within_vfs, length); + CHECK_AND_CALL(ret, r, vfs, dir->truncate, path_within_vfs, length); return ret; } @@ -889,10 +1141,10 @@ int esp_vfs_ftruncate(int fd, off_t length) return -1; } - CHECK_VFS_READONLY_FLAG(vfs->vfs.flags); + CHECK_VFS_READONLY_FLAG(vfs->flags); int ret; - CHECK_AND_CALL(ret, r, vfs, ftruncate, local_fd, length); + CHECK_AND_CALL(ret, r, vfs, dir->ftruncate, local_fd, length); return ret; } @@ -905,8 +1157,8 @@ static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, for (int i = 0; i < end_index; ++i) { const vfs_entry_t *vfs = get_vfs_for_index(i); const fds_triple_t *item = &vfs_fds_triple[i]; - if (vfs && vfs->vfs.end_select && item->isset) { - esp_err_t err = vfs->vfs.end_select(driver_args[i]); + if (vfs && vfs->vfs->select->end_select && item->isset) { + esp_err_t err = vfs->vfs->select->end_select(driver_args[i]); if (err != ESP_OK) { ESP_LOGD(TAG, "end_select failed: %s", esp_err_to_name(err)); } @@ -1023,8 +1275,8 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds esp_vfs_safe_fd_isset(fd, writefds) || esp_vfs_safe_fd_isset(fd, errorfds)) { const vfs_entry_t *vfs = s_vfs[vfs_index]; - socket_select = vfs->vfs.socket_select; - sel_sem.sem = vfs->vfs.get_socket_select_semaphore(); + socket_select = vfs->vfs->select->socket_select; + sel_sem.sem = vfs->vfs->select->get_socket_select_semaphore(); } } continue; @@ -1080,16 +1332,16 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds const vfs_entry_t *vfs = get_vfs_for_index(i); fds_triple_t *item = &vfs_fds_triple[i]; - if (vfs && !vfs->vfs.start_select) { + if (vfs && !vfs->vfs->select->start_select) { ESP_LOGD(TAG, "start_select function callback for this vfs (s_vfs[%d]) is not defined", vfs->offset); - } else if (vfs && vfs->vfs.start_select && item->isset) { + } else if (vfs && vfs->vfs->select->start_select && item->isset) { // call start_select for all non-socket VFSs with has at least one FD set in readfds, writefds, or errorfds // note: it can point to socket VFS but item->isset will be false for that ESP_LOGD(TAG, "calling start_select for VFS ID %d with the following local FDs", i); esp_vfs_log_fd_set("readfds", &item->readfds); esp_vfs_log_fd_set("writefds", &item->writefds); esp_vfs_log_fd_set("errorfds", &item->errorfds); - esp_err_t err = vfs->vfs.start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem, + esp_err_t err = vfs->vfs->select->start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem, driver_args + i); if (err != ESP_OK) { @@ -1193,8 +1445,8 @@ void esp_vfs_select_triggered(esp_vfs_select_sem_t sem) // Note: s_vfs_count could have changed since the start of vfs_select() call. However, that change doesn't // matter here stop_socket_select() will be called for only valid VFS drivers. const vfs_entry_t *vfs = s_vfs[i]; - if (vfs != NULL && vfs->vfs.stop_socket_select != NULL) { - vfs->vfs.stop_socket_select(sem.sem); + if (vfs != NULL && vfs->vfs->select->stop_socket_select != NULL) { + vfs->vfs->select->stop_socket_select(sem.sem); break; } } @@ -1213,9 +1465,9 @@ void esp_vfs_select_triggered_isr(esp_vfs_select_sem_t sem, BaseType_t *woken) // Note: s_vfs_count could have changed since the start of vfs_select() call. However, that change doesn't // matter here stop_socket_select() will be called for only valid VFS drivers. const vfs_entry_t *vfs = s_vfs[i]; - if (vfs != NULL && vfs->vfs.stop_socket_select_isr != NULL) { + if (vfs != NULL && vfs->vfs->select->stop_socket_select_isr != NULL) { // Note: If the UART ISR resides in IRAM, the function referenced by stop_socket_select_isr should also be placed in IRAM. - vfs->vfs.stop_socket_select_isr(sem.sem, woken); + vfs->vfs->select->stop_socket_select_isr(sem.sem, woken); break; } } @@ -1236,7 +1488,7 @@ int tcgetattr(int fd, struct termios *p) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, tcgetattr, local_fd, p); + CHECK_AND_CALL(ret, r, vfs, termios->tcgetattr, local_fd, p); return ret; } @@ -1250,7 +1502,7 @@ int tcsetattr(int fd, int optional_actions, const struct termios *p) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, tcsetattr, local_fd, optional_actions, p); + CHECK_AND_CALL(ret, r, vfs, termios->tcsetattr, local_fd, optional_actions, p); return ret; } @@ -1264,7 +1516,7 @@ int tcdrain(int fd) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, tcdrain, local_fd); + CHECK_AND_CALL(ret, r, vfs, termios->tcdrain, local_fd); return ret; } @@ -1278,7 +1530,7 @@ int tcflush(int fd, int select) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, tcflush, local_fd, select); + CHECK_AND_CALL(ret, r, vfs, termios->tcflush, local_fd, select); return ret; } @@ -1292,7 +1544,7 @@ int tcflow(int fd, int action) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, tcflow, local_fd, action); + CHECK_AND_CALL(ret, r, vfs, termios->tcflow, local_fd, action); return ret; } @@ -1306,7 +1558,7 @@ pid_t tcgetsid(int fd) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, tcgetsid, local_fd); + CHECK_AND_CALL(ret, r, vfs, termios->tcgetsid, local_fd); return ret; } @@ -1320,7 +1572,7 @@ int tcsendbreak(int fd, int duration) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, tcsendbreak, local_fd, duration); + CHECK_AND_CALL(ret, r, vfs, termios->tcsendbreak, local_fd, duration); return ret; } #endif // CONFIG_VFS_SUPPORT_TERMIOS From 36d821f70c923712c572cdeddf1dd25080d906dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Wed, 10 Jul 2024 10:42:47 +0200 Subject: [PATCH 02/11] feat(storage/vfs): add more extensive checks to vfs tests --- components/vfs/test_apps/main/test_vfs_lwip.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/vfs/test_apps/main/test_vfs_lwip.c b/components/vfs/test_apps/main/test_vfs_lwip.c index 3bed7d5ec8..e9cf3870ab 100644 --- a/components/vfs/test_apps/main/test_vfs_lwip.c +++ b/components/vfs/test_apps/main/test_vfs_lwip.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,8 +15,9 @@ TEST_CASE("fstat() sets st_mode to socket type", "[vfs][lwip]") { test_case_uses_tcpip(); int socket_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + TEST_ASSERT(socket_fd >= 0); struct stat stat = { 0 }; - fstat(socket_fd, &stat); + TEST_ASSERT_EQUAL(0, fstat(socket_fd, &stat)); TEST_ASSERT_TRUE(S_ISSOCK(stat.st_mode)); TEST_ASSERT_FALSE(S_ISBLK(stat.st_mode)); @@ -25,5 +26,5 @@ TEST_CASE("fstat() sets st_mode to socket type", "[vfs][lwip]") TEST_ASSERT_FALSE(S_ISREG(stat.st_mode)); TEST_ASSERT_FALSE(S_ISLNK(stat.st_mode)); - close(socket_fd); + TEST_ASSERT_EQUAL(0, close(socket_fd)); } From fe0fc40049e4b8cd516905f7c130c911df1608a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Tue, 6 Aug 2024 10:56:30 +0200 Subject: [PATCH 03/11] fix(storage/vfs): incorrect registration checks --- components/vfs/include/esp_vfs.h | 2 ++ components/vfs/vfs.c | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 42c6a1199a..5a664475aa 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -486,6 +486,8 @@ ssize_t esp_vfs_pwrite(int fd, const void *src, size_t size, off_t offset); */ void esp_vfs_dump_fds(FILE *fp); +void esp_vfs_dump_registered_paths(FILE *fp); + #ifdef __cplusplus } // extern "C" #endif diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index 7e494b90ef..6a88a96d2e 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -77,7 +77,7 @@ static fd_table_t s_fd_table[MAX_FDS] = { [0 ... MAX_FDS-1] = FD_TABLE_ENTRY_UNU static _lock_t s_fd_table_lock; static ssize_t esp_get_free_index(void) { - for (ssize_t i = 0; i < MAX_FDS; i++) { + for (ssize_t i = 0; i < VFS_MAX_COUNT; i++) { if (s_vfs[i] == NULL) { return i; } @@ -294,7 +294,7 @@ static esp_err_t esp_vfs_register_minified_common(const char* base_path, size_t } else { bzero(entry->path_prefix, sizeof(entry->path_prefix)); } - entry->path_prefix_len = strlen(base_path); + entry->path_prefix_len = len; entry->vfs = vfs; entry->ctx = ctx; entry->offset = index; @@ -326,6 +326,7 @@ esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minifie esp_err_t ret = esp_vfs_register_minified_common(base_path, strlen(base_path), _vfs, flags, ctx, NULL); if (ret != ESP_OK) { esp_free_minified_vfs(_vfs); + return ret; } return ESP_OK; @@ -354,6 +355,7 @@ esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_v esp_err_t ret = esp_vfs_register_minified_common(base_path, len, _vfs, vfs->flags, ctx, vfs_index); if (ret != ESP_OK) { esp_free_minified_vfs(_vfs); + return ret; } return ESP_OK; @@ -542,6 +544,16 @@ void esp_vfs_dump_fds(FILE *fp) _lock_release(&s_fd_table_lock); } +void esp_vfs_dump_registered_paths(FILE *fp) +{ + fprintf(fp, "------------------------------------------------------\n"); + fprintf(fp, ": -> \n"); + fprintf(fp, "------------------------------------------------------\n"); + for (size_t i = 0; i < VFS_MAX_COUNT; ++i) { + fprintf(fp, "%d:%s -> %p\n", i, s_vfs[i] ? s_vfs[i]->path_prefix : "NULL", s_vfs[i]); + } +} + /* * Set ESP_VFS_FLAG_READONLY_FS read-only flag for a registered virtual filesystem * for given path prefix. Should be only called from the esp_vfs_*filesystem* register From cec0525460aae0c761c978dc30a774f7c22fa125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Tue, 6 Aug 2024 11:08:39 +0200 Subject: [PATCH 04/11] fix(storage/vfs): update select sanity checks --- components/vfs/vfs.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index 6a88a96d2e..95d88afdba 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -1169,7 +1169,11 @@ static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, for (int i = 0; i < end_index; ++i) { const vfs_entry_t *vfs = get_vfs_for_index(i); const fds_triple_t *item = &vfs_fds_triple[i]; - if (vfs && vfs->vfs->select->end_select && item->isset) { + if (vfs != NULL + && vfs->vfs->select != NULL + && vfs->vfs->select->end_select != NULL + && item->isset + ) { esp_err_t err = vfs->vfs->select->end_select(driver_args[i]); if (err != ESP_OK) { ESP_LOGD(TAG, "end_select failed: %s", esp_err_to_name(err)); @@ -1457,7 +1461,10 @@ void esp_vfs_select_triggered(esp_vfs_select_sem_t sem) // Note: s_vfs_count could have changed since the start of vfs_select() call. However, that change doesn't // matter here stop_socket_select() will be called for only valid VFS drivers. const vfs_entry_t *vfs = s_vfs[i]; - if (vfs != NULL && vfs->vfs->select->stop_socket_select != NULL) { + if (vfs != NULL + && vfs->vfs->select != NULL + && vfs->vfs->select->stop_socket_select != NULL + ) { vfs->vfs->select->stop_socket_select(sem.sem); break; } @@ -1477,7 +1484,10 @@ void esp_vfs_select_triggered_isr(esp_vfs_select_sem_t sem, BaseType_t *woken) // Note: s_vfs_count could have changed since the start of vfs_select() call. However, that change doesn't // matter here stop_socket_select() will be called for only valid VFS drivers. const vfs_entry_t *vfs = s_vfs[i]; - if (vfs != NULL && vfs->vfs->select->stop_socket_select_isr != NULL) { + if (vfs != NULL + && vfs->vfs->select != NULL + && vfs->vfs->select->stop_socket_select_isr != NULL + ) { // Note: If the UART ISR resides in IRAM, the function referenced by stop_socket_select_isr should also be placed in IRAM. vfs->vfs->select->stop_socket_select_isr(sem.sem, woken); break; From 755adf3b4fdd30b85689ebc8fee18df516093f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Wed, 21 Aug 2024 12:58:38 +0200 Subject: [PATCH 05/11] feat(storage/vfs): impelement sparse vfs struct --- components/vfs/vfs.c | 443 ++++++++++++++++++++++++++++--------------- 1 file changed, 286 insertions(+), 157 deletions(-) diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index 95d88afdba..cc2a2eab03 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -101,46 +101,6 @@ static void esp_free_minified_vfs(esp_vfs_minified_t *vfs) { free(vfs); } -static esp_vfs_minified_t *esp_alloc_minified_vfs(void) { - esp_vfs_minified_t *main = (esp_vfs_minified_t*) heap_caps_malloc(sizeof(esp_vfs_minified_t), VFS_MALLOC_FLAGS); - if (main == NULL) { - return NULL; - } - - // Initialize all fields to NULL - memset(main, 0, sizeof(esp_vfs_minified_t)); - -#ifdef CONFIG_VFS_SUPPORT_DIR - main->dir = (esp_vfs_dir_t*) heap_caps_malloc(sizeof(esp_vfs_dir_t), VFS_MALLOC_FLAGS); - if (main->dir == NULL) { - goto fail; - } -#endif - -#ifdef CONFIG_VFS_SUPPORT_TERMIOS - main->termios = (esp_vfs_termios_t*) heap_caps_malloc(sizeof(esp_vfs_termios_t), VFS_MALLOC_FLAGS); - if (main->termios == NULL) { - goto fail; - } -#endif - -#ifdef CONFIG_VFS_SUPPORT_SELECT - main->select = (esp_vfs_select_t*) heap_caps_malloc(sizeof(esp_vfs_select_t), VFS_MALLOC_FLAGS); - if (main->select == NULL) { - goto fail; - } -#endif - - return main; - -#if defined(CONFIG_VFS_SUPPORT_SELECT) || defined(CONFIG_VFS_SUPPORT_TERMIOS) || defined(CONFIG_VFS_SUPPORT_DIR) -fail: - - esp_free_minified_vfs(main); - return NULL; -#endif -} - static void esp_vfs_free_entry(vfs_entry_t *entry) { if (entry == NULL) { // Necessary because of the following flags check return; @@ -154,18 +114,8 @@ static void esp_vfs_free_entry(vfs_entry_t *entry) { } static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_minified_t *min) { - if (vfs == NULL) { - ESP_LOGE(TAG, "Cannot minify NULL VFS"); - assert(vfs != NULL); // Show stack trace - abort(); // Ensure we don't continue with a NULL VFS when assert is disabled - } - - if (min == NULL) { - ESP_LOGE(TAG, "Cannot minify VFS to NULL"); - assert(min != NULL); // Show stack trace - abort(); // Ensure we don't continue with a NULL VFS when assert is disabled - } - + assert(vfs != NULL); + assert(min != NULL); *min = (esp_vfs_minified_t) { .write = vfs->write, .lseek = vfs->lseek, @@ -190,68 +140,212 @@ static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_minified_t *min) }; #ifdef CONFIG_VFS_SUPPORT_DIR - if (min->dir == NULL) { - ESP_LOGE(TAG, "Dir subcomponent is not allocated"); - assert(min->dir != NULL); // Show stack trace - abort(); // Ensure we don't continue with a NULL VFS when assert is disabled + // If the dir functions are not implemented, we don't need to convert them + if (min->dir != NULL) { + *(min->dir) = (esp_vfs_dir_t) { + .stat = vfs->stat, + .link = vfs->link, + .unlink = vfs->unlink, + .rename = vfs->rename, + .opendir = vfs->opendir, + .readdir = vfs->readdir, + .readdir_r = vfs->readdir_r, + .telldir = vfs->telldir, + .seekdir = vfs->seekdir, + .closedir = vfs->closedir, + .mkdir = vfs->mkdir, + .rmdir = vfs->rmdir, + .access = vfs->access, + .truncate = vfs->truncate, + .ftruncate = vfs->ftruncate, + .utime = vfs->utime, + }; } - *(min->dir) = (esp_vfs_dir_t) { - .stat = vfs->stat, - .link = vfs->link, - .unlink = vfs->unlink, - .rename = vfs->rename, - .opendir = vfs->opendir, - .readdir = vfs->readdir, - .readdir_r = vfs->readdir_r, - .telldir = vfs->telldir, - .seekdir = vfs->seekdir, - .closedir = vfs->closedir, - .mkdir = vfs->mkdir, - .rmdir = vfs->rmdir, - .access = vfs->access, - .truncate = vfs->truncate, - .ftruncate = vfs->ftruncate, - .utime = vfs->utime, - }; #endif // CONFIG_VFS_SUPPORT_DIR #ifdef CONFIG_VFS_SUPPORT_TERMIOS - if (min->termios == NULL) { - ESP_LOGE(TAG, "Termios subcomponent is not allocated"); - assert(min->termios != NULL); // Show stack trace - abort(); // Ensure we don't continue with a NULL VFS when assert is disabled + // If the termios functions are not implemented, we don't need to convert them + if (min->termios != NULL) { + *(min->termios) = (esp_vfs_termios_t) { + .tcsetattr = vfs->tcsetattr, + .tcgetattr = vfs->tcgetattr, + .tcdrain = vfs->tcdrain, + .tcflush = vfs->tcflush, + .tcflow = vfs->tcflow, + .tcgetsid = vfs->tcgetsid, + .tcsendbreak = vfs->tcsendbreak, + }; } - - *(min->termios) = (esp_vfs_termios_t) { - .tcsetattr = vfs->tcsetattr, - .tcgetattr = vfs->tcgetattr, - .tcdrain = vfs->tcdrain, - .tcflush = vfs->tcflush, - .tcflow = vfs->tcflow, - .tcgetsid = vfs->tcgetsid, - .tcsendbreak = vfs->tcsendbreak, - }; #endif // CONFIG_VFS_SUPPORT_TERMIOS #ifdef CONFIG_VFS_SUPPORT_SELECT - if (min->select == NULL) { - ESP_LOGE(TAG, "Select subcomponent is not allocated"); - assert(min->select != NULL); // Show stack trace - abort(); // Ensure we don't continue with a NULL VFS when assert is disabled + // If the select functions are not implemented, we don't need to convert them + if (min->select != NULL) { + *(min->select) = (esp_vfs_select_t) { + .start_select = vfs->start_select, + .socket_select = vfs->socket_select, + .stop_socket_select = vfs->stop_socket_select, + .stop_socket_select_isr = vfs->stop_socket_select_isr, + .get_socket_select_semaphore = vfs->get_socket_select_semaphore, + .end_select = vfs->end_select, + }; } - - *(min->select) = (esp_vfs_select_t) { - .start_select = vfs->start_select, - .socket_select = vfs->socket_select, - .stop_socket_select = vfs->stop_socket_select, - .stop_socket_select_isr = vfs->stop_socket_select_isr, - .get_socket_select_semaphore = vfs->get_socket_select_semaphore, - .end_select = vfs->end_select, - }; #endif // CONFIG_VFS_SUPPORT_SELECT } +static esp_vfs_minified_t* esp_duplicate_minified_vfs(const esp_vfs_minified_t *vfs) { + esp_vfs_minified_t *min = (esp_vfs_minified_t*) heap_caps_malloc(sizeof(esp_vfs_minified_t), VFS_MALLOC_FLAGS); + if (min == NULL) { + return NULL; + } + + memcpy(min, vfs, sizeof(esp_vfs_minified_t)); + + // remove references to the original components +#ifdef CONFIG_VFS_SUPPORT_DIR + min->dir = NULL; +#endif +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + min->termios = NULL; +#endif +#ifdef CONFIG_VFS_SUPPORT_SELECT + min->select = NULL; +#endif + +#ifdef CONFIG_VFS_SUPPORT_DIR + if (vfs->dir != NULL) { + min->dir = (esp_vfs_dir_t*) heap_caps_malloc(sizeof(esp_vfs_dir_t), VFS_MALLOC_FLAGS); + if (min->dir == NULL) { + goto fail; + } + memcpy(min->dir, vfs->dir, sizeof(esp_vfs_dir_t)); + } +#endif + +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + if (vfs->termios != NULL) { + min->termios = (esp_vfs_termios_t*) heap_caps_malloc(sizeof(esp_vfs_termios_t), VFS_MALLOC_FLAGS); + if (min->termios == NULL) { + goto fail; + } + memcpy(min->termios, vfs->termios, sizeof(esp_vfs_termios_t)); + } +#endif + +#ifdef CONFIG_VFS_SUPPORT_SELECT + if (vfs->select != NULL) { + min->select = (esp_vfs_select_t*) heap_caps_malloc(sizeof(esp_vfs_select_t), VFS_MALLOC_FLAGS); + if (min->select == NULL) { + goto fail; + } + memcpy(min->select, vfs->select, sizeof(esp_vfs_select_t)); + } +#endif + + return min; + +#if defined(CONFIG_VFS_SUPPORT_SELECT) || defined(CONFIG_VFS_SUPPORT_TERMIOS) || defined(CONFIG_VFS_SUPPORT_DIR) +fail: +#endif + esp_free_minified_vfs(min); + return NULL; +} + +static esp_err_t esp_vfs_make_minified_vfs(const esp_vfs_t *vfs, esp_vfs_minified_t **min) { + if (vfs == NULL) { + ESP_LOGE(TAG, "Cannot minify NULL VFS"); + return ESP_ERR_INVALID_ARG; + } + + if (min == NULL) { + ESP_LOGE(TAG, "Cannot minify VFS to NULL"); + return ESP_ERR_INVALID_ARG; + } + + esp_vfs_minified_t *main = (esp_vfs_minified_t*) heap_caps_malloc(sizeof(esp_vfs_minified_t), VFS_MALLOC_FLAGS); + if (main == NULL) { + return ESP_ERR_NO_MEM; + } + + // Initialize all fields to NULL + memset(main, 0, sizeof(esp_vfs_minified_t)); + +#ifdef CONFIG_VFS_SUPPORT_DIR + bool skip_dir = + vfs->stat == NULL && + vfs->link == NULL && + vfs->unlink == NULL && + vfs->rename == NULL && + vfs->opendir == NULL && + vfs->readdir == NULL && + vfs->readdir_r == NULL && + vfs->telldir == NULL && + vfs->seekdir == NULL && + vfs->closedir == NULL && + vfs->mkdir == NULL && + vfs->rmdir == NULL && + vfs->access == NULL && + vfs->truncate == NULL && + vfs->ftruncate == NULL && + vfs->utime == NULL; + + if (!skip_dir) { + main->dir = (esp_vfs_dir_t*) heap_caps_malloc(sizeof(esp_vfs_dir_t), VFS_MALLOC_FLAGS); + if (main->dir == NULL) { + goto fail; + } + } +#endif + +#ifdef CONFIG_VFS_SUPPORT_TERMIOS + bool skip_termios = + vfs->tcsetattr == NULL && + vfs->tcgetattr == NULL && + vfs->tcdrain == NULL && + vfs->tcflush == NULL && + vfs->tcflow == NULL && + vfs->tcgetsid == NULL && + vfs->tcsendbreak == NULL; + + if (!skip_termios) { + main->termios = (esp_vfs_termios_t*) heap_caps_malloc(sizeof(esp_vfs_termios_t), VFS_MALLOC_FLAGS); + if (main->termios == NULL) { + goto fail; + } + } +#endif + +#ifdef CONFIG_VFS_SUPPORT_SELECT + bool skip_select = + vfs->start_select == NULL && + vfs->socket_select == NULL && + vfs->stop_socket_select == NULL && + vfs->stop_socket_select_isr == NULL && + vfs->get_socket_select_semaphore == NULL && + vfs->end_select == NULL; + + if (!skip_select) { + main->select = (esp_vfs_select_t*) heap_caps_malloc(sizeof(esp_vfs_select_t), VFS_MALLOC_FLAGS); + if (main->select == NULL) { + goto fail; + } + } +#endif + + esp_minify_vfs(vfs, main); + + *min = main; + return ESP_OK; + +#if defined(CONFIG_VFS_SUPPORT_SELECT) || defined(CONFIG_VFS_SUPPORT_TERMIOS) || defined(CONFIG_VFS_SUPPORT_DIR) +fail: + + esp_free_minified_vfs(main); + return ESP_ERR_NO_MEM; +#endif +} + static esp_err_t esp_vfs_register_minified_common(const char* base_path, size_t len, const esp_vfs_minified_t* vfs, int flags, void* ctx, int *vfs_index) { if (vfs == NULL) { @@ -318,7 +412,7 @@ esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minifie return esp_vfs_register_minified_common(base_path, strlen(base_path), vfs, flags, ctx, NULL); } - esp_vfs_minified_t *_vfs = esp_alloc_minified_vfs(); + esp_vfs_minified_t *_vfs = esp_duplicate_minified_vfs(vfs); if (_vfs == NULL) { return ESP_ERR_NO_MEM; } @@ -344,15 +438,13 @@ esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_v return ESP_ERR_INVALID_ARG; } - esp_vfs_minified_t *_vfs = esp_alloc_minified_vfs(); - if (_vfs == NULL) { - return ESP_ERR_NO_MEM; + esp_vfs_minified_t *_vfs = NULL; + esp_err_t ret = esp_vfs_make_minified_vfs(vfs, &_vfs); + if (ret != ESP_OK) { + return ret; } - // Minify the VFS - esp_minify_vfs(vfs, _vfs); - - esp_err_t ret = esp_vfs_register_minified_common(base_path, len, _vfs, vfs->flags, ctx, vfs_index); + ret = esp_vfs_register_minified_common(base_path, len, _vfs, vfs->flags, ctx, vfs_index); if (ret != ESP_OK) { esp_free_minified_vfs(_vfs); return ret; @@ -629,7 +721,7 @@ const vfs_entry_t* get_vfs_for_path(const char* path) size_t len = strlen(path); for (size_t i = 0; i < s_vfs_count; ++i) { const vfs_entry_t* vfs = s_vfs[i]; - if (!vfs || vfs->path_prefix_len == LEN_PATH_PREFIX_IGNORED) { + if (vfs == NULL || vfs->path_prefix_len == LEN_PATH_PREFIX_IGNORED) { continue; } // match path prefix @@ -685,6 +777,16 @@ const vfs_entry_t* get_vfs_for_path(const char* path) ret = (*pvfs->vfs->func)(__VA_ARGS__);\ } +#define CHECK_AND_CALL_MINIFIED(ret, r, pvfs, component, func, ...) \ + if (pvfs->vfs->component == NULL || pvfs->vfs->component->func == NULL) { \ + __errno_r(r) = ENOSYS; \ + return -1; \ + } \ + if (pvfs->flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ + ret = (*pvfs->vfs->component->func ## _p)(pvfs->ctx, __VA_ARGS__); \ + } else { \ + ret = (*pvfs->vfs->component->func)(__VA_ARGS__);\ + } #define CHECK_AND_CALLV(r, pvfs, func, ...) \ if (pvfs->vfs->func == NULL) { \ @@ -697,6 +799,17 @@ const vfs_entry_t* get_vfs_for_path(const char* path) (*pvfs->vfs->func)(__VA_ARGS__);\ } +#define CHECK_AND_CALL_MINIFIEDV(r, pvfs, component, func, ...) \ + if (pvfs->vfs->component == NULL || pvfs->vfs->component->func == NULL) { \ + __errno_r(r) = ENOSYS; \ + return; \ + } \ + if (pvfs->flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ + (*pvfs->vfs->component->func ## _p)(pvfs->ctx, __VA_ARGS__); \ + } else { \ + (*pvfs->vfs->component->func)(__VA_ARGS__);\ + } + #define CHECK_AND_CALLP(ret, r, pvfs, func, ...) \ if (pvfs->vfs->func == NULL) { \ __errno_r(r) = ENOSYS; \ @@ -708,6 +821,17 @@ const vfs_entry_t* get_vfs_for_path(const char* path) ret = (*pvfs->vfs->func)(__VA_ARGS__);\ } +#define CHECK_AND_CALL_MINIFIEDP(ret, r, pvfs, component, func, ...) \ + if (pvfs->vfs->component == NULL || pvfs->vfs->component->func == NULL) { \ + __errno_r(r) = ENOSYS; \ + return NULL; \ + } \ + if (pvfs->flags & ESP_VFS_FLAG_CONTEXT_PTR) { \ + ret = (*pvfs->vfs->component->func ## _p)(pvfs->ctx, __VA_ARGS__); \ + } else { \ + ret = (*pvfs->vfs->component->func)(__VA_ARGS__);\ + } + #define CHECK_VFS_READONLY_FLAG(flags) \ if (flags & ESP_VFS_FLAG_READONLY_FS) { \ __errno_r(r) = EROFS; \ @@ -912,7 +1036,7 @@ int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st) } const char* path_within_vfs = translate_path(vfs, path); int ret; - CHECK_AND_CALL(ret, r, vfs, dir->stat, path_within_vfs, st); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, stat, path_within_vfs, st); return ret; } @@ -926,7 +1050,7 @@ int esp_vfs_utime(const char *path, const struct utimbuf *times) return -1; } const char* path_within_vfs = translate_path(vfs, path); - CHECK_AND_CALL(ret, r, vfs, dir->utime, path_within_vfs, times); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, utime, path_within_vfs, times); return ret; } @@ -948,7 +1072,7 @@ int esp_vfs_link(struct _reent *r, const char* n1, const char* n2) const char* path1_within_vfs = translate_path(vfs, n1); const char* path2_within_vfs = translate_path(vfs, n2); int ret; - CHECK_AND_CALL(ret, r, vfs, dir->link, path1_within_vfs, path2_within_vfs); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, link, path1_within_vfs, path2_within_vfs); return ret; } @@ -964,7 +1088,7 @@ int esp_vfs_unlink(struct _reent *r, const char *path) const char* path_within_vfs = translate_path(vfs, path); int ret; - CHECK_AND_CALL(ret, r, vfs, dir->unlink, path_within_vfs); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, unlink, path_within_vfs); return ret; } @@ -989,7 +1113,7 @@ int esp_vfs_rename(struct _reent *r, const char *src, const char *dst) const char* src_within_vfs = translate_path(vfs, src); const char* dst_within_vfs = translate_path(vfs, dst); int ret; - CHECK_AND_CALL(ret, r, vfs, dir->rename, src_within_vfs, dst_within_vfs); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, rename, src_within_vfs, dst_within_vfs); return ret; } @@ -1003,7 +1127,7 @@ DIR* esp_vfs_opendir(const char* name) } const char* path_within_vfs = translate_path(vfs, name); DIR* ret; - CHECK_AND_CALLP(ret, r, vfs, dir->opendir, path_within_vfs); + CHECK_AND_CALL_MINIFIEDP(ret, r, vfs, dir, opendir, path_within_vfs); if (ret != NULL) { ret->dd_vfs_idx = vfs->offset; } @@ -1019,7 +1143,7 @@ struct dirent* esp_vfs_readdir(DIR* pdir) return NULL; } struct dirent* ret; - CHECK_AND_CALLP(ret, r, vfs, dir->readdir, pdir); + CHECK_AND_CALL_MINIFIEDP(ret, r, vfs, dir, readdir, pdir); return ret; } @@ -1032,7 +1156,7 @@ int esp_vfs_readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_diren return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, dir->readdir_r, pdir, entry, out_dirent); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, readdir_r, pdir, entry, out_dirent); return ret; } @@ -1045,7 +1169,7 @@ long esp_vfs_telldir(DIR* pdir) return -1; } long ret; - CHECK_AND_CALL(ret, r, vfs, dir->telldir, pdir); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, telldir, pdir); return ret; } @@ -1057,7 +1181,7 @@ void esp_vfs_seekdir(DIR* pdir, long loc) errno = EBADF; return; } - CHECK_AND_CALLV(r, vfs, dir->seekdir, pdir, loc); + CHECK_AND_CALL_MINIFIEDV(r, vfs, dir, seekdir, pdir, loc); } void esp_vfs_rewinddir(DIR* pdir) @@ -1074,7 +1198,7 @@ int esp_vfs_closedir(DIR* pdir) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, dir->closedir, pdir); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, closedir, pdir); return ret; } @@ -1091,7 +1215,7 @@ int esp_vfs_mkdir(const char* name, mode_t mode) const char* path_within_vfs = translate_path(vfs, name); int ret; - CHECK_AND_CALL(ret, r, vfs, dir->mkdir, path_within_vfs, mode); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, mkdir, path_within_vfs, mode); return ret; } @@ -1108,7 +1232,7 @@ int esp_vfs_rmdir(const char* name) const char* path_within_vfs = translate_path(vfs, name); int ret; - CHECK_AND_CALL(ret, r, vfs, dir->rmdir, path_within_vfs); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, rmdir, path_within_vfs); return ret; } @@ -1122,7 +1246,7 @@ int esp_vfs_access(const char *path, int amode) return -1; } const char* path_within_vfs = translate_path(vfs, path); - CHECK_AND_CALL(ret, r, vfs, dir->access, path_within_vfs, amode); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, access, path_within_vfs, amode); return ret; } @@ -1139,7 +1263,7 @@ int esp_vfs_truncate(const char *path, off_t length) CHECK_VFS_READONLY_FLAG(vfs->flags); const char* path_within_vfs = translate_path(vfs, path); - CHECK_AND_CALL(ret, r, vfs, dir->truncate, path_within_vfs, length); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, truncate, path_within_vfs, length); return ret; } @@ -1156,7 +1280,7 @@ int esp_vfs_ftruncate(int fd, off_t length) CHECK_VFS_READONLY_FLAG(vfs->flags); int ret; - CHECK_AND_CALL(ret, r, vfs, dir->ftruncate, local_fd, length); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, ftruncate, local_fd, length); return ret; } @@ -1348,33 +1472,38 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds const vfs_entry_t *vfs = get_vfs_for_index(i); fds_triple_t *item = &vfs_fds_triple[i]; - if (vfs && !vfs->vfs->select->start_select) { + if (vfs == NULL || vfs->vfs->select == NULL || vfs->vfs->select->start_select == NULL) { ESP_LOGD(TAG, "start_select function callback for this vfs (s_vfs[%d]) is not defined", vfs->offset); - } else if (vfs && vfs->vfs->select->start_select && item->isset) { - // call start_select for all non-socket VFSs with has at least one FD set in readfds, writefds, or errorfds - // note: it can point to socket VFS but item->isset will be false for that - ESP_LOGD(TAG, "calling start_select for VFS ID %d with the following local FDs", i); - esp_vfs_log_fd_set("readfds", &item->readfds); - esp_vfs_log_fd_set("writefds", &item->writefds); - esp_vfs_log_fd_set("errorfds", &item->errorfds); - esp_err_t err = vfs->vfs->select->start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem, - driver_args + i); + continue; + } - if (err != ESP_OK) { - if (err != ESP_ERR_NOT_SUPPORTED) { - call_end_selects(i, vfs_fds_triple, driver_args); - } - (void) set_global_fd_sets(vfs_fds_triple, vfs_count, readfds, writefds, errorfds); - if (sel_sem.is_sem_local && sel_sem.sem) { - vSemaphoreDelete(sel_sem.sem); - sel_sem.sem = NULL; - } - free(vfs_fds_triple); - free(driver_args); - __errno_r(r) = EINTR; - ESP_LOGD(TAG, "start_select failed: %s", esp_err_to_name(err)); - return -1; + if (!item->isset) { + continue; + } + + // call start_select for all non-socket VFSs with has at least one FD set in readfds, writefds, or errorfds + // note: it can point to socket VFS but item->isset will be false for that + ESP_LOGD(TAG, "calling start_select for VFS ID %d with the following local FDs", i); + esp_vfs_log_fd_set("readfds", &item->readfds); + esp_vfs_log_fd_set("writefds", &item->writefds); + esp_vfs_log_fd_set("errorfds", &item->errorfds); + esp_err_t err = vfs->vfs->select->start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem, + driver_args + i); + + if (err != ESP_OK) { + if (err != ESP_ERR_NOT_SUPPORTED) { + call_end_selects(i, vfs_fds_triple, driver_args); } + (void) set_global_fd_sets(vfs_fds_triple, vfs_count, readfds, writefds, errorfds); + if (sel_sem.is_sem_local && sel_sem.sem) { + vSemaphoreDelete(sel_sem.sem); + sel_sem.sem = NULL; + } + free(vfs_fds_triple); + free(driver_args); + __errno_r(r) = EINTR; + ESP_LOGD(TAG, "start_select failed: %s", esp_err_to_name(err)); + return -1; } } @@ -1510,7 +1639,7 @@ int tcgetattr(int fd, struct termios *p) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, termios->tcgetattr, local_fd, p); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcgetattr, local_fd, p); return ret; } @@ -1524,7 +1653,7 @@ int tcsetattr(int fd, int optional_actions, const struct termios *p) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, termios->tcsetattr, local_fd, optional_actions, p); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcsetattr, local_fd, optional_actions, p); return ret; } @@ -1538,7 +1667,7 @@ int tcdrain(int fd) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, termios->tcdrain, local_fd); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcdrain, local_fd); return ret; } @@ -1552,7 +1681,7 @@ int tcflush(int fd, int select) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, termios->tcflush, local_fd, select); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcflush, local_fd, select); return ret; } @@ -1566,7 +1695,7 @@ int tcflow(int fd, int action) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, termios->tcflow, local_fd, action); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcflow, local_fd, action); return ret; } @@ -1580,7 +1709,7 @@ pid_t tcgetsid(int fd) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, termios->tcgetsid, local_fd); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcgetsid, local_fd); return ret; } @@ -1594,7 +1723,7 @@ int tcsendbreak(int fd, int duration) return -1; } int ret; - CHECK_AND_CALL(ret, r, vfs, termios->tcsendbreak, local_fd, duration); + CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcsendbreak, local_fd, duration); return ret; } #endif // CONFIG_VFS_SUPPORT_TERMIOS From 3cfc78ee6719d03cfb9302164935b523476f4f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Mon, 9 Sep 2024 09:42:44 +0200 Subject: [PATCH 06/11] feat(storage/vfs): update documentation for minified vfs functions --- components/vfs/include/esp_vfs_minified.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/components/vfs/include/esp_vfs_minified.h b/components/vfs/include/esp_vfs_minified.h index 3a417f54c2..bcd9871217 100644 --- a/components/vfs/include/esp_vfs_minified.h +++ b/components/vfs/include/esp_vfs_minified.h @@ -254,9 +254,11 @@ typedef struct { * In the special case of an empty base_path, a "fallback" * VFS is registered. Such VFS will handle paths which are not * matched by any other registered VFS. - * @param vfs Pointer to esp_vfs_t, a structure which maps syscalls to - * the filesystem driver functions. VFS component doesn't - * assume ownership of this pointer. + * @param vfs Pointer to esp_vfs_minified_t, a structure which maps syscalls to + * the filesystem driver functions. VFS component does not assume ownership of this struct, but see flags for more info + * @param flag Set of binary flags controlling how the registered FS should be treated + * - ESP_FLAG_VFS_STATIC - if this flag is specified VFS assumes the provided esp_vfs_minified_t is statically allocated, + * if it is not enabled a copy of the provided struct will be created, which will be managed by the VFS component * @param ctx If vfs->flags has ESP_VFS_FLAG_CONTEXT_PTR set, a pointer * which should be passed to VFS functions. Otherwise, NULL. * @@ -265,10 +267,20 @@ typedef struct { */ esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minified_t* vfs, int flags, void* ctx); +/** + * Analog of esp_vfs_register_with_id which accepts esp_vfs_minified_t instead. + * + */ esp_err_t esp_vfs_register_minified_with_id(const esp_vfs_minified_t* vfs, int flags, void* ctx, int* id); +/** + * Alias for esp_vfs_unregister for naming consistency + */ esp_err_t esp_vfs_unregister_minified(const char* base_path); +/** + * Alias for esp_vfs_unregister_with_id for naming consistency + */ esp_err_t esp_vfs_unregister_minified_with_id(esp_vfs_id_t id); #ifdef __cplusplus From 923fb635b4a2e998d7203a6d9773c34d00177203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Mon, 9 Sep 2024 10:03:11 +0200 Subject: [PATCH 07/11] feat(storage/vfs): add documentation for minified_vfs --- components/vfs/include/esp_vfs_minified.h | 24 +++++++++++++++++++---- docs/doxygen/Doxyfile | 1 + docs/en/api-reference/storage/vfs.rst | 14 +++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/components/vfs/include/esp_vfs_minified.h b/components/vfs/include/esp_vfs_minified.h index bcd9871217..55cdbd65e0 100644 --- a/components/vfs/include/esp_vfs_minified.h +++ b/components/vfs/include/esp_vfs_minified.h @@ -52,6 +52,10 @@ typedef struct #ifdef CONFIG_VFS_SUPPORT_DIR +/** + * @brief Struct containing function pointers to directory related functionality. + * + */ typedef struct { union { int (*stat_p)(void* ctx, const char * path, struct stat * st); /*!< stat with context pointer */ @@ -123,6 +127,10 @@ typedef struct { #ifdef CONFIG_VFS_SUPPORT_TERMIOS +/** + * @brief Struct containing function pointers to termios related functionality. + * + */ typedef struct { union { int (*tcsetattr_p)(void *ctx, int fd, int optional_actions, const struct termios *p); /*!< tcsetattr with context pointer */ @@ -158,6 +166,10 @@ typedef struct { #ifdef CONFIG_VFS_SUPPORT_SELECT +/** + * @brief Struct containing function pointers to select related functionality. + * + */ typedef struct { /** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */ esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args); @@ -180,6 +192,10 @@ typedef struct { #endif // CONFIG_VFS_SUPPORT_SELECT +/** + * @brief Main struct of the minified vfs API, containing basic function pointers as well as pointers to the other subcomponents. + * + */ typedef struct { union { ssize_t (*write_p)(void* p, int fd, const void * data, size_t size); /*!< Write with context pointer */ @@ -227,15 +243,15 @@ typedef struct { }; #ifdef CONFIG_VFS_SUPPORT_DIR - esp_vfs_dir_t *dir; + esp_vfs_dir_t *dir; /*!< pointer to the dir subcomponent */ #endif #ifdef CONFIG_VFS_SUPPORT_TERMIOS - esp_vfs_termios_t *termios; + esp_vfs_termios_t *termios; /*!< pointer to the termios subcomponent */ #endif #if CONFIG_VFS_SUPPORT_SELECT || defined __DOXYGEN__ - esp_vfs_select_t *select; + esp_vfs_select_t *select; /*!< pointer to the select subcomponent */ #endif } esp_vfs_minified_t; @@ -256,7 +272,7 @@ typedef struct { * matched by any other registered VFS. * @param vfs Pointer to esp_vfs_minified_t, a structure which maps syscalls to * the filesystem driver functions. VFS component does not assume ownership of this struct, but see flags for more info - * @param flag Set of binary flags controlling how the registered FS should be treated + * @param flags Set of binary flags controlling how the registered FS should be treated * - ESP_FLAG_VFS_STATIC - if this flag is specified VFS assumes the provided esp_vfs_minified_t is statically allocated, * if it is not enabled a copy of the provided struct will be created, which will be managed by the VFS component * @param ctx If vfs->flags has ESP_VFS_FLAG_CONTEXT_PTR set, a pointer diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 8a131eddec..5bdefdc834 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -314,6 +314,7 @@ INPUT = \ $(PROJECT_PATH)/components/vfs/include/esp_vfs_eventfd.h \ $(PROJECT_PATH)/components/vfs/include/esp_vfs_semihost.h \ $(PROJECT_PATH)/components/vfs/include/esp_vfs_null.h \ + $(PROJECT_PATH)/components/vfs/include/esp_vfs_minified.h \ $(PROJECT_PATH)/components/vfs/include/esp_vfs.h \ $(PROJECT_PATH)/components/wear_levelling/include/wear_levelling.h \ $(PROJECT_PATH)/components/wifi_provisioning/include/wifi_provisioning/manager.h \ diff --git a/docs/en/api-reference/storage/vfs.rst b/docs/en/api-reference/storage/vfs.rst index 44b1307546..6b0d09aace 100644 --- a/docs/en/api-reference/storage/vfs.rst +++ b/docs/en/api-reference/storage/vfs.rst @@ -192,6 +192,18 @@ Standard I/O streams (``stdin``, ``stdout``, ``stderr``) are mapped to file desc Note that creating an eventfd with ``EFD_SUPPORT_ISR`` will cause interrupts to be temporarily disabled when reading, writing the file and during the beginning and the ending of the ``select()`` when this file is set. +Minified VFS +------------ + +To minimize RAM usage, most provided filesystems use alternative version of :cpp:func:`esp_vfs_register` function, :cpp:func:`esp_vfs_register_minified`. +This version accepts :cpp:class:`esp_vfs_minified_t` instead of :cpp:class:`esp_vfs_t` alongside separate argument for OR-ed flags, +unlike :cpp:func:`esp_vfs_register` it can handle statically allocated struct, as long as the ``ESP_VFS_FLAG_STATIC`` is provided. + +The :cpp:class:`esp_vfs_minified_t` is split into separate structs based on features (directory operations, select support, termios support, ...). +The main struct contains the basic functions (``read``, ``write``, ...), alongside pointers to the feature-specific structs, these pointers can be ``NULL`` indicating lack of support for all the functions provided by that struct, this decreases the required memory. + +This API is also available for users to use. + Well Known VFS Devices ---------------------- @@ -213,6 +225,8 @@ API Reference .. include-build-file:: inc/esp_vfs.inc +.. include-build-file:: inc/esp_vfs_minified.inc + .. include-build-file:: inc/esp_vfs_dev.inc .. include-build-file:: inc/uart_vfs.inc From 3cab84f03394f4d355fed18d3cc9497df56df826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Thu, 26 Sep 2024 08:29:03 +0200 Subject: [PATCH 08/11] fix(storage/vfs): clarify minified related documentation --- components/vfs/include/esp_vfs.h | 15 +++++++++++++++ components/vfs/include/esp_vfs_minified.h | 18 +++++++++++------- docs/en/api-reference/storage/vfs.rst | 7 +++++-- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 5a664475aa..0f4a879465 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -486,6 +486,21 @@ ssize_t esp_vfs_pwrite(int fd, const void *src, size_t size, off_t offset); */ void esp_vfs_dump_fds(FILE *fp); +/** + * @brief Dump all registered FSs to the provided FILE* + * + * Dump the FSs in the format: + @verbatim + : -> + + where: + index : internal index in the table of registered FSs (the same as returned when registering fd with id) + VFS Path Prefix : file prefix used in the esp_vfs_register call or "NULL" + VFS entry ptr : pointer to the esp_vfs_minified_t struct used internally when resolving the calls + @endverbatim + * + * @param fp File descriptor where data will be dumped + */ void esp_vfs_dump_registered_paths(FILE *fp); #ifdef __cplusplus diff --git a/components/vfs/include/esp_vfs_minified.h b/components/vfs/include/esp_vfs_minified.h index 55cdbd65e0..3a522cc5f7 100644 --- a/components/vfs/include/esp_vfs_minified.h +++ b/components/vfs/include/esp_vfs_minified.h @@ -272,13 +272,17 @@ typedef struct { * matched by any other registered VFS. * @param vfs Pointer to esp_vfs_minified_t, a structure which maps syscalls to * the filesystem driver functions. VFS component does not assume ownership of this struct, but see flags for more info - * @param flags Set of binary flags controlling how the registered FS should be treated - * - ESP_FLAG_VFS_STATIC - if this flag is specified VFS assumes the provided esp_vfs_minified_t is statically allocated, - * if it is not enabled a copy of the provided struct will be created, which will be managed by the VFS component - * @param ctx If vfs->flags has ESP_VFS_FLAG_CONTEXT_PTR set, a pointer - * which should be passed to VFS functions. Otherwise, NULL. * - * @return ESP_OK if successful, ESP_ERR_NO_MEM if too many VFSes are + * @param flags Set of binary flags controlling how the registered FS should be treated + * - ESP_VFS_FLAG_STATIC - if this flag is specified VFS assumes the provided esp_vfs_minified_t and all its subcomponents are statically allocated, + * if it is not enabled a deep copy of the provided struct will be created, which will be managed by the VFS component + * - ESP_VFS_FLAG_CONTEXT_PTR - If set, the VFS will use the context-aware versions of the filesystem operation functions (suffixed with `_p`) in `esp_vfs_fs_ops_t` and its subcomponents. + * The `ctx` parameter will be passed as the context argument when these functions are invoked. + * + * @param ctx Context pointer for fs operation functions, see the ESP_VFS_FLAG_CONTEXT_PTR. + * Should be `NULL` if not used. + * + * @return ESP_OK if successful, ESP_ERR_NO_MEM if too many FSes are * registered. */ esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minified_t* vfs, int flags, void* ctx); @@ -287,7 +291,7 @@ esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minifie * Analog of esp_vfs_register_with_id which accepts esp_vfs_minified_t instead. * */ -esp_err_t esp_vfs_register_minified_with_id(const esp_vfs_minified_t* vfs, int flags, void* ctx, int* id); +esp_err_t esp_vfs_register_fs_with_id(const esp_vfs_minified_t* vfs, int flags, void* ctx, esp_vfs_id_t* id); /** * Alias for esp_vfs_unregister for naming consistency diff --git a/docs/en/api-reference/storage/vfs.rst b/docs/en/api-reference/storage/vfs.rst index 6b0d09aace..84c1afd99d 100644 --- a/docs/en/api-reference/storage/vfs.rst +++ b/docs/en/api-reference/storage/vfs.rst @@ -192,17 +192,19 @@ Standard I/O streams (``stdin``, ``stdout``, ``stderr``) are mapped to file desc Note that creating an eventfd with ``EFD_SUPPORT_ISR`` will cause interrupts to be temporarily disabled when reading, writing the file and during the beginning and the ending of the ``select()`` when this file is set. + Minified VFS ------------ -To minimize RAM usage, most provided filesystems use alternative version of :cpp:func:`esp_vfs_register` function, :cpp:func:`esp_vfs_register_minified`. +To minimize RAM usage, an alternative version of :cpp:func:`esp_vfs_register` function, :cpp:func:`esp_vfs_register_minified` is provided. This version accepts :cpp:class:`esp_vfs_minified_t` instead of :cpp:class:`esp_vfs_t` alongside separate argument for OR-ed flags, unlike :cpp:func:`esp_vfs_register` it can handle statically allocated struct, as long as the ``ESP_VFS_FLAG_STATIC`` is provided. The :cpp:class:`esp_vfs_minified_t` is split into separate structs based on features (directory operations, select support, termios support, ...). The main struct contains the basic functions (``read``, ``write``, ...), alongside pointers to the feature-specific structs, these pointers can be ``NULL`` indicating lack of support for all the functions provided by that struct, this decreases the required memory. -This API is also available for users to use. +Internally the vfs component uses this version of API, with additional steps to convert the :cpp:class:`esp_vfs_t` to :cpp:class:`esp_vfs_minified_t` upon registration. + Well Known VFS Devices ---------------------- @@ -220,6 +222,7 @@ Application Examples - :example:`system/select` demonstrates how to use synchronous I/O multiplexing with the ``select()`` function, using UART and socket file descriptors, and configuring both to act as loopbacks to receive messages sent from other tasks. + API Reference ------------- From 040ad5ca204f55cb558c760700cfb57d0220b3bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Fri, 27 Sep 2024 11:21:13 +0200 Subject: [PATCH 09/11] feat(storage/vfs): add test for ESP_VFS_FLAG_STATIC --- components/vfs/test_apps/main/CMakeLists.txt | 1 + .../vfs/test_apps/main/test_vfs_minified.c | 167 ++++++++++++++++++ components/vfs/vfs.c | 8 +- 3 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 components/vfs/test_apps/main/test_vfs_minified.c diff --git a/components/vfs/test_apps/main/CMakeLists.txt b/components/vfs/test_apps/main/CMakeLists.txt index 7ab4968a9e..e7cfc100f5 100644 --- a/components/vfs/test_apps/main/CMakeLists.txt +++ b/components/vfs/test_apps/main/CMakeLists.txt @@ -3,6 +3,7 @@ set(src "test_app_main.c" "test_vfs_access.c" "test_vfs_fd.c" "test_vfs_lwip.c" "test_vfs_open.c" "test_vfs_paths.c" "test_vfs_select.c" "test_vfs_nullfs.c" + "test_vfs_minified.c" ) idf_component_register(SRCS ${src} diff --git a/components/vfs/test_apps/main/test_vfs_minified.c b/components/vfs/test_apps/main/test_vfs_minified.c new file mode 100644 index 0000000000..f103b7b3cd --- /dev/null +++ b/components/vfs/test_apps/main/test_vfs_minified.c @@ -0,0 +1,167 @@ + +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include +#include +#include + +#include "esp_err.h" +#include "esp_vfs_minified.h" +#include "unity.h" +#include "esp_vfs.h" + +#include "unity_test_runner.h" + +#define BUF_CAP 1024 + +typedef struct { + uint8_t data[BUF_CAP]; + size_t head; + size_t tail; +} cb_t; + +void cb_reset(cb_t* buf) { + buf->head = 0; + buf->tail = 0; +} + +size_t cb_count(const cb_t *buf) { + return buf->head - buf->tail; +} + +int cb_write(cb_t *buf, const uint8_t *data, size_t size) { + size_t count = cb_count(buf); + size_t space = BUF_CAP - count; + + size_t to_write = (size > space) ? space : size; + + size_t idx = buf->head % BUF_CAP; + size_t first_chunk = BUF_CAP - idx; + if (first_chunk > to_write) + first_chunk = to_write; + + memcpy(&buf->data[idx], data, first_chunk); + buf->head += first_chunk; + + if (first_chunk < to_write) { + size_t second_chunk = to_write - first_chunk; + memcpy(&buf->data[0], data + first_chunk, second_chunk); + buf->head += second_chunk; + } + + return (int)to_write; +} + +int cb_read(cb_t *buf, uint8_t *dest, size_t count) { + size_t available = cb_count(buf); + size_t to_read = (count > available) ? available : count; + + size_t idx = buf->tail % BUF_CAP; + size_t first_chunk = BUF_CAP - idx; + if (first_chunk > to_read) + first_chunk = to_read; + + memcpy(dest, &buf->data[idx], first_chunk); + buf->tail += first_chunk; + + if (first_chunk < to_read) { + size_t second_chunk = to_read - first_chunk; + memcpy(dest + first_chunk, &buf->data[0], second_chunk); + buf->tail += second_chunk; + } + + return (int)to_read; +} + + +int buffer_open(void *ctx, const char *path, int flags, int mode) { + return 0; +} + +int buffer_write(void *ctx, int fd, const void *data, size_t size) { + cb_t* buf = (cb_t*) ctx; + return cb_write(buf, data, size); +} + +int buffer_read(void *ctx, int fd, void *data, size_t size) { + cb_t* buf = (cb_t*) ctx; + return cb_read(buf, data, size); +} + +int buffer_close(void *ctx, int fd) { + cb_reset((cb_t*) ctx); + return 0; +} + +static esp_vfs_minified_t s_buffer_fs = { + .write_p = buffer_write, + .read_p = buffer_read, + .open_p = buffer_open, + .close_p = buffer_close, +}; + +TEST_CASE("VFS won't create a copy when ESP_FLAG_VFS_STATIC is specified", "[vfs_minified]") +{ + TEST_MESSAGE("test"); + static esp_vfs_dir_t dir = {}; + static esp_vfs_minified_t vfs = { + .dir = &dir, + }; + + cb_t *buffer = calloc(1, sizeof(cb_t)); + + esp_err_t err = ESP_OK; + err = esp_vfs_register_minified("/buffer", &s_buffer_fs, ESP_VFS_FLAG_CONTEXT_PTR | ESP_VFS_FLAG_STATIC, buffer); + TEST_ASSERT_EQUAL(ESP_OK, err); + + err = esp_vfs_register_minified("/static", &vfs, ESP_VFS_FLAG_STATIC, NULL); + TEST_ASSERT_EQUAL(ESP_OK, err); + + err = esp_vfs_register_minified("/dynamic", &vfs, ESP_VFS_FLAG_DEFAULT, NULL); + TEST_ASSERT_EQUAL(ESP_OK, err); + + FILE *buf_f = fopen("/buffer/a", "r+"); + + esp_vfs_dump_registered_paths(buf_f); + + char read_buffer[512]; + size_t bytes_read = fread(read_buffer, 1, sizeof(read_buffer) - 1, buf_f); + read_buffer[bytes_read] = '\0'; // Null-terminate the string + + // Parse the buffer to extract VFS pointers + char *line = strtok(read_buffer, "\n"); + void *static_vfs_ptr = NULL; + void *dynamic_vfs_ptr = NULL; + + while (line != NULL) { + int index; + char path_prefix[64]; + char ptr_str[32]; + TEST_MESSAGE(line); + if (sscanf(line, "%d:%63s -> %31s", &index, path_prefix, ptr_str) == 3) { + void *vfs_ptr = (void *)strtoul(ptr_str, NULL, 0); + if (strcmp(path_prefix, "/static") == 0) { + static_vfs_ptr = vfs_ptr; + } else if (strcmp(path_prefix, "/dynamic") == 0) { + dynamic_vfs_ptr = vfs_ptr; + } + } + line = strtok(NULL, "\n"); + } + + // Check that the pointer for "/static" is the same as 'vfs' and "/dynamic" is different + TEST_ASSERT_EQUAL_PTR(&vfs, static_vfs_ptr); + TEST_ASSERT_NOT_EQUAL(&vfs, dynamic_vfs_ptr); + + free(buffer); + fclose(buf_f); + + esp_vfs_unregister("/buffer"); + esp_vfs_unregister("/static"); + esp_vfs_unregister("/dynamic"); +} diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index cc2a2eab03..d01aedbcfb 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -642,7 +642,13 @@ void esp_vfs_dump_registered_paths(FILE *fp) fprintf(fp, ": -> \n"); fprintf(fp, "------------------------------------------------------\n"); for (size_t i = 0; i < VFS_MAX_COUNT; ++i) { - fprintf(fp, "%d:%s -> %p\n", i, s_vfs[i] ? s_vfs[i]->path_prefix : "NULL", s_vfs[i]); + fprintf( + fp, + "%d:%s -> %p\n", + i, + s_vfs[i] ? s_vfs[i]->path_prefix : "NULL", + s_vfs[i] ? s_vfs[i]->vfs : NULL + ); } } From 18e20c0bc5cfe8a7618b4aaab9af06ab6d70c9a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Thu, 3 Oct 2024 14:38:51 +0200 Subject: [PATCH 10/11] feat(storage/vfs): change names related to minified vfs --- components/vfs/include/esp_vfs.h | 4 +- .../{esp_vfs_minified.h => esp_vfs_ops.h} | 28 ++-- .../vfs/private_include/esp_vfs_private.h | 2 +- .../vfs/test_apps/main/test_vfs_minified.c | 17 ++- components/vfs/vfs.c | 130 +++++++++--------- docs/doxygen/Doxyfile | 2 +- docs/en/api-reference/storage/vfs.rst | 10 +- 7 files changed, 96 insertions(+), 97 deletions(-) rename components/vfs/include/{esp_vfs_minified.h => esp_vfs_ops.h} (93%) diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 0f4a879465..8e71115a43 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -29,7 +29,7 @@ #include #include "sdkconfig.h" -#include "esp_vfs_minified.h" +#include "esp_vfs_ops.h" #ifdef __cplusplus extern "C" { @@ -496,7 +496,7 @@ void esp_vfs_dump_fds(FILE *fp); where: index : internal index in the table of registered FSs (the same as returned when registering fd with id) VFS Path Prefix : file prefix used in the esp_vfs_register call or "NULL" - VFS entry ptr : pointer to the esp_vfs_minified_t struct used internally when resolving the calls + VFS entry ptr : pointer to the esp_vfs_fs_ops_t struct used internally when resolving the calls @endverbatim * * @param fp File descriptor where data will be dumped diff --git a/components/vfs/include/esp_vfs_minified.h b/components/vfs/include/esp_vfs_ops.h similarity index 93% rename from components/vfs/include/esp_vfs_minified.h rename to components/vfs/include/esp_vfs_ops.h index 3a522cc5f7..bd5d635235 100644 --- a/components/vfs/include/esp_vfs_minified.h +++ b/components/vfs/include/esp_vfs_ops.h @@ -121,7 +121,7 @@ typedef struct { int (*utime_p)(void* ctx, const char *path, const struct utimbuf *times); /*!< utime with context pointer */ int (*utime)(const char *path, const struct utimbuf *times); /*!< utime without context pointer */ }; -} esp_vfs_dir_t; +} esp_vfs_dir_ops_t; #endif // CONFIG_VFS_SUPPORT_DIR @@ -160,7 +160,7 @@ typedef struct { int (*tcsendbreak_p)(void *ctx, int fd, int duration); /*!< tcsendbreak with context pointer */ int (*tcsendbreak)(int fd, int duration); /*!< tcsendbreak without context pointer */ }; -} esp_vfs_termios_t; +} esp_vfs_termios_ops_t; #endif // CONFIG_VFS_SUPPORT_TERMIOS @@ -188,7 +188,7 @@ typedef struct { /** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */ esp_err_t (*end_select)(void *end_select_args); -} esp_vfs_select_t; +} esp_vfs_select_ops_t; #endif // CONFIG_VFS_SUPPORT_SELECT @@ -243,18 +243,18 @@ typedef struct { }; #ifdef CONFIG_VFS_SUPPORT_DIR - esp_vfs_dir_t *dir; /*!< pointer to the dir subcomponent */ + esp_vfs_dir_ops_t *dir; /*!< pointer to the dir subcomponent */ #endif #ifdef CONFIG_VFS_SUPPORT_TERMIOS - esp_vfs_termios_t *termios; /*!< pointer to the termios subcomponent */ + esp_vfs_termios_ops_t *termios; /*!< pointer to the termios subcomponent */ #endif #if CONFIG_VFS_SUPPORT_SELECT || defined __DOXYGEN__ - esp_vfs_select_t *select; /*!< pointer to the select subcomponent */ + esp_vfs_select_ops_t *select; /*!< pointer to the select subcomponent */ #endif -} esp_vfs_minified_t; +} esp_vfs_fs_ops_t; /** * Register a virtual filesystem for given path prefix. @@ -270,11 +270,11 @@ typedef struct { * In the special case of an empty base_path, a "fallback" * VFS is registered. Such VFS will handle paths which are not * matched by any other registered VFS. - * @param vfs Pointer to esp_vfs_minified_t, a structure which maps syscalls to + * @param vfs Pointer to esp_vfs_fs_ops_t, a structure which maps syscalls to * the filesystem driver functions. VFS component does not assume ownership of this struct, but see flags for more info * * @param flags Set of binary flags controlling how the registered FS should be treated - * - ESP_VFS_FLAG_STATIC - if this flag is specified VFS assumes the provided esp_vfs_minified_t and all its subcomponents are statically allocated, + * - ESP_VFS_FLAG_STATIC - if this flag is specified VFS assumes the provided esp_vfs_fs_ops_t and all its subcomponents are statically allocated, * if it is not enabled a deep copy of the provided struct will be created, which will be managed by the VFS component * - ESP_VFS_FLAG_CONTEXT_PTR - If set, the VFS will use the context-aware versions of the filesystem operation functions (suffixed with `_p`) in `esp_vfs_fs_ops_t` and its subcomponents. * The `ctx` parameter will be passed as the context argument when these functions are invoked. @@ -285,23 +285,23 @@ typedef struct { * @return ESP_OK if successful, ESP_ERR_NO_MEM if too many FSes are * registered. */ -esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minified_t* vfs, int flags, void* ctx); +esp_err_t esp_vfs_register_fs(const char* base_path, const esp_vfs_fs_ops_t* vfs, int flags, void* ctx); /** - * Analog of esp_vfs_register_with_id which accepts esp_vfs_minified_t instead. + * Analog of esp_vfs_register_with_id which accepts esp_vfs_fs_ops_t instead. * */ -esp_err_t esp_vfs_register_fs_with_id(const esp_vfs_minified_t* vfs, int flags, void* ctx, esp_vfs_id_t* id); +esp_err_t esp_vfs_register_fs_with_id(const esp_vfs_fs_ops_t* vfs, int flags, void* ctx, esp_vfs_id_t* id); /** * Alias for esp_vfs_unregister for naming consistency */ -esp_err_t esp_vfs_unregister_minified(const char* base_path); +esp_err_t esp_vfs_unregister_fs(const char* base_path); /** * Alias for esp_vfs_unregister_with_id for naming consistency */ -esp_err_t esp_vfs_unregister_minified_with_id(esp_vfs_id_t id); +esp_err_t esp_vfs_unregister_fs_with_id(esp_vfs_id_t id); #ifdef __cplusplus } diff --git a/components/vfs/private_include/esp_vfs_private.h b/components/vfs/private_include/esp_vfs_private.h index b211f842a2..5dcca69b55 100644 --- a/components/vfs/private_include/esp_vfs_private.h +++ b/components/vfs/private_include/esp_vfs_private.h @@ -20,7 +20,7 @@ extern "C" { typedef struct vfs_entry_ { int flags; /*!< ESP_VFS_FLAG_CONTEXT_PTR and/or ESP_VFS_FLAG_READONLY_FS or ESP_VFS_FLAG_DEFAULT */ - const esp_vfs_minified_t *vfs; // contains pointers to VFS functions + const esp_vfs_fs_ops_t *vfs; // contains pointers to VFS functions char path_prefix[ESP_VFS_PATH_MAX]; // path prefix mapped to this VFS size_t path_prefix_len; // micro-optimization to avoid doing extra strlen void* ctx; // optional pointer which can be passed to VFS diff --git a/components/vfs/test_apps/main/test_vfs_minified.c b/components/vfs/test_apps/main/test_vfs_minified.c index f103b7b3cd..bef2e507fb 100644 --- a/components/vfs/test_apps/main/test_vfs_minified.c +++ b/components/vfs/test_apps/main/test_vfs_minified.c @@ -1,4 +1,3 @@ - /* * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * @@ -11,7 +10,7 @@ #include #include "esp_err.h" -#include "esp_vfs_minified.h" +#include "esp_vfs_ops.h" #include "unity.h" #include "esp_vfs.h" @@ -98,31 +97,31 @@ int buffer_close(void *ctx, int fd) { return 0; } -static esp_vfs_minified_t s_buffer_fs = { +static esp_vfs_fs_ops_t s_buffer_fs = { .write_p = buffer_write, .read_p = buffer_read, .open_p = buffer_open, .close_p = buffer_close, }; -TEST_CASE("VFS won't create a copy when ESP_FLAG_VFS_STATIC is specified", "[vfs_minified]") +TEST_CASE("VFS won't create a copy when ESP_FLAG_VFS_STATIC is specified", "[esp_vfs_fs_ops_t]") { TEST_MESSAGE("test"); - static esp_vfs_dir_t dir = {}; - static esp_vfs_minified_t vfs = { + static esp_vfs_dir_ops_t dir = {}; + static esp_vfs_fs_ops_t vfs = { .dir = &dir, }; cb_t *buffer = calloc(1, sizeof(cb_t)); esp_err_t err = ESP_OK; - err = esp_vfs_register_minified("/buffer", &s_buffer_fs, ESP_VFS_FLAG_CONTEXT_PTR | ESP_VFS_FLAG_STATIC, buffer); + err = esp_vfs_register_fs("/buffer", &s_buffer_fs, ESP_VFS_FLAG_CONTEXT_PTR | ESP_VFS_FLAG_STATIC, buffer); TEST_ASSERT_EQUAL(ESP_OK, err); - err = esp_vfs_register_minified("/static", &vfs, ESP_VFS_FLAG_STATIC, NULL); + err = esp_vfs_register_fs("/static", &vfs, ESP_VFS_FLAG_STATIC, NULL); TEST_ASSERT_EQUAL(ESP_OK, err); - err = esp_vfs_register_minified("/dynamic", &vfs, ESP_VFS_FLAG_DEFAULT, NULL); + err = esp_vfs_register_fs("/dynamic", &vfs, ESP_VFS_FLAG_DEFAULT, NULL); TEST_ASSERT_EQUAL(ESP_OK, err); FILE *buf_f = fopen("/buffer/a", "r+"); diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index d01aedbcfb..1f02e0f550 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -85,7 +85,7 @@ static ssize_t esp_get_free_index(void) { return -1; } -static void esp_free_minified_vfs(esp_vfs_minified_t *vfs) { +static void esp_vfs_free_fs_ops(esp_vfs_fs_ops_t *vfs) { #ifdef CONFIG_VFS_SUPPORT_TERMIOS free(vfs->termios); #endif @@ -107,16 +107,16 @@ static void esp_vfs_free_entry(vfs_entry_t *entry) { } if (!(entry->flags & ESP_VFS_FLAG_STATIC)) { - esp_free_minified_vfs((esp_vfs_minified_t*)entry->vfs); // const cast, but we know it's not static from the flag + esp_vfs_free_fs_ops((esp_vfs_fs_ops_t*)entry->vfs); // const cast, but we know it's not static from the flag } free(entry); } -static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_minified_t *min) { +static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_fs_ops_t *min) { assert(vfs != NULL); assert(min != NULL); - *min = (esp_vfs_minified_t) { + *min = (esp_vfs_fs_ops_t) { .write = vfs->write, .lseek = vfs->lseek, .read = vfs->read, @@ -142,7 +142,7 @@ static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_minified_t *min) #ifdef CONFIG_VFS_SUPPORT_DIR // If the dir functions are not implemented, we don't need to convert them if (min->dir != NULL) { - *(min->dir) = (esp_vfs_dir_t) { + *(min->dir) = (esp_vfs_dir_ops_t) { .stat = vfs->stat, .link = vfs->link, .unlink = vfs->unlink, @@ -166,7 +166,7 @@ static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_minified_t *min) #ifdef CONFIG_VFS_SUPPORT_TERMIOS // If the termios functions are not implemented, we don't need to convert them if (min->termios != NULL) { - *(min->termios) = (esp_vfs_termios_t) { + *(min->termios) = (esp_vfs_termios_ops_t) { .tcsetattr = vfs->tcsetattr, .tcgetattr = vfs->tcgetattr, .tcdrain = vfs->tcdrain, @@ -181,7 +181,7 @@ static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_minified_t *min) #ifdef CONFIG_VFS_SUPPORT_SELECT // If the select functions are not implemented, we don't need to convert them if (min->select != NULL) { - *(min->select) = (esp_vfs_select_t) { + *(min->select) = (esp_vfs_select_ops_t) { .start_select = vfs->start_select, .socket_select = vfs->socket_select, .stop_socket_select = vfs->stop_socket_select, @@ -194,13 +194,13 @@ static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_minified_t *min) } -static esp_vfs_minified_t* esp_duplicate_minified_vfs(const esp_vfs_minified_t *vfs) { - esp_vfs_minified_t *min = (esp_vfs_minified_t*) heap_caps_malloc(sizeof(esp_vfs_minified_t), VFS_MALLOC_FLAGS); +static esp_vfs_fs_ops_t* esp_vfs_duplicate_fs_ops(const esp_vfs_fs_ops_t *vfs) { + esp_vfs_fs_ops_t *min = (esp_vfs_fs_ops_t*) heap_caps_malloc(sizeof(esp_vfs_fs_ops_t), VFS_MALLOC_FLAGS); if (min == NULL) { return NULL; } - memcpy(min, vfs, sizeof(esp_vfs_minified_t)); + memcpy(min, vfs, sizeof(esp_vfs_fs_ops_t)); // remove references to the original components #ifdef CONFIG_VFS_SUPPORT_DIR @@ -215,31 +215,31 @@ static esp_vfs_minified_t* esp_duplicate_minified_vfs(const esp_vfs_minified_t * #ifdef CONFIG_VFS_SUPPORT_DIR if (vfs->dir != NULL) { - min->dir = (esp_vfs_dir_t*) heap_caps_malloc(sizeof(esp_vfs_dir_t), VFS_MALLOC_FLAGS); + min->dir = (esp_vfs_dir_ops_t*) heap_caps_malloc(sizeof(esp_vfs_dir_ops_t), VFS_MALLOC_FLAGS); if (min->dir == NULL) { goto fail; } - memcpy(min->dir, vfs->dir, sizeof(esp_vfs_dir_t)); + memcpy(min->dir, vfs->dir, sizeof(esp_vfs_dir_ops_t)); } #endif #ifdef CONFIG_VFS_SUPPORT_TERMIOS if (vfs->termios != NULL) { - min->termios = (esp_vfs_termios_t*) heap_caps_malloc(sizeof(esp_vfs_termios_t), VFS_MALLOC_FLAGS); + min->termios = (esp_vfs_termios_ops_t*) heap_caps_malloc(sizeof(esp_vfs_termios_ops_t), VFS_MALLOC_FLAGS); if (min->termios == NULL) { goto fail; } - memcpy(min->termios, vfs->termios, sizeof(esp_vfs_termios_t)); + memcpy(min->termios, vfs->termios, sizeof(esp_vfs_termios_ops_t)); } #endif #ifdef CONFIG_VFS_SUPPORT_SELECT if (vfs->select != NULL) { - min->select = (esp_vfs_select_t*) heap_caps_malloc(sizeof(esp_vfs_select_t), VFS_MALLOC_FLAGS); + min->select = (esp_vfs_select_ops_t*) heap_caps_malloc(sizeof(esp_vfs_select_ops_t), VFS_MALLOC_FLAGS); if (min->select == NULL) { goto fail; } - memcpy(min->select, vfs->select, sizeof(esp_vfs_select_t)); + memcpy(min->select, vfs->select, sizeof(esp_vfs_select_ops_t)); } #endif @@ -248,11 +248,11 @@ static esp_vfs_minified_t* esp_duplicate_minified_vfs(const esp_vfs_minified_t * #if defined(CONFIG_VFS_SUPPORT_SELECT) || defined(CONFIG_VFS_SUPPORT_TERMIOS) || defined(CONFIG_VFS_SUPPORT_DIR) fail: #endif - esp_free_minified_vfs(min); + esp_vfs_free_fs_ops(min); return NULL; } -static esp_err_t esp_vfs_make_minified_vfs(const esp_vfs_t *vfs, esp_vfs_minified_t **min) { +static esp_err_t esp_vfs_make_fs_ops(const esp_vfs_t *vfs, esp_vfs_fs_ops_t **min) { if (vfs == NULL) { ESP_LOGE(TAG, "Cannot minify NULL VFS"); return ESP_ERR_INVALID_ARG; @@ -263,13 +263,13 @@ static esp_err_t esp_vfs_make_minified_vfs(const esp_vfs_t *vfs, esp_vfs_minifie return ESP_ERR_INVALID_ARG; } - esp_vfs_minified_t *main = (esp_vfs_minified_t*) heap_caps_malloc(sizeof(esp_vfs_minified_t), VFS_MALLOC_FLAGS); + esp_vfs_fs_ops_t *main = (esp_vfs_fs_ops_t*) heap_caps_malloc(sizeof(esp_vfs_fs_ops_t), VFS_MALLOC_FLAGS); if (main == NULL) { return ESP_ERR_NO_MEM; } // Initialize all fields to NULL - memset(main, 0, sizeof(esp_vfs_minified_t)); + memset(main, 0, sizeof(esp_vfs_fs_ops_t)); #ifdef CONFIG_VFS_SUPPORT_DIR bool skip_dir = @@ -291,7 +291,7 @@ static esp_err_t esp_vfs_make_minified_vfs(const esp_vfs_t *vfs, esp_vfs_minifie vfs->utime == NULL; if (!skip_dir) { - main->dir = (esp_vfs_dir_t*) heap_caps_malloc(sizeof(esp_vfs_dir_t), VFS_MALLOC_FLAGS); + main->dir = (esp_vfs_dir_ops_t*) heap_caps_malloc(sizeof(esp_vfs_dir_ops_t), VFS_MALLOC_FLAGS); if (main->dir == NULL) { goto fail; } @@ -309,7 +309,7 @@ static esp_err_t esp_vfs_make_minified_vfs(const esp_vfs_t *vfs, esp_vfs_minifie vfs->tcsendbreak == NULL; if (!skip_termios) { - main->termios = (esp_vfs_termios_t*) heap_caps_malloc(sizeof(esp_vfs_termios_t), VFS_MALLOC_FLAGS); + main->termios = (esp_vfs_termios_ops_t*) heap_caps_malloc(sizeof(esp_vfs_termios_ops_t), VFS_MALLOC_FLAGS); if (main->termios == NULL) { goto fail; } @@ -326,7 +326,7 @@ static esp_err_t esp_vfs_make_minified_vfs(const esp_vfs_t *vfs, esp_vfs_minifie vfs->end_select == NULL; if (!skip_select) { - main->select = (esp_vfs_select_t*) heap_caps_malloc(sizeof(esp_vfs_select_t), VFS_MALLOC_FLAGS); + main->select = (esp_vfs_select_ops_t*) heap_caps_malloc(sizeof(esp_vfs_select_ops_t), VFS_MALLOC_FLAGS); if (main->select == NULL) { goto fail; } @@ -341,12 +341,12 @@ static esp_err_t esp_vfs_make_minified_vfs(const esp_vfs_t *vfs, esp_vfs_minifie #if defined(CONFIG_VFS_SUPPORT_SELECT) || defined(CONFIG_VFS_SUPPORT_TERMIOS) || defined(CONFIG_VFS_SUPPORT_DIR) fail: - esp_free_minified_vfs(main); + esp_vfs_free_fs_ops(main); return ESP_ERR_NO_MEM; #endif } -static esp_err_t esp_vfs_register_minified_common(const char* base_path, size_t len, const esp_vfs_minified_t* vfs, int flags, void* ctx, int *vfs_index) +static esp_err_t esp_vfs_register_fs_common(const char* base_path, size_t len, const esp_vfs_fs_ops_t* vfs, int flags, void* ctx, int *vfs_index) { if (vfs == NULL) { ESP_LOGE(TAG, "VFS is NULL"); @@ -401,7 +401,7 @@ static esp_err_t esp_vfs_register_minified_common(const char* base_path, size_t return ESP_OK; } -esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minified_t* vfs, int flags, void* ctx) +esp_err_t esp_vfs_register_fs(const char* base_path, const esp_vfs_fs_ops_t* vfs, int flags, void* ctx) { if (vfs == NULL) { ESP_LOGE(TAG, "VFS is NULL"); @@ -409,17 +409,17 @@ esp_err_t esp_vfs_register_minified(const char* base_path, const esp_vfs_minifie } if ((flags & ESP_VFS_FLAG_STATIC)) { - return esp_vfs_register_minified_common(base_path, strlen(base_path), vfs, flags, ctx, NULL); + return esp_vfs_register_fs_common(base_path, strlen(base_path), vfs, flags, ctx, NULL); } - esp_vfs_minified_t *_vfs = esp_duplicate_minified_vfs(vfs); + esp_vfs_fs_ops_t *_vfs = esp_vfs_duplicate_fs_ops(vfs); if (_vfs == NULL) { return ESP_ERR_NO_MEM; } - esp_err_t ret = esp_vfs_register_minified_common(base_path, strlen(base_path), _vfs, flags, ctx, NULL); + esp_err_t ret = esp_vfs_register_fs_common(base_path, strlen(base_path), _vfs, flags, ctx, NULL); if (ret != ESP_OK) { - esp_free_minified_vfs(_vfs); + esp_vfs_free_fs_ops(_vfs); return ret; } @@ -434,19 +434,19 @@ esp_err_t esp_vfs_register_common(const char* base_path, size_t len, const esp_v } if (vfs->flags & ESP_VFS_FLAG_STATIC) { - ESP_LOGE(TAG, "ESP_VFS_FLAG_STATIC is not supported for esp_vfs_t, use esp_vfs_register_minified instead"); + ESP_LOGE(TAG, "ESP_VFS_FLAG_STATIC is not supported for esp_vfs_t, use esp_vfs_register_fs instead"); return ESP_ERR_INVALID_ARG; } - esp_vfs_minified_t *_vfs = NULL; - esp_err_t ret = esp_vfs_make_minified_vfs(vfs, &_vfs); + esp_vfs_fs_ops_t *_vfs = NULL; + esp_err_t ret = esp_vfs_make_fs_ops(vfs, &_vfs); if (ret != ESP_OK) { return ret; } - ret = esp_vfs_register_minified_common(base_path, len, _vfs, vfs->flags, ctx, vfs_index); + ret = esp_vfs_register_fs_common(base_path, len, _vfs, vfs->flags, ctx, vfs_index); if (ret != ESP_OK) { - esp_free_minified_vfs(_vfs); + esp_vfs_free_fs_ops(_vfs); return ret; } @@ -495,14 +495,14 @@ esp_err_t esp_vfs_register_fd_range(const esp_vfs_t *vfs, void *ctx, int min_fd, return ret; } -esp_err_t esp_vfs_register_minified_with_id(const esp_vfs_minified_t *vfs, int flags, void *ctx, esp_vfs_id_t *vfs_id) +esp_err_t esp_vfs_register_fs_with_id(const esp_vfs_fs_ops_t *vfs, int flags, void *ctx, esp_vfs_id_t *vfs_id) { if (vfs_id == NULL) { return ESP_ERR_INVALID_ARG; } *vfs_id = -1; - return esp_vfs_register_minified_common("", LEN_PATH_PREFIX_IGNORED, vfs, flags, ctx, vfs_id); + return esp_vfs_register_fs_common("", LEN_PATH_PREFIX_IGNORED, vfs, flags, ctx, vfs_id); } esp_err_t esp_vfs_register_with_id(const esp_vfs_t *vfs, void *ctx, esp_vfs_id_t *vfs_id) @@ -537,7 +537,7 @@ esp_err_t esp_vfs_unregister_with_id(esp_vfs_id_t vfs_id) } -esp_err_t esp_vfs_unregister_minified_with_id(esp_vfs_id_t vfs_id) __attribute__((alias("esp_vfs_unregister_with_id"))); +esp_err_t esp_vfs_unregister_fs_with_id(esp_vfs_id_t vfs_id) __attribute__((alias("esp_vfs_unregister_with_id"))); esp_err_t esp_vfs_unregister(const char* base_path) { @@ -555,7 +555,7 @@ esp_err_t esp_vfs_unregister(const char* base_path) return ESP_ERR_INVALID_STATE; } -esp_err_t esp_vfs_unregister_minified(const char* base_path) __attribute__((alias("esp_vfs_unregister"))); +esp_err_t esp_vfs_unregister_fs(const char* base_path) __attribute__((alias("esp_vfs_unregister"))); esp_err_t esp_vfs_register_fd(esp_vfs_id_t vfs_id, int *fd) { @@ -783,7 +783,7 @@ const vfs_entry_t* get_vfs_for_path(const char* path) ret = (*pvfs->vfs->func)(__VA_ARGS__);\ } -#define CHECK_AND_CALL_MINIFIED(ret, r, pvfs, component, func, ...) \ +#define CHECK_AND_CALL_SUBCOMPONENT(ret, r, pvfs, component, func, ...) \ if (pvfs->vfs->component == NULL || pvfs->vfs->component->func == NULL) { \ __errno_r(r) = ENOSYS; \ return -1; \ @@ -805,7 +805,7 @@ const vfs_entry_t* get_vfs_for_path(const char* path) (*pvfs->vfs->func)(__VA_ARGS__);\ } -#define CHECK_AND_CALL_MINIFIEDV(r, pvfs, component, func, ...) \ +#define CHECK_AND_CALL_SUBCOMPONENTV(r, pvfs, component, func, ...) \ if (pvfs->vfs->component == NULL || pvfs->vfs->component->func == NULL) { \ __errno_r(r) = ENOSYS; \ return; \ @@ -827,7 +827,7 @@ const vfs_entry_t* get_vfs_for_path(const char* path) ret = (*pvfs->vfs->func)(__VA_ARGS__);\ } -#define CHECK_AND_CALL_MINIFIEDP(ret, r, pvfs, component, func, ...) \ +#define CHECK_AND_CALL_SUBCOMPONENTP(ret, r, pvfs, component, func, ...) \ if (pvfs->vfs->component == NULL || pvfs->vfs->component->func == NULL) { \ __errno_r(r) = ENOSYS; \ return NULL; \ @@ -1042,7 +1042,7 @@ int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st) } const char* path_within_vfs = translate_path(vfs, path); int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, stat, path_within_vfs, st); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, stat, path_within_vfs, st); return ret; } @@ -1056,7 +1056,7 @@ int esp_vfs_utime(const char *path, const struct utimbuf *times) return -1; } const char* path_within_vfs = translate_path(vfs, path); - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, utime, path_within_vfs, times); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, utime, path_within_vfs, times); return ret; } @@ -1078,7 +1078,7 @@ int esp_vfs_link(struct _reent *r, const char* n1, const char* n2) const char* path1_within_vfs = translate_path(vfs, n1); const char* path2_within_vfs = translate_path(vfs, n2); int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, link, path1_within_vfs, path2_within_vfs); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, link, path1_within_vfs, path2_within_vfs); return ret; } @@ -1094,7 +1094,7 @@ int esp_vfs_unlink(struct _reent *r, const char *path) const char* path_within_vfs = translate_path(vfs, path); int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, unlink, path_within_vfs); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, unlink, path_within_vfs); return ret; } @@ -1119,7 +1119,7 @@ int esp_vfs_rename(struct _reent *r, const char *src, const char *dst) const char* src_within_vfs = translate_path(vfs, src); const char* dst_within_vfs = translate_path(vfs, dst); int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, rename, src_within_vfs, dst_within_vfs); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, rename, src_within_vfs, dst_within_vfs); return ret; } @@ -1133,7 +1133,7 @@ DIR* esp_vfs_opendir(const char* name) } const char* path_within_vfs = translate_path(vfs, name); DIR* ret; - CHECK_AND_CALL_MINIFIEDP(ret, r, vfs, dir, opendir, path_within_vfs); + CHECK_AND_CALL_SUBCOMPONENTP(ret, r, vfs, dir, opendir, path_within_vfs); if (ret != NULL) { ret->dd_vfs_idx = vfs->offset; } @@ -1149,7 +1149,7 @@ struct dirent* esp_vfs_readdir(DIR* pdir) return NULL; } struct dirent* ret; - CHECK_AND_CALL_MINIFIEDP(ret, r, vfs, dir, readdir, pdir); + CHECK_AND_CALL_SUBCOMPONENTP(ret, r, vfs, dir, readdir, pdir); return ret; } @@ -1162,7 +1162,7 @@ int esp_vfs_readdir_r(DIR* pdir, struct dirent* entry, struct dirent** out_diren return -1; } int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, readdir_r, pdir, entry, out_dirent); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, readdir_r, pdir, entry, out_dirent); return ret; } @@ -1175,7 +1175,7 @@ long esp_vfs_telldir(DIR* pdir) return -1; } long ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, telldir, pdir); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, telldir, pdir); return ret; } @@ -1187,7 +1187,7 @@ void esp_vfs_seekdir(DIR* pdir, long loc) errno = EBADF; return; } - CHECK_AND_CALL_MINIFIEDV(r, vfs, dir, seekdir, pdir, loc); + CHECK_AND_CALL_SUBCOMPONENTV(r, vfs, dir, seekdir, pdir, loc); } void esp_vfs_rewinddir(DIR* pdir) @@ -1204,7 +1204,7 @@ int esp_vfs_closedir(DIR* pdir) return -1; } int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, closedir, pdir); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, closedir, pdir); return ret; } @@ -1221,7 +1221,7 @@ int esp_vfs_mkdir(const char* name, mode_t mode) const char* path_within_vfs = translate_path(vfs, name); int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, mkdir, path_within_vfs, mode); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, mkdir, path_within_vfs, mode); return ret; } @@ -1238,7 +1238,7 @@ int esp_vfs_rmdir(const char* name) const char* path_within_vfs = translate_path(vfs, name); int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, rmdir, path_within_vfs); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, rmdir, path_within_vfs); return ret; } @@ -1252,7 +1252,7 @@ int esp_vfs_access(const char *path, int amode) return -1; } const char* path_within_vfs = translate_path(vfs, path); - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, access, path_within_vfs, amode); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, access, path_within_vfs, amode); return ret; } @@ -1269,7 +1269,7 @@ int esp_vfs_truncate(const char *path, off_t length) CHECK_VFS_READONLY_FLAG(vfs->flags); const char* path_within_vfs = translate_path(vfs, path); - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, truncate, path_within_vfs, length); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, truncate, path_within_vfs, length); return ret; } @@ -1286,7 +1286,7 @@ int esp_vfs_ftruncate(int fd, off_t length) CHECK_VFS_READONLY_FLAG(vfs->flags); int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, dir, ftruncate, local_fd, length); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, dir, ftruncate, local_fd, length); return ret; } @@ -1645,7 +1645,7 @@ int tcgetattr(int fd, struct termios *p) return -1; } int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcgetattr, local_fd, p); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, termios, tcgetattr, local_fd, p); return ret; } @@ -1659,7 +1659,7 @@ int tcsetattr(int fd, int optional_actions, const struct termios *p) return -1; } int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcsetattr, local_fd, optional_actions, p); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, termios, tcsetattr, local_fd, optional_actions, p); return ret; } @@ -1673,7 +1673,7 @@ int tcdrain(int fd) return -1; } int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcdrain, local_fd); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, termios, tcdrain, local_fd); return ret; } @@ -1687,7 +1687,7 @@ int tcflush(int fd, int select) return -1; } int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcflush, local_fd, select); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, termios, tcflush, local_fd, select); return ret; } @@ -1701,7 +1701,7 @@ int tcflow(int fd, int action) return -1; } int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcflow, local_fd, action); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, termios, tcflow, local_fd, action); return ret; } @@ -1715,7 +1715,7 @@ pid_t tcgetsid(int fd) return -1; } int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcgetsid, local_fd); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, termios, tcgetsid, local_fd); return ret; } @@ -1729,7 +1729,7 @@ int tcsendbreak(int fd, int duration) return -1; } int ret; - CHECK_AND_CALL_MINIFIED(ret, r, vfs, termios, tcsendbreak, local_fd, duration); + CHECK_AND_CALL_SUBCOMPONENT(ret, r, vfs, termios, tcsendbreak, local_fd, duration); return ret; } #endif // CONFIG_VFS_SUPPORT_TERMIOS diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 5bdefdc834..b48101881a 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -314,7 +314,7 @@ INPUT = \ $(PROJECT_PATH)/components/vfs/include/esp_vfs_eventfd.h \ $(PROJECT_PATH)/components/vfs/include/esp_vfs_semihost.h \ $(PROJECT_PATH)/components/vfs/include/esp_vfs_null.h \ - $(PROJECT_PATH)/components/vfs/include/esp_vfs_minified.h \ + $(PROJECT_PATH)/components/vfs/include/esp_vfs_ops.h \ $(PROJECT_PATH)/components/vfs/include/esp_vfs.h \ $(PROJECT_PATH)/components/wear_levelling/include/wear_levelling.h \ $(PROJECT_PATH)/components/wifi_provisioning/include/wifi_provisioning/manager.h \ diff --git a/docs/en/api-reference/storage/vfs.rst b/docs/en/api-reference/storage/vfs.rst index 84c1afd99d..732699a617 100644 --- a/docs/en/api-reference/storage/vfs.rst +++ b/docs/en/api-reference/storage/vfs.rst @@ -196,14 +196,14 @@ Note that creating an eventfd with ``EFD_SUPPORT_ISR`` will cause interrupts to Minified VFS ------------ -To minimize RAM usage, an alternative version of :cpp:func:`esp_vfs_register` function, :cpp:func:`esp_vfs_register_minified` is provided. -This version accepts :cpp:class:`esp_vfs_minified_t` instead of :cpp:class:`esp_vfs_t` alongside separate argument for OR-ed flags, +To minimize RAM usage, an alternative version of :cpp:func:`esp_vfs_register` function, :cpp:func:`esp_vfs_register_fs` is provided. +This version accepts :cpp:class:`esp_vfs_fs_ops_t` instead of :cpp:class:`esp_vfs_t` alongside separate argument for OR-ed flags, unlike :cpp:func:`esp_vfs_register` it can handle statically allocated struct, as long as the ``ESP_VFS_FLAG_STATIC`` is provided. -The :cpp:class:`esp_vfs_minified_t` is split into separate structs based on features (directory operations, select support, termios support, ...). +The :cpp:class:`esp_vfs_fs_ops_t` is split into separate structs based on features (directory operations, select support, termios support, ...). The main struct contains the basic functions (``read``, ``write``, ...), alongside pointers to the feature-specific structs, these pointers can be ``NULL`` indicating lack of support for all the functions provided by that struct, this decreases the required memory. -Internally the vfs component uses this version of API, with additional steps to convert the :cpp:class:`esp_vfs_t` to :cpp:class:`esp_vfs_minified_t` upon registration. +Internally the vfs component uses this version of API, with additional steps to convert the :cpp:class:`esp_vfs_t` to :cpp:class:`esp_vfs_fs_ops_t` upon registration. Well Known VFS Devices @@ -228,7 +228,7 @@ API Reference .. include-build-file:: inc/esp_vfs.inc -.. include-build-file:: inc/esp_vfs_minified.inc +.. include-build-file:: inc/esp_vfs_ops.inc .. include-build-file:: inc/esp_vfs_dev.inc From 09820a0ae6ea9f56c70941ea84fab3d97581f53a Mon Sep 17 00:00:00 2001 From: Zhang Shuxian Date: Sat, 12 Oct 2024 11:36:13 +0800 Subject: [PATCH 11/11] docs: Update CN trans for vfs.rst and improve EN formatting --- docs/en/api-reference/storage/vfs.rst | 13 ++++---- docs/zh_CN/api-reference/storage/vfs.rst | 42 ++++++++++++++++-------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/docs/en/api-reference/storage/vfs.rst b/docs/en/api-reference/storage/vfs.rst index 732699a617..b92bebba76 100644 --- a/docs/en/api-reference/storage/vfs.rst +++ b/docs/en/api-reference/storage/vfs.rst @@ -44,7 +44,7 @@ Case 1: API functions are declared without an extra context pointer (the FS driv .write = &myfs_write, // ... other members initialized - // When registering FS, context pointer (third argument) is NULL: + // When registering FS, context pointer (the third argument) is NULL: ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL)); Case 2: API functions are declared with an extra context pointer (the FS driver supports multiple instances):: @@ -141,7 +141,9 @@ A socket VFS driver needs to be registered with the following functions defined: Please see :component_file:`lwip/port/esp32xx/vfs_lwip.c` for a reference socket driver implementation using LWIP. .. note:: + If you use :cpp:func:`select` for socket file descriptors only then you can disable the :ref:`CONFIG_VFS_SUPPORT_SELECT` option to reduce the code size and improve performance. + You should not change the socket driver during an active :cpp:func:`select` call or you might experience some undefined behavior. Paths @@ -196,14 +198,11 @@ Note that creating an eventfd with ``EFD_SUPPORT_ISR`` will cause interrupts to Minified VFS ------------ -To minimize RAM usage, an alternative version of :cpp:func:`esp_vfs_register` function, :cpp:func:`esp_vfs_register_fs` is provided. -This version accepts :cpp:class:`esp_vfs_fs_ops_t` instead of :cpp:class:`esp_vfs_t` alongside separate argument for OR-ed flags, -unlike :cpp:func:`esp_vfs_register` it can handle statically allocated struct, as long as the ``ESP_VFS_FLAG_STATIC`` is provided. +To minimize RAM usage, an alternative version of :cpp:func:`esp_vfs_register` function, :cpp:func:`esp_vfs_register_fs` is provided. This version accepts :cpp:class:`esp_vfs_fs_ops_t` instead of :cpp:class:`esp_vfs_t` alongside separate argument for OR-ed flags. Unlike :cpp:func:`esp_vfs_register`, it can handle statically allocated struct, as long as the ``ESP_VFS_FLAG_STATIC`` is provided. -The :cpp:class:`esp_vfs_fs_ops_t` is split into separate structs based on features (directory operations, select support, termios support, ...). -The main struct contains the basic functions (``read``, ``write``, ...), alongside pointers to the feature-specific structs, these pointers can be ``NULL`` indicating lack of support for all the functions provided by that struct, this decreases the required memory. +The :cpp:class:`esp_vfs_fs_ops_t` is split into separate structs based on features (directory operations, select support, termios support, ...). The main struct contains the basic functions (``read``, ``write``, ...), alongside pointers to the feature-specific structs. These pointers can be ``NULL`` indicating lack of support for all the functions provided by that struct, which decreases the required memory. -Internally the vfs component uses this version of API, with additional steps to convert the :cpp:class:`esp_vfs_t` to :cpp:class:`esp_vfs_fs_ops_t` upon registration. +Internally the VFS component uses this version of API, with additional steps to convert the :cpp:class:`esp_vfs_t` to :cpp:class:`esp_vfs_fs_ops_t` upon registration. Well Known VFS Devices diff --git a/docs/zh_CN/api-reference/storage/vfs.rst b/docs/zh_CN/api-reference/storage/vfs.rst index ff633c189c..8f96113183 100644 --- a/docs/zh_CN/api-reference/storage/vfs.rst +++ b/docs/zh_CN/api-reference/storage/vfs.rst @@ -39,34 +39,34 @@ VFS 组件支持 C 库函数(如 fopen 和 fprintf 等)与文件系统 (FS) ssize_t myfs_write(int fd, const void * data, size_t size); - // In definition of esp_vfs_t: + // 在 esp_vfs_t 的定义中: .flags = ESP_VFS_FLAG_DEFAULT, .write = &myfs_write, - // ... other members initialized + // ... 其他成员已初始化 - // When registering FS, context pointer (third argument) is NULL: + // 注册文件系统时,上下文指针(第三个参数)为 NULL: ESP_ERROR_CHECK(esp_vfs_register("/data", &myfs, NULL)); 示例 2:声明 API 函数时需要一个额外的上下文指针作为参数,即可支持多个 FS 驱动程序实例,此时使用 ``write_p`` :: ssize_t myfs_write(myfs_t* fs, int fd, const void * data, size_t size); - // In definition of esp_vfs_t: + // 在 esp_vfs_t 的定义中: .flags = ESP_VFS_FLAG_CONTEXT_PTR, .write_p = &myfs_write, - // ... other members initialized + // ... 其他成员已初始化 - // When registering FS, pass the FS context pointer into the third argument - // (hypothetical myfs_mount function is used for illustrative purposes) + // 注册文件系统时,将文件系统上下文指针传递给第三个参数 + // (使用假设的 myfs_mount 函数进行示例说明) myfs_t* myfs_inst1 = myfs_mount(partition1->offset, partition1->size); ESP_ERROR_CHECK(esp_vfs_register("/data1", &myfs, myfs_inst1)); - // Can register another instance: + // 可以注册另一个实例: myfs_t* myfs_inst2 = myfs_mount(partition2->offset, partition2->size); ESP_ERROR_CHECK(esp_vfs_register("/data2", &myfs, myfs_inst2)); 同步输入/输出多路复用 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^ VFS 组件支持通过 :cpp:func:`select` 进行同步输入/输出多路复用,其实现方式如下: @@ -91,16 +91,17 @@ VFS 组件支持通过 :cpp:func:`select` 进行同步输入/输出多路复用 :: - // In definition of esp_vfs_t: + // 在 esp_vfs_t 的定义中: .start_select = &uart_start_select, .end_select = &uart_end_select, - // ... other members initialized + // ... 其他成员已初始化 调用 :cpp:func:`start_select` 函数可以设置环境,检测指定 VFS 驱动的文件描述符读取/写入/错误条件。 调用 :cpp:func:`end_select` 函数可以终止/取消初始化/释放由 :cpp:func:`start_select` 设置的环境。 .. note:: + 在少数情况下,在调用 :cpp:func:`end_select` 之前可能并没有调用过 :cpp:func:`start_select`。因此 :cpp:func:`end_select` 的实现必须在该情况下返回错误而不能崩溃。 如需获取更多信息,请参考 :component_file:`esp_driver_uart/src/uart_vfs.c` 中 UART 外设的 VFS 驱动,尤其是函数 :cpp:func:`uart_vfs_dev_register`、:cpp:func:`uart_start_select` 和 :cpp:func:`uart_end_select`。 @@ -122,12 +123,12 @@ VFS 组件支持通过 :cpp:func:`select` 进行同步输入/输出多路复用 :: - // In definition of esp_vfs_t: + // 在 esp_vfs_t 的定义中: .socket_select = &lwip_select, .get_socket_select_semaphore = &lwip_get_socket_select_semaphore, .stop_socket_select = &lwip_stop_socket_select, .stop_socket_select_isr = &lwip_stop_socket_select_isr, - // ... other members initialized + // ... 其他成员已初始化 函数 :cpp:func:`socket_select` 是套接字驱动对 :cpp:func:`select` 的内部实现。该函数只对套接字 VFS 驱动的文件描述符起作用。 @@ -142,6 +143,7 @@ VFS 组件支持通过 :cpp:func:`select` 进行同步输入/输出多路复用 .. note:: 如果 :cpp:func:`select` 用于套接字文件描述符,可以禁用 :ref:`CONFIG_VFS_SUPPORT_SELECT` 选项来减少代码量,提高性能。 + 不要在 :cpp:func:`select` 调用过程中更改套接字驱动,否则会出现一些未定义行为。 路径 @@ -192,6 +194,17 @@ VFS 对文件路径长度没有限制,但文件系统路径前缀受 ``ESP_VFS 注意,用 ``EFD_SUPPORT_ISR`` 创建 eventfd 将导致在读取、写入文件时,以及在设置这个文件的 ``select()`` 开始和结束时,暂时禁用中断。 + +精简版 VFS +------------ + +为尽量减少 RAM 使用,提供了另一版本的 :cpp:func:`esp_vfs_register` 函数,即 :cpp:func:`esp_vfs_register_fs`。这个版本的函数接受 :cpp:class:`esp_vfs_fs_ops_t` 而不是 :cpp:class:`esp_vfs_t`,并且还接受按位或 (OR-ed) 的标志参数。与 :cpp:func:`esp_vfs_register` 函数不同,只要在调用时提供 ``ESP_VFS_FLAG_STATIC`` 标志,该函数就可以处理静态分配的结构体。 + +:cpp:class:`esp_vfs_fs_ops_t` 根据功能(如,目录操作、选择支持、termios 支持等)被拆分为不同的结构体。主结构体包含基本功能,如 ``read``、``write`` 等,并包含指向特定功能结构体的指针。这些指针可以设置为 ``NULL``,表示不支持该结构体中提供的所有功能,从而减少所需内存。 + +在内部,VFS 组件使用的是该版本的 API,并在注册时通过额外步骤将 :cpp:class:`esp_vfs_t` 转换为 :cpp:class:`esp_vfs_fs_ops_t`。 + + 常用 VFS 设备 ------------- @@ -208,11 +221,14 @@ IDF 定义了多个可供应用程序使用的 VFS 设备。这些设备包括 - :example:`system/select` 演示了如何使用 ``select()`` 函数进行同步 I/O 多路复用,使用 UART 和套接字文件描述符,并将二者配置为回环模式,以接收来自其他任务发送的消息。 + API 参考 ------------- .. include-build-file:: inc/esp_vfs.inc +.. include-build-file:: inc/esp_vfs_ops.inc + .. include-build-file:: inc/esp_vfs_dev.inc .. include-build-file:: inc/uart_vfs.inc