feat(storage/vfs): make subcomponent pointers const

This commit is contained in:
Tomáš Rohlínek
2024-11-01 14:05:31 +01:00
parent 05b6d92042
commit ced490fc6e
2 changed files with 125 additions and 82 deletions

View File

@ -243,15 +243,15 @@ typedef struct {
}; };
#ifdef CONFIG_VFS_SUPPORT_DIR #ifdef CONFIG_VFS_SUPPORT_DIR
esp_vfs_dir_ops_t *dir; /*!< pointer to the dir subcomponent */ const esp_vfs_dir_ops_t *dir; /*!< pointer to the dir subcomponent */
#endif #endif
#ifdef CONFIG_VFS_SUPPORT_TERMIOS #ifdef CONFIG_VFS_SUPPORT_TERMIOS
esp_vfs_termios_ops_t *termios; /*!< pointer to the termios subcomponent */ const esp_vfs_termios_ops_t *termios; /*!< pointer to the termios subcomponent */
#endif #endif
#if CONFIG_VFS_SUPPORT_SELECT || defined __DOXYGEN__ #if CONFIG_VFS_SUPPORT_SELECT || defined __DOXYGEN__
esp_vfs_select_ops_t *select; /*!< pointer to the select subcomponent */ const esp_vfs_select_ops_t *select; /*!< pointer to the select subcomponent */
#endif #endif
} esp_vfs_fs_ops_t; } esp_vfs_fs_ops_t;

View File

