From 31b4edc67b75658ce5e2d41f2fc87331f4b26d49 Mon Sep 17 00:00:00 2001 From: bhgv Date: Sun, 10 May 2020 02:59:23 +0300 Subject: a try to add support of FreeRTOS riscV-64 (k210 cpu). first step --- libiot/vfs/lfs.c | 949 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 949 insertions(+) create mode 100644 libiot/vfs/lfs.c (limited to 'libiot/vfs/lfs.c') diff --git a/libiot/vfs/lfs.c b/libiot/vfs/lfs.c new file mode 100644 index 0000000..c008e5e --- /dev/null +++ b/libiot/vfs/lfs.c @@ -0,0 +1,949 @@ +/* + * Copyright (C) 2015 - 2018, IBEROXARXA SERVICIOS INTEGRALES, S.L. + * Copyright (C) 2015 - 2018, Jaume Olivé Petrus (jolive@whitecatboard.org) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * * The WHITECAT logotype cannot be changed, you can remove it, but you + * cannot change it in any way. The WHITECAT logotype is: + * + * /\ /\ + * / \_____/ \ + * /_____________\ + * W H I T E C A T + * + * * Redistributions in binary form must retain all copyright notices printed + * to any local or remote output device. This include any reference to + * Lua RTOS, whitecatboard.org, Lua, and other copyright notices that may + * appear in the future. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Lua RTOS lfs vfs + * + */ + +#include "sdkconfig.h" + +#if CONFIG_LUA_RTOS_USE_LFS + +#include "rom/spi_flash.h" +#include "esp_partition.h" + +#include + +#include +#include +#include +#include + +#include + +#include "esp_vfs.h" +#include + +#include "lfs.h" + +#include +#include +#include +#include +#include +#include +#include + +static int vfs_lfs_open(const char *path, int flags, int mode); +static ssize_t vfs_lfs_write(int fd, const void *data, size_t size); +static ssize_t vfs_lfs_read(int fd, void * dst, size_t size); +static int vfs_lfs_fstat(int fd, struct stat * st); +static int vfs_lfs_close(int fd); +static off_t vfs_lfs_lseek(int fd, off_t size, int mode); +static int vfs_lfs_access(const char *path, int amode); +static long vfs_lfs_telldir(DIR *dirp); + +static struct list files; +static lfs_t lfs; + +struct vfs_lfs_context { + uint32_t base_addr; + struct mtx lock; +}; + +/* + * This function translate error codes from lfs to errno error codes + * + */ +static int lfs_to_errno(int res) { + switch (res) { + case LFS_ERR_OK: + return 0; + + case LFS_ERR_IO: + case LFS_ERR_CORRUPT: + return EIO; + + case LFS_ERR_NOENT: + return ENOENT; + + case LFS_ERR_EXIST: + return EEXIST; + + case LFS_ERR_NOTDIR: + return ENOTDIR; + + case LFS_ERR_ISDIR: + return EISDIR; + + case LFS_ERR_NOTEMPTY: + return ENOTEMPTY; + + case LFS_ERR_BADF: + return EBADF; + + case LFS_ERR_NOMEM: + return ENOMEM; + + case LFS_ERR_NOSPC: + return ENOSPC; + + case LFS_ERR_INVAL: + return EINVAL; + + default: + return res; + } +} + +static int vfs_lfs_open(const char *path, int flags, int mode) { + int fd; + int result; + + // Allocate new file + vfs_file_t *file = calloc(1, sizeof(vfs_file_t)); + if (!file) { + errno = ENOMEM; + return -1; + } + + file->fs_file = (void *)calloc(1, sizeof(lfs_file_t)); + if (!file->fs_file) { + free(file); + errno = ENOMEM; + return -1; + } + + file->path = strdup(path); + if (!file->path) { + free(file->fs_file); + free(file); + errno = ENOMEM; + return -1; + } + + // Add file to file list and get the file descriptor + int res = lstadd(&files, file, &fd); + if (res) { + free(file->fs_file); + free(file->path); + free(file); + errno = res; + return -1; + } + + // Translate flags to lfs flags + int lfs_flags = 0; + + if (flags == O_APPEND) + lfs_flags |= LFS_O_APPEND; + + if (flags == O_RDONLY) + lfs_flags |= LFS_O_RDONLY; + + if (flags & O_WRONLY) + lfs_flags |= LFS_O_WRONLY; + + if (flags & O_RDWR) + lfs_flags |= LFS_O_RDWR; + + if (flags & O_EXCL) + lfs_flags |= LFS_O_EXCL; + + if (flags & O_CREAT) + lfs_flags |= LFS_O_CREAT; + + if (flags & O_TRUNC) + lfs_flags |= LFS_O_TRUNC; + + if (*path == '/') { + path++; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + if ((result = lfs_file_open(&lfs, file->fs_file, path, lfs_flags)) < 0) { + errno = lfs_to_errno(result); + lstremove(&files, fd, 0); + + free(file->fs_file); + free(file->path); + free(file); + + mtx_unlock(&ctx->lock); + + return -1; + } + + mtx_unlock(&ctx->lock); + + return fd; +} + +static ssize_t vfs_lfs_write(int fd, const void *data, size_t size) { + vfs_file_t *file; + int result; + + // Get file from file list + result = lstget(&files, fd, (void **) &file); + if (result) { + errno = EBADF; + return -1; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + // Write to file + result = lfs_file_write(&lfs, file->fs_file, (void *)data, size); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + return result; +} + +static ssize_t vfs_lfs_read(int fd, void *dst, size_t size) { + vfs_file_t *file; + int result; + + // Get file from file list + result = lstget(&files, fd, (void **) &file); + if (result) { + errno = EBADF; + return -1; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + // Read from file + result = lfs_file_read(&lfs, file->fs_file, dst, size); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + return result; +} + +static int vfs_lfs_fstat(int fd, struct stat *st) { + vfs_file_t *file; + struct lfs_info info; + int result; + + // Get file from file list + result = lstget(&files, fd, (void **) &file); + if (result) { + errno = EBADF; + return -1; + } + + // Init stats + memset(st, 0, sizeof(struct stat)); + + // Set block size for this file system + st->st_blksize = lfs.cfg->block_size; + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + // Get the file stats + result = lfs_stat(&lfs, file->path, &info); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + st->st_size = info.size; + st->st_mode = ((info.type==LFS_TYPE_REG)?S_IFREG:S_IFDIR); + + return 0; +} + +static int vfs_lfs_close(int fd) { + vfs_file_t *file; + int result; + + // Get file from file list + result = lstget(&files, fd, (void **) &file); + if (result) { + errno = EBADF; + return -1; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + // Close file + result = lfs_file_close(&lfs, file->fs_file); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + // Remove file from file list + lstremove(&files, fd, 0); + + free(file->fs_file); + free(file->path); + free(file); + + mtx_unlock(&ctx->lock); + + return 0; +} + +static off_t vfs_lfs_lseek(int fd, off_t size, int mode) { + vfs_file_t *file; + int result; + + // Get file from file list + result = lstget(&files, fd, (void **) &file); + if (result) { + errno = EBADF; + return -1; + } + + int whence = LFS_SEEK_CUR; + + switch (mode) { + case SEEK_SET: + whence = LFS_SEEK_SET; + break; + case SEEK_CUR: + whence = LFS_SEEK_CUR; + break; + case SEEK_END: + whence = LFS_SEEK_END; + break; + default: + errno = EINVAL; + return -1; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + result = lfs_file_seek(&lfs, file->fs_file, size, whence); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + return result; +} + +static int vfs_lfs_stat(const char *path, struct stat *st) { + struct lfs_info info; + int result; + + // Init stats + memset(st, 0, sizeof(struct stat)); + + // Set block size for this file system + st->st_blksize = lfs.cfg->block_size; + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + // Get the file stats + result = lfs_stat(&lfs, path, &info); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + st->st_size = info.size; + st->st_mode = ((info.type==LFS_TYPE_REG)?S_IFREG:S_IFDIR); + + return 0; +} + +static int vfs_lfs_access(const char *path, int amode) { +#if 0 + struct stat s; + + if (vfs_lfs_stat(path, &s) < 0) { + return -1; + } + + if (s.st_mode != S_IFREG) { + errno = EACCES; + return -1; + } + + return 0; +#endif + return 0; + +} + +static int vfs_lfs_unlink(const char *path) { + struct lfs_info info; + int result; + + // Sanity checks + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + // Is not a directory + result = lfs_stat(&lfs, path, &info); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + if (info.type == LFS_TYPE_DIR) { + mtx_unlock(&ctx->lock); + errno = EPERM; + return -1; + } + + // Unlink + if ((result = lfs_remove(&lfs, path)) < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + return 0; +} + +static int vfs_lfs_rename(const char *src, const char *dst) { + int result; + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + if ((result = lfs_rename(&lfs, src, dst)) < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + return 0; +} + +static DIR* vfs_lfs_opendir(const char *name) { + int result; + + vfs_dir_t *dir; + + dir = vfs_allocate_dir("lfs", name); + if (!dir) { + return NULL; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + // Open directory + if ((result = lfs_dir_open(&lfs, dir->fs_dir, name)) < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + vfs_free_dir(dir); + + return NULL; + } + + mtx_unlock(&ctx->lock); + + return (DIR *)dir; +} + +static int vfs_lfs_rmdir(const char *name) { + struct lfs_info info; + int result; + + // Sanity checks + if (strcmp(name,"/") == 0) { + errno = EBUSY; + return -1; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + // Is a directory + result = lfs_stat(&lfs, name, &info); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + if (info.type != LFS_TYPE_DIR) { + mtx_unlock(&ctx->lock); + errno = ENOTDIR; + return -1; + } + + // Unlink + if ((result = lfs_remove(&lfs, name)) < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + return 0; +} + +static struct dirent *vfs_lfs_readdir(DIR *pdir) { + vfs_dir_t *dir = (vfs_dir_t *)pdir; + struct dirent *ent = &dir->ent; + int result; + + // Clear current entry + memset(ent, 0, sizeof(struct dirent)); + + // If there are mount points to read, read them first + if (dir->mount) { + struct dirent *ment = mount_readdir((DIR *)dir); + if (ment) { + return ment; + } + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + +again: + // Read next directory entry + if ((result = lfs_dir_read(&lfs, ((vfs_dir_t *)pdir)->fs_dir, (struct lfs_info *)dir->fs_info)) < 0) { + errno = lfs_to_errno(result); + } else if (result > 0) { + if ((strcmp(((struct lfs_info *)dir->fs_info)->name,".") == 0) || (strcmp(((struct lfs_info *)dir->fs_info)->name,"..") == 0)) { + goto again; + } + + ent->d_type = (((struct lfs_info *)dir->fs_info)->type == LFS_TYPE_REG)?DT_REG:DT_DIR; + ent->d_fsize = ((struct lfs_info *)dir->fs_info)->size; + strlcpy(ent->d_name, ((struct lfs_info *)dir->fs_info)->name, MAXNAMLEN); + + mtx_unlock(&ctx->lock); + + return ent; + } + + mtx_unlock(&ctx->lock); + + return NULL; +} + +static long vfs_lfs_telldir(DIR *dirp) { + vfs_dir_t *dir = (vfs_dir_t *)dirp; + + lfs_soff_t offset; + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + offset = lfs_dir_tell(&lfs, dir->fs_dir); + if (offset < 0) { + mtx_unlock(&ctx->lock); + errno = EBADF; + return -1; + } + + mtx_unlock(&ctx->lock); + + return (long)offset; +} + +static int vfs_piffs_closedir(DIR *pdir) { + vfs_dir_t *dir = ((vfs_dir_t *)pdir); + int result; + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + if ((result = lfs_dir_close(&lfs, dir->fs_dir)) < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + vfs_free_dir(dir); + + mtx_unlock(&ctx->lock); + + return 0; +} + +static int vfs_lfs_mkdir(const char *path, mode_t mode) { + int result; + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + if ((result = lfs_mkdir(&lfs, path)) < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + return 0; +} + +static int vfs_lfs_fsync(int fd) { + vfs_file_t *file; + int result; + + // Get file from file list + result = lstget(&files, fd, (void **) &file); + if (result) { + errno = EBADF; + return -1; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + result = lfs_file_sync(&lfs, file->fs_file); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + return 0; +} + +static int vfs_lfs_ftruncate(int fd, off_t length) { + vfs_file_t *file; + int result; + + // Get file from file list + result = lstget(&files, fd, (void **) &file); + if (result) { + errno = EBADF; + return -1; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)lfs.cfg->context; + + mtx_lock(&ctx->lock); + + result = lfs_file_truncate(&lfs, file->fs_file, length); + if (result < 0) { + mtx_unlock(&ctx->lock); + errno = lfs_to_errno(result); + return -1; + } + + mtx_unlock(&ctx->lock); + + return 0; +} + +static int lfs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) { + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)c->context; + + if (spi_flash_read(ctx->base_addr + (block * c->block_size) + off, buffer, size) != 0) { + return LFS_ERR_IO; + } + + return 0; +} + +static int lfs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) { + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)c->context; + + if (spi_flash_write(ctx->base_addr + (block * c->block_size) + off, buffer, size) != 0) { + return LFS_ERR_IO; + } + + return 0; +} + +static int lfs_erase(const struct lfs_config *c, lfs_block_t block) { + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)c->context; + + if (spi_flash_erase_sector((ctx->base_addr + (block * c->block_size)) >> 12) != 0) { + return LFS_ERR_IO; + } + + return 0; +} + +static int lfs_sync(const struct lfs_config *c) { + return 0; +} + +static struct lfs_config *lfs_config() { + // Find a partition + uint32_t base_address = 0; + uint32_t fs_size = 0; + + const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, LUA_RTOS_LFS_PART, NULL); + + if (!partition) { + syslog(LOG_ERR, "lfs can't find a valid partition"); + return NULL; + } else { + base_address = partition->address; + fs_size = partition->size; + } + + // Allocate file system configuration data + struct lfs_config *cfg = calloc(1, sizeof(struct lfs_config)); + if (!cfg) { + syslog(LOG_ERR, "lfs not enough memory"); + return NULL; + } + + struct vfs_lfs_context *ctx = calloc(1, sizeof(struct vfs_lfs_context)); + if (!ctx) { + free(cfg); + + syslog(LOG_ERR, "lfs not enough memory"); + return NULL; + } + + // Configure the file system + cfg->read = lfs_read; + cfg->prog = lfs_prog; + cfg->erase = lfs_erase; + cfg->sync = lfs_sync; + + cfg->block_size = CONFIG_LUA_RTOS_LFS_BLOCK_SIZE; + cfg->read_size = CONFIG_LUA_RTOS_LFS_READ_SIZE; + cfg->prog_size = CONFIG_LUA_RTOS_LFS_PROG_SIZE; + cfg->block_count = fs_size / cfg->block_size; + cfg->lookahead = cfg->block_count; + + cfg->context = ctx; + ctx->base_addr = base_address; + + return cfg; +} + +int vfs_lfs_mount(const char *target) { + esp_vfs_t vfs = { + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &vfs_lfs_write, + .open = &vfs_lfs_open, + .fstat = &vfs_lfs_fstat, + .close = &vfs_lfs_close, + .read = &vfs_lfs_read, + .lseek = &vfs_lfs_lseek, + .stat = &vfs_lfs_stat, + .link = NULL, + .unlink = &vfs_lfs_unlink, + .rename = &vfs_lfs_rename, + .mkdir = &vfs_lfs_mkdir, + .opendir = &vfs_lfs_opendir, + .readdir = &vfs_lfs_readdir, + .closedir = &vfs_piffs_closedir, + .rmdir = &vfs_lfs_rmdir, + .fsync = &vfs_lfs_fsync, + .access = &vfs_lfs_access, + .ftruncate = &vfs_lfs_ftruncate, + .telldir = &vfs_lfs_telldir, + }; + + // Get configuration + struct lfs_config *cfg = lfs_config(); + if (!cfg) { + return -1; + } + + struct vfs_lfs_context *ctx = (struct vfs_lfs_context *)(cfg->context); + + mtx_init(&ctx->lock, NULL, NULL, 0); + + syslog(LOG_INFO, + "lfs start address at 0x%x, size %d Kb", + ctx->base_addr, (cfg->block_count * cfg->block_size) / 1024); + + syslog(LOG_INFO, "lfs %d blocks, %d bytes/block, %d bytes/read, %d bytes/write",cfg->block_count,cfg->block_size, cfg->read_size, cfg->prog_size); + + // Mount file system + int err = lfs_mount(&lfs, cfg); + if (err < 0) { + syslog(LOG_INFO, "lfs formatting ..."); + + int block; + for(block = 0;block < cfg->block_count;block++) { + lfs_erase(cfg, block); + } + + lfs_format(&lfs, cfg); + err = lfs_mount(&lfs, cfg); + } + + if (err == LFS_ERR_OK) { + lstinit(&files, 0, LIST_DEFAULT); + + // Register the file system + ESP_ERROR_CHECK(esp_vfs_register("/lfs", &vfs, NULL)); + + syslog(LOG_INFO, "lfs mounted on %s", target); + + return 0; + } else { + free(cfg); + free(ctx); + + syslog(LOG_INFO, "lfs mount error"); + } + + return -1; +} + +int vfs_lfs_umount(const char *target) { + // Unmount + lfs_umount(&lfs); + + // Free resources + if (lfs.cfg) { + if (lfs.cfg->context) { + mtx_destroy(&((struct vfs_lfs_context *)lfs.cfg->context)->lock); + free(lfs.cfg->context); + } + + free((struct lfs_config *)lfs.cfg); + } + + lstdestroy(&files, 1); + + // Unregister vfs + esp_vfs_unregister("/lfs"); + + syslog(LOG_INFO, "lfs unmounted"); + + return 0; +} + +int vfs_lfs_format(const char *target) { + // Unmount first + vfs_lfs_umount(target); + + // Get configuration + struct lfs_config *cfg = lfs_config(); + if (!cfg) { + return -1; + } + + // Format + int block; + for(block = 0;block < cfg->block_count;block++) { + lfs_erase(cfg, block); + } + + int err = lfs_format(&lfs, cfg); + + // Free resources + if (lfs.cfg) { + if (lfs.cfg->context) { + free(lfs.cfg->context); + } + + free((struct lfs_config *)lfs.cfg); + } + + if (err == LFS_ERR_OK) { + // Mount again + vfs_lfs_mount(target); + } + + return -1; +} + +int vfs_lfs_fsstat(const char *target, u32_t *total, u32_t *used) { + + int err = lfs_info(&lfs, total, used); + if (err != 0) { + syslog(LOG_ERR, "lfs get fs info of '%s' (%i)", target, err); + return -1; + } + + return 0; +} + +#endif -- cgit v1.2.3