diff options
Diffstat (limited to 'libiot/vfs/ramfs.c')
| -rw-r--r-- | libiot/vfs/ramfs.c | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/libiot/vfs/ramfs.c b/libiot/vfs/ramfs.c new file mode 100644 index 0000000..270209c --- /dev/null +++ b/libiot/vfs/ramfs.c @@ -0,0 +1,634 @@ +/* + * 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 <organization> 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 <COPYRIGHT HOLDER> 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, RAM file system + * + */ + +#include "sdkconfig.h" + +#if CONFIG_LUA_RTOS_USE_RAM_FS + +#include "esp_partition.h" + +#include <freertos/FreeRTOS.h> + +#include <string.h> +#include <stdio.h> +#include <limits.h> +#include <dirent.h> + +#include <sys/stat.h> + +#include "esp_vfs.h" + +#include <errno.h> + +#include "ramfs.h" + +#include <sys/syslog.h> +#include <sys/mount.h> +#include <sys/mutex.h> +#include <sys/list.h> +#include <sys/fcntl.h> +#include <sys/vfs/vfs.h> +#include <dirent.h> + +static int vfs_ramfs_open(const char *path, int flags, int mode); +static ssize_t vfs_ramfs_write(int fd, const void *data, size_t size); +static ssize_t vfs_ramfs_read(int fd, void * dst, size_t size); +static int vfs_ramfs_fstat(int fd, struct stat * st); +static int vfs_ramfs_close(int fd); +static off_t vfs_ramfs_lseek(int fd, off_t size, int mode); +static int vfs_ramfs_access(const char *path, int amode); + +static struct list files; +static ramfs_t fs; + +/* + * This function translate file system errors to POSIX errors + * + */ +static int ramfs_to_errno(int res) { + switch (res) { + case RAMFS_ERR_OK: + return 0; + case RAMFS_ERR_NOMEM: + return ENOMEM; + case RAMFS_ERR_NOENT: + return ENOENT; + case RAMFS_ERR_EXIST: + return EEXIST; + case RAMFS_ERR_NOTDIR: + return ENOTDIR; + case RAMFS_ERR_BADF: + return EBADF; + case RAMFS_ERR_ACCESS: + return EACCES; + case RAMFS_ERR_NOSPC: + return ENOSPC; + case RAMFS_ERR_INVAL: + return EINVAL; + case RAMFS_ERR_ISDIR: + return EISDIR; + case RAMFS_ERR_NOTEMPTY: + return ENOTEMPTY; + case RAMFS_ERR_BUSY: + return EBUSY; + case RAMFS_ERR_PERM: + return EPERM; + case RAMFS_ERR_NAMETOOLONG: + return ENAMETOOLONG; + } + + return ENOTSUP; +} + +static int vfs_ramfs_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(ramfs_file_t)); + if (!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); + errno = res; + return -1; + } + + // Translate POSIX flags to file system flags + int ramfs_flags = 0; + + // Access mode + int access_mode = flags & O_ACCMODE; + + if (access_mode == O_RDONLY) { + ramfs_flags |= RAMFS_O_RDONLY; + } else if (access_mode == O_WRONLY) { + ramfs_flags |= RAMFS_O_WRONLY; + } else if (access_mode == O_RDWR) { + ramfs_flags |= RAMFS_O_RDWR; + } + + // File status + if (flags & O_CREAT) { + ramfs_flags |= RAMFS_O_CREAT; + } + + if (flags & O_EXCL) { + ramfs_flags |= RAMFS_O_EXCL; + } + + if (flags & O_TRUNC) { + ramfs_flags |= RAMFS_O_TRUNC; + } + + if (flags & O_APPEND) { + ramfs_flags |= RAMFS_O_APPEND; + } + + if ((result = ramfs_file_open(&fs, file->fs_file, path, ramfs_flags)) != RAMFS_ERR_OK) { + errno = ramfs_to_errno(result); + lstremove(&files, fd, 0); + + free(file->fs_file); + free(file); + + return -1; + } + + return fd; +} + +static ssize_t vfs_ramfs_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; + } + + // Write to file + result = ramfs_file_write(&fs, file->fs_file, (void *)data, size); + if (result < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + return result; +} + +static ssize_t vfs_ramfs_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; + } + + // Read from file + result = ramfs_file_read(&fs, file->fs_file, dst, size); + if (result < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + return result; +} + +static int vfs_ramfs_fstat(int fd, struct stat *st) { + vfs_file_t *file; + ramfs_info_t 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)); + + // Get the file stats + result = ramfs_file_stat(&fs, file->fs_file, &info); + if (result < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + st->st_size = info.size; + st->st_mode = ((info.type==RAMFS_FILE)?S_IFREG:S_IFDIR); + st->st_blksize = fs.block_size; + + return 0; +} + +static int vfs_ramfs_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; + } + + // Close file + result = ramfs_file_close(&fs, file->fs_file); + if (result < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + // Remove file from file list + lstremove(&files, fd, 0); + + free(file->fs_file); + free(file); + + return 0; +} + +static off_t vfs_ramfs_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; + } + + // Convert POSIX whence to file system whence + int whence = RAMFS_SEEK_CUR; + + switch (mode) { + case SEEK_SET: + whence = RAMFS_SEEK_SET; + break; + case SEEK_CUR: + whence = RAMFS_SEEK_CUR; + break; + case SEEK_END: + whence = RAMFS_SEEK_END; + break; + default: + errno = EINVAL; + return -1; + } + + result = ramfs_file_seek(&fs, file->fs_file, size, whence); + if (result < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + return result; +} + +static int vfs_ramfs_stat(const char *path, struct stat *st) { + ramfs_info_t info; + int result; + + // Init stats + memset(st, 0, sizeof(struct stat)); + + // Get the file stats + result = ramfs_stat(&fs, path, &info); + if (result < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + st->st_size = info.size; + st->st_mode = ((info.type==RAMFS_FILE)?S_IFREG:S_IFDIR); + st->st_blksize = fs.block_size; + + return 0; +} + +static int vfs_ramfs_access(const char *path, int amode) { +#if 0 + struct stat s; + + if (vfs_ramfs_stat(path, &s) < 0) { + return -1; + } + + if (s.st_mode != S_IFREG) { + errno = EACCES; + return -1; + } + + return 0; +#endif + return 0; + +} + +static int vfs_ramfs_unlink(const char *path) { + int result; + + if ((result = ramfs_unlink(&fs, path)) < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + return 0; +} + +static int vfs_ramfs_rename(const char *src, const char *dst) { + int result; + + if ((result = ramfs_rename(&fs, src, dst)) < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + return 0; +} + +static DIR* vfs_ramfs_opendir(const char *name) { + int result; + + vfs_dir_t *dir = vfs_allocate_dir("ramfs", name); + if (!dir) { + return NULL; + } + + // Open directory + if ((result = ramfs_dir_open(&fs, dir->fs_dir, name)) < 0) { + errno = ramfs_to_errno(result); + vfs_free_dir(dir); + + return NULL; + } + + return (DIR *)dir; +} + +static int vfs_ramfs_rmdir(const char *name) { + int result; + + if ((result = ramfs_rmdir(&fs, name)) < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + return 0; +} + +static struct dirent *vfs_ramfs_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; + } + } + + // Read next directory entry + if ((result = ramfs_dir_read(&fs, ((vfs_dir_t *)pdir)->fs_dir, (ramfs_info_t *)dir->fs_info)) == RAMFS_ERR_OK) { + ent->d_type = (((ramfs_info_t *)dir->fs_info)->type == RAMFS_FILE)?DT_REG:DT_DIR; + ent->d_fsize = ((ramfs_info_t *)dir->fs_info)->size; + strlcpy(ent->d_name, ((ramfs_info_t *)dir->fs_info)->name, MAXNAMLEN); + + return ent; + } + + if (result != RAMFS_ERR_NOENT) { + errno = ramfs_to_errno(result); + } + + return NULL; +} + +static long vfs_ramfs_telldir(DIR *dirp) { + vfs_dir_t *dir = (vfs_dir_t *)dirp; + ramfs_off_t offset; + + offset = ramfs_telldir(&fs, dir->fs_dir); + if (offset < 0) { + errno = ramfs_to_errno(offset); + return -1; + } + + return (long)offset; +} + +static int vfs_ramfs_closedir(DIR *pdir) { + vfs_dir_t *dir = ((vfs_dir_t *)pdir); + int result; + + if ((result = ramfs_dir_close(&fs, dir->fs_dir)) < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + vfs_free_dir(dir); + + return 0; +} + +static int vfs_ramfs_mkdir(const char *path, mode_t mode) { + int result; + + if ((result = ramfs_mkdir(&fs, path)) < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + return 0; +} + +static int vfs_ramfs_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; + } + + result = ramfs_file_sync(&fs, file->fs_file); + if (result < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + return 0; +} + +static int vfs_ramfs_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; + } + + if ((result = ramfs_file_truncate(&fs, file->fs_file, length)) != RAMFS_ERR_OK) { + errno = ramfs_to_errno(result); + return -1; + } + + return 0; +} + +static int vfs_ramfs_truncate(const char *path, off_t length) { + ramfs_file_t file; + int result; + + if ((result = ramfs_file_open(&fs, &file, path, RAMFS_O_RDWR)) != RAMFS_ERR_OK) { + errno = ramfs_to_errno(result); + return -1; + } + + if ((result = ramfs_file_truncate(&fs, &file, length)) != RAMFS_ERR_OK) { + errno = ramfs_to_errno(result); + return -1; + } + + result = ramfs_file_close(&fs, &file); + if (result < 0) { + errno = ramfs_to_errno(result); + return -1; + } + + return 0; +} + +int vfs_ramfs_mount(const char *target) { + esp_vfs_t vfs = { + .flags = ESP_VFS_FLAG_DEFAULT, + .write = &vfs_ramfs_write, + .open = &vfs_ramfs_open, + .fstat = &vfs_ramfs_fstat, + .close = &vfs_ramfs_close, + .read = &vfs_ramfs_read, + .lseek = &vfs_ramfs_lseek, + .stat = &vfs_ramfs_stat, + .link = NULL, + .unlink = &vfs_ramfs_unlink, + .rename = &vfs_ramfs_rename, + .mkdir = &vfs_ramfs_mkdir, + .opendir = &vfs_ramfs_opendir, + .readdir = &vfs_ramfs_readdir, + .closedir = &vfs_ramfs_closedir, + .rmdir = &vfs_ramfs_rmdir, + .fsync = &vfs_ramfs_fsync, + .access = &vfs_ramfs_access, + .telldir = &vfs_ramfs_telldir, + .truncate = &vfs_ramfs_truncate, + .ftruncate = &vfs_ramfs_ftruncate, + }; + + int res; + ramfs_config_t config; + + config.size = CONFIG_LUA_RTOS_RAM_FS_SIZE; + config.block_size = CONFIG_LUA_RTOS_RAM_FS_BLOCK_SIZE; + + syslog(LOG_INFO, "ramfs size %d Kb, block size %d bytes", config.size / 1024, config.block_size); + + if ((res = ramfs_mount(&fs, &config)) == RAMFS_ERR_OK) { + lstinit(&files, 0, LIST_DEFAULT); + + // Register the file system + ESP_ERROR_CHECK(esp_vfs_register("/ramfs", &vfs, NULL)); + + syslog(LOG_INFO, "ramfs mounted on %s", target); + + return 0; + } else { + syslog(LOG_INFO, "ramfs mount error"); + } + + return -1; +} + +int vfs_ramfs_umount(const char *target) { + ramfs_umount(&fs); + esp_vfs_unregister("/ramfs"); + + syslog(LOG_INFO, "ramfs unmounted"); + + return 0; +} + +int vfs_ramfs_format(const char *target) { + vfs_ramfs_umount(target); + vfs_ramfs_mount(target); + + return 0; +} + +int vfs_ramfs_fsstat(const char *target, u32_t *total, u32_t *used) { + + if (total) { + *total = fs.size; + } + + if (used) { + *used = fs.current_size; + } + + return 0; +} + +#endif |