@ -86,16 +86,17 @@ static ssize_t esp_get_free_index(void) {
} }
static void esp_vfs_free_fs_ops(esp_vfs_fs_ops_t *vfs) { static void esp_vfs_free_fs_ops(esp_vfs_fs_ops_t *vfs) {
// We can afford to cast away the const qualifier here, because we know that we allocated the struct and therefore its safe
#ifdef CONFIG_VFS_SUPPORT_TERMIOS #ifdef CONFIG_VFS_SUPPORT_TERMIOS
free(vfs->termios); free((void*)vfs->termios);
#endif #endif
#ifdef CONFIG_VFS_SUPPORT_DIR #ifdef CONFIG_VFS_SUPPORT_DIR
free(vfs->dir); free((void*)vfs->dir);
#endif #endif
#ifdef CONFIG_VFS_SUPPORT_SELECT #ifdef CONFIG_VFS_SUPPORT_SELECT
free(vfs->select); free((void*)vfs->select);
#endif #endif
free(vfs); free(vfs);
@ -113,36 +114,37 @@ static void esp_vfs_free_entry(vfs_entry_t *entry) {
free(entry); free(entry);
} }
static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_fs_ops_t *min) { typedef struct {
assert(vfs != NULL);
assert(min != NULL);
*min = (esp_vfs_fs_ops_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 #ifdef CONFIG_VFS_SUPPORT_DIR
.dir = min->dir, esp_vfs_dir_ops_t *dir;
#endif #endif
#ifdef CONFIG_VFS_SUPPORT_TERMIOS #ifdef CONFIG_VFS_SUPPORT_TERMIOS
.termios = min->termios, esp_vfs_termios_ops_t *termios;
#endif #endif
#ifdef CONFIG_VFS_SUPPORT_SELECT #ifdef CONFIG_VFS_SUPPORT_SELECT
.select = min->select, esp_vfs_select_ops_t *select;
#endif #endif
}; } vfs_component_proxy_t;
static void free_proxy_members(vfs_component_proxy_t *proxy) {
#ifdef CONFIG_VFS_SUPPORT_DIR
free(proxy->dir);
#endif
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
free(proxy->termios);
#endif
#ifdef CONFIG_VFS_SUPPORT_SELECT
free(proxy->select);
#endif
}
static esp_vfs_fs_ops_t *esp_minify_vfs(const esp_vfs_t * const vfs, vfs_component_proxy_t proxy) {
assert(vfs != NULL);
#ifdef CONFIG_VFS_SUPPORT_DIR #ifdef CONFIG_VFS_SUPPORT_DIR
// If the dir functions are not implemented, we don't need to convert them // If the dir functions are not implemented, we don't need to convert them
if (min->dir != NULL) { if (proxy.dir != NULL) {
*(min->dir) = (esp_vfs_dir_ops_t) { *(proxy.dir) = (esp_vfs_dir_ops_t) {
.stat = vfs->stat, .stat = vfs->stat,
.link = vfs->link, .link = vfs->link,
.unlink = vfs->unlink, .unlink = vfs->unlink,
@ -165,8 +167,8 @@ static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_fs_ops_t *min) {
#ifdef CONFIG_VFS_SUPPORT_TERMIOS #ifdef CONFIG_VFS_SUPPORT_TERMIOS
// If the termios functions are not implemented, we don't need to convert them // If the termios functions are not implemented, we don't need to convert them
if (min->termios != NULL) { if (proxy.termios != NULL) {
*(min->termios) = (esp_vfs_termios_ops_t) { *(proxy.termios) = (esp_vfs_termios_ops_t) {
.tcsetattr = vfs->tcsetattr, .tcsetattr = vfs->tcsetattr,
.tcgetattr = vfs->tcgetattr, .tcgetattr = vfs->tcgetattr,
.tcdrain = vfs->tcdrain, .tcdrain = vfs->tcdrain,
@ -180,8 +182,8 @@ static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_fs_ops_t *min) {
#ifdef CONFIG_VFS_SUPPORT_SELECT #ifdef CONFIG_VFS_SUPPORT_SELECT
// If the select functions are not implemented, we don't need to convert them // If the select functions are not implemented, we don't need to convert them
if (min->select != NULL) { if (proxy.select != NULL) {
*(min->select) = (esp_vfs_select_ops_t) { *(proxy.select) = (esp_vfs_select_ops_t) {
.start_select = vfs->start_select, .start_select = vfs->start_select,
.socket_select = vfs->socket_select, .socket_select = vfs->socket_select,
.stop_socket_select = vfs->stop_socket_select, .stop_socket_select = vfs->stop_socket_select,
@ -192,63 +194,109 @@ static void esp_minify_vfs(const esp_vfs_t * const vfs, esp_vfs_fs_ops_t *min) {
} }
#endif // CONFIG_VFS_SUPPORT_SELECT #endif // CONFIG_VFS_SUPPORT_SELECT
} esp_vfs_fs_ops_t tmp = {
.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 = proxy.dir,
#endif
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
.termios = proxy.termios,
#endif
#ifdef CONFIG_VFS_SUPPORT_SELECT
.select = proxy.select,
#endif
};
static esp_vfs_fs_ops_t* esp_vfs_duplicate_fs_ops(const esp_vfs_fs_ops_t *vfs) { esp_vfs_fs_ops_t *out = heap_caps_malloc(sizeof(esp_vfs_fs_ops_t), VFS_MALLOC_FLAGS);
esp_vfs_fs_ops_t *min = (esp_vfs_fs_ops_t*) heap_caps_malloc(sizeof(esp_vfs_fs_ops_t), VFS_MALLOC_FLAGS); if (out == NULL) {
if (min == NULL) {
return NULL; return NULL;
} }
memcpy(min, vfs, sizeof(esp_vfs_fs_ops_t)); // Doing this is the only way to correctly initialize const members of a struct according to C standard
memcpy(out, &tmp, sizeof(esp_vfs_fs_ops_t));
// remove references to the original components return out;
#ifdef CONFIG_VFS_SUPPORT_DIR }
min->dir = NULL;
#endif
#ifdef CONFIG_VFS_SUPPORT_TERMIOS static esp_vfs_fs_ops_t* esp_vfs_duplicate_fs_ops(const esp_vfs_fs_ops_t *orig) {
min->termios = NULL; vfs_component_proxy_t proxy = {};
#endif
#ifdef CONFIG_VFS_SUPPORT_SELECT
min->select = NULL;
#endif
#ifdef CONFIG_VFS_SUPPORT_DIR #ifdef CONFIG_VFS_SUPPORT_DIR
if (vfs->dir != NULL) { if (orig->dir != NULL) {
min->dir = (esp_vfs_dir_ops_t*) heap_caps_malloc(sizeof(esp_vfs_dir_ops_t), VFS_MALLOC_FLAGS); proxy.dir = (esp_vfs_dir_ops_t*) heap_caps_malloc(sizeof(esp_vfs_dir_ops_t), VFS_MALLOC_FLAGS);
if (min->dir == NULL) { if (proxy.dir == NULL) {
goto fail; goto fail;
} }
memcpy(min->dir, vfs->dir, sizeof(esp_vfs_dir_ops_t)); memcpy(proxy.dir, orig->dir, sizeof(esp_vfs_dir_ops_t));
} }
#endif #endif
#ifdef CONFIG_VFS_SUPPORT_TERMIOS #ifdef CONFIG_VFS_SUPPORT_TERMIOS
if (vfs->termios != NULL) { if (orig->termios != NULL) {
min->termios = (esp_vfs_termios_ops_t*) heap_caps_malloc(sizeof(esp_vfs_termios_ops_t), VFS_MALLOC_FLAGS); proxy.termios = (esp_vfs_termios_ops_t*) heap_caps_malloc(sizeof(esp_vfs_termios_ops_t), VFS_MALLOC_FLAGS);
if (min->termios == NULL) { if (proxy.termios == NULL) {
goto fail; goto fail;
} }
memcpy(min->termios, vfs->termios, sizeof(esp_vfs_termios_ops_t)); memcpy(proxy.termios, orig->termios, sizeof(esp_vfs_termios_ops_t));
} }
#endif #endif
#ifdef CONFIG_VFS_SUPPORT_SELECT #ifdef CONFIG_VFS_SUPPORT_SELECT
if (vfs->select != NULL) { if (orig->select != NULL) {
min->select = (esp_vfs_select_ops_t*) heap_caps_malloc(sizeof(esp_vfs_select_ops_t), VFS_MALLOC_FLAGS); proxy.select = (esp_vfs_select_ops_t*) heap_caps_malloc(sizeof(esp_vfs_select_ops_t), VFS_MALLOC_FLAGS);
if (min->select == NULL) { if (proxy.select == NULL) {
goto fail; goto fail;
} }
memcpy(min->select, vfs->select, sizeof(esp_vfs_select_ops_t)); memcpy(proxy.select, orig->select, sizeof(esp_vfs_select_ops_t));
} }
#endif #endif
return min; // This tediousness is required because of const members
esp_vfs_fs_ops_t tmp = {
.write = orig->write,
.lseek = orig->lseek,
.read = orig->read,
.pread = orig->pread,
.pwrite = orig->pwrite,
.open = orig->open,
.close = orig->close,
.fstat = orig->fstat,
.fcntl = orig->fcntl,
.ioctl = orig->ioctl,
.fsync = orig->fsync,
#ifdef CONFIG_VFS_SUPPORT_DIR
.dir = proxy.dir,
#endif
#ifdef CONFIG_VFS_SUPPORT_TERMIOS
.termios = proxy.termios,
#endif
#ifdef CONFIG_VFS_SUPPORT_SELECT
.select = proxy.select,
#endif
};
esp_vfs_fs_ops_t *out = heap_caps_malloc(sizeof(esp_vfs_fs_ops_t), VFS_MALLOC_FLAGS);
if (out == NULL) {
goto fail;
}
memcpy(out, &tmp, sizeof(esp_vfs_fs_ops_t));
return out;
#if defined(CONFIG_VFS_SUPPORT_SELECT) || defined(CONFIG_VFS_SUPPORT_TERMIOS) || defined(CONFIG_VFS_SUPPORT_DIR)
fail: fail:
#endif free_proxy_members(&proxy);
esp_vfs_free_fs_ops(min);
return NULL; return NULL;
} }
@ -263,16 +311,10 @@ static esp_err_t esp_vfs_make_fs_ops(const esp_vfs_t *vfs, esp_vfs_fs_ops_t **mi
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
esp_vfs_fs_ops_t *main = (esp_vfs_fs_ops_t*) heap_caps_malloc(sizeof(esp_vfs_fs_ops_t), VFS_MALLOC_FLAGS); vfs_component_proxy_t proxy = {};
if (main == NULL) {
return ESP_ERR_NO_MEM;
}
// Initialize all fields to NULL
memset(main, 0, sizeof(esp_vfs_fs_ops_t));
#ifdef CONFIG_VFS_SUPPORT_DIR #ifdef CONFIG_VFS_SUPPORT_DIR
bool skip_dir = const bool skip_dir =
vfs->stat == NULL && vfs->stat == NULL &&
vfs->link == NULL && vfs->link == NULL &&
vfs->unlink == NULL && vfs->unlink == NULL &&
@ -291,15 +333,15 @@ static esp_err_t esp_vfs_make_fs_ops(const esp_vfs_t *vfs, esp_vfs_fs_ops_t **mi
vfs->utime == NULL; vfs->utime == NULL;
if (!skip_dir) { if (!skip_dir) {
main->dir = (esp_vfs_dir_ops_t*) heap_caps_malloc(sizeof(esp_vfs_dir_ops_t), VFS_MALLOC_FLAGS); proxy.dir = (esp_vfs_dir_ops_t*) heap_caps_malloc(sizeof(esp_vfs_dir_ops_t), VFS_MALLOC_FLAGS);
if (main->dir == NULL) { if (proxy.dir == NULL) {
goto fail; goto fail;
} }
} }
#endif #endif
#ifdef CONFIG_VFS_SUPPORT_TERMIOS #ifdef CONFIG_VFS_SUPPORT_TERMIOS
bool skip_termios = const bool skip_termios =
vfs->tcsetattr == NULL && vfs->tcsetattr == NULL &&
vfs->tcgetattr == NULL && vfs->tcgetattr == NULL &&
vfs->tcdrain == NULL && vfs->tcdrain == NULL &&
@ -309,15 +351,15 @@ static esp_err_t esp_vfs_make_fs_ops(const esp_vfs_t *vfs, esp_vfs_fs_ops_t **mi
vfs->tcsendbreak == NULL; vfs->tcsendbreak == NULL;
if (!skip_termios) { if (!skip_termios) {
main->termios = (esp_vfs_termios_ops_t*) heap_caps_malloc(sizeof(esp_vfs_termios_ops_t), VFS_MALLOC_FLAGS); proxy.termios = (esp_vfs_termios_ops_t*) heap_caps_malloc(sizeof(esp_vfs_termios_ops_t), VFS_MALLOC_FLAGS);
if (main->termios == NULL) { if (proxy.termios == NULL) {
goto fail; goto fail;
} }
} }
#endif #endif
#ifdef CONFIG_VFS_SUPPORT_SELECT #ifdef CONFIG_VFS_SUPPORT_SELECT
bool skip_select = const bool skip_select =
vfs->start_select == NULL && vfs->start_select == NULL &&
vfs->socket_select == NULL && vfs->socket_select == NULL &&
vfs->stop_socket_select == NULL && vfs->stop_socket_select == NULL &&
@ -326,24 +368,25 @@ static esp_err_t esp_vfs_make_fs_ops(const esp_vfs_t *vfs, esp_vfs_fs_ops_t **mi
vfs->end_select == NULL; vfs->end_select == NULL;
if (!skip_select) { if (!skip_select) {
main->select = (esp_vfs_select_ops_t*) heap_caps_malloc(sizeof(esp_vfs_select_ops_t), VFS_MALLOC_FLAGS); proxy.select = (esp_vfs_select_ops_t*) heap_caps_malloc(sizeof(esp_vfs_select_ops_t), VFS_MALLOC_FLAGS);
if (main->select == NULL) { if (proxy.select == NULL) {
goto fail; goto fail;
} }
} }
#endif #endif
esp_minify_vfs(vfs, main); esp_vfs_fs_ops_t *main = esp_minify_vfs(vfs, proxy);
if (main == NULL) {
goto fail;
}
*min = main; *min = main;
return ESP_OK; return ESP_OK;
#if defined(CONFIG_VFS_SUPPORT_SELECT) || defined(CONFIG_VFS_SUPPORT_TERMIOS) || defined(CONFIG_VFS_SUPPORT_DIR)
fail: fail:
esp_vfs_free_fs_ops(main); free_proxy_members(&proxy);
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
#endif
} }
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) 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)