From eb0aaca64d017fad306b040b871e3c0d1b8d6c71 Mon Sep 17 00:00:00 2001 From: Ramakrishna Pallala Date: Thu, 3 May 2018 17:17:22 +0530 Subject: [PATCH] lib: posix: Add Posix Style File System API support Add IEEE 1003.1 Posix Style file system API support. These API's will internally use corresponding Zephyr File System API's. Signed-off-by: Ramakrishna Pallala --- arch/posix/include/posix_cheats.h | 16 ++ include/fs.h | 18 ++ include/posix/sys/stat.h | 57 +++++ include/posix/sys/types.h | 2 + include/posix/unistd.h | 37 ++- lib/libc/newlib/libc-hooks.c | 41 ++-- lib/posix/CMakeLists.txt | 1 + lib/posix/Kconfig | 19 ++ lib/posix/fs.c | 378 ++++++++++++++++++++++++++++++ 9 files changed, 550 insertions(+), 19 deletions(-) create mode 100644 include/posix/sys/stat.h create mode 100644 lib/posix/fs.c diff --git a/arch/posix/include/posix_cheats.h b/arch/posix/include/posix_cheats.h index a4da1aaf8bb..d44d5f16284 100644 --- a/arch/posix/include/posix_cheats.h +++ b/arch/posix/include/posix_cheats.h @@ -45,6 +45,8 @@ #define mqueue_desc zap_mqueue_desc #define mqd_t zap_mqd_t #define mq_attr zap_mq_attr +#define dirent zap_dirent +#define DIR zap_DIR /* Condition variables */ @@ -163,6 +165,20 @@ #define mq_timedreceive(...) zap_mq_timedreceive(__VA_ARGS__) #define mq_timedsend(...) zap_mq_timedsend(__VA_ARGS__) +/* File system */ +#define open zap_open +#define close zap_close +#define write zap_write +#define read zap_read +#define lseek zap_lseek +#define opendir zap_opendir +#define closedir zap_closedir +#define readdir zap_readdir +#define rename zap_rename +#define unlink zap_unlink +#define stat zap_stat +#define mkdir zap_mkdir + #endif /* CONFIG_PTHREAD_IPC */ #endif /* CONFIG_ARCH_POSIX */ diff --git a/include/fs.h b/include/fs.h index 381a4ffa859..bbb850baf6c 100644 --- a/include/fs.h +++ b/include/fs.h @@ -7,7 +7,25 @@ #ifndef _FS_H_ #define _FS_H_ +#ifdef CONFIG_ARCH_POSIX +#ifndef __ssize_t_defined +typedef __SIZE_TYPE__ ssize_t; +#define __ssize_t_defined +#endif + +#ifndef __off_t_defined +#ifndef __USE_FILE_OFFSET64 +typedef long int off_t; +#else +typedef long long int off_t; +#endif +#define __off_t_defined +#endif + +#else #include +#endif + #include #include diff --git a/include/posix/sys/stat.h b/include/posix/sys/stat.h new file mode 100644 index 00000000000..7a594707d51 --- /dev/null +++ b/include/posix/sys/stat.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __POSIX_STAT_H__ +#define __POSIX_STAT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_PTHREAD_IPC +#include + +#ifdef CONFIG_POSIX_FS +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +/* File open modes */ +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ + +struct stat { + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; +}; + +#endif /* CONFIG_POSIX_FS */ + +#endif /* CONFIG_PTHREAD_IPC */ + +#ifdef __cplusplus +} +#endif + +#endif /* __POSIX_STAT_H__ */ diff --git a/include/posix/sys/types.h b/include/posix/sys/types.h index a6afb41b34a..dca7df39304 100644 --- a/include/posix/sys/types.h +++ b/include/posix/sys/types.h @@ -11,7 +11,9 @@ extern "C" { #endif +#ifndef CONFIG_ARCH_POSIX #include_next +#endif #ifdef CONFIG_PTHREAD_IPC #include diff --git a/include/posix/unistd.h b/include/posix/unistd.h index 91c03753319..4fd9d4c8d55 100644 --- a/include/posix/unistd.h +++ b/include/posix/unistd.h @@ -11,11 +11,46 @@ extern "C" { #endif #include "sys/types.h" +#include "sys/stat.h" + +#ifdef CONFIG_POSIX_FS +#include + +#undef PATH_MAX +#define PATH_MAX 256 + +typedef struct fs_dir_t DIR; +typedef unsigned int mode_t; + +struct dirent { + unsigned int d_ino; + char d_name[PATH_MAX + 1]; +}; + +/* File related operations */ +extern int open(const char *name, int flags); +extern int close(int file); +extern ssize_t write(int file, char *buffer, unsigned int count); +extern ssize_t read(int file, char *buffer, unsigned int count); +extern int lseek(int file, int offset, int whence); + +/* Directory related operations */ +extern DIR *opendir(const char *dirname); +extern int closedir(DIR *dirp); +extern struct dirent *readdir(DIR *dirp); + +/* File System related operations */ +extern int rename(const char *old, const char *newp); +extern int unlink(const char *path); +extern int stat(const char *path, struct stat *buf); +extern int mkdir(const char *path, mode_t mode); +#endif unsigned sleep(unsigned int seconds); int usleep(useconds_t useconds); -#endif #ifdef __cplusplus } +#endif + #endif /* __POSIX_UNISTD_H__ */ diff --git a/lib/libc/newlib/libc-hooks.c b/lib/libc/newlib/libc-hooks.c index 0edf4492a38..0844d8bf3d4 100644 --- a/lib/libc/newlib/libc-hooks.c +++ b/lib/libc/newlib/libc-hooks.c @@ -75,6 +75,7 @@ void __stdin_hook_install(unsigned char (*hook)(void)) _stdin_hook = hook; } +#ifndef CONFIG_POSIX_FS int _read(int fd, char *buf, int nbytes) { int i = 0; @@ -104,6 +105,28 @@ int _write(int fd, char *buf, int nbytes) } FUNC_ALIAS(_write, write, int); +int _open(const char *name, int mode) +{ + return -1; +} +FUNC_ALIAS(_open, open, int); + +int _close(int file) +{ + return -1; +} +FUNC_ALIAS(_close, close, int); + +int _lseek(int file, int ptr, int dir) +{ + return 0; +} +FUNC_ALIAS(_lseek, lseek, int); +#else +extern ssize_t write(int file, char *buffer, unsigned int count); +#define _write write +#endif + int _isatty(int file) { return 1; @@ -137,24 +160,6 @@ void _exit(int status) } } -int _open(const char *name, int mode) -{ - return -1; -} -FUNC_ALIAS(_open, open, int); - -int _close(int file) -{ - return -1; -} -FUNC_ALIAS(_close, close, int); - -int _lseek(int file, int ptr, int dir) -{ - return 0; -} -FUNC_ALIAS(_lseek, lseek, int); - void *_sbrk(int count) { void *ptr = heap_base + heap_sz; diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index db478ebf4eb..ec863720280 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -16,6 +16,7 @@ zephyr_library_sources(timer.c) zephyr_library_sources(pthread_rwlock.c) zephyr_library_sources(semaphore.c) zephyr_library_sources_ifdef(CONFIG_POSIX_MQUEUE mqueue.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c) zephyr_library_link_libraries(PTHREAD) target_link_libraries(PTHREAD INTERFACE zephyr_interface) diff --git a/lib/posix/Kconfig b/lib/posix/Kconfig index be484fd205d..19444a7fcc3 100644 --- a/lib/posix/Kconfig +++ b/lib/posix/Kconfig @@ -70,4 +70,23 @@ config MQUEUE_NAMELEN_MAX Mention length of message queue name in number of characters. endif + +if FILE_SYSTEM +config POSIX_FS + bool + prompt "Enable POSIX file system API support" + default n + help + This enabled POSIX style file system related APIs. + +if POSIX_FS +config POSIX_MAX_OPEN_FILES + int + prompt "Maximum number of open file descriptors" + default 16 + help + Mention maximum number of open file descriptors. +endif +endif + endif diff --git a/lib/posix/fs.c b/lib/posix/fs.c new file mode 100644 index 00000000000..cc90f3cb231 --- /dev/null +++ b/lib/posix/fs.c @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + + +union file_desc { + struct fs_file_t file; + struct fs_dir_t dir; +}; + +struct posix_fs_desc { + union file_desc desc; + bool is_dir; + bool used; +}; + +static struct posix_fs_desc desc_array[CONFIG_POSIX_MAX_OPEN_FILES]; + +static struct fs_dirent fdirent; +static struct dirent pdirent; + +static int posix_fs_alloc_fd(union file_desc **ptr, bool is_dir) +{ + int fd; + unsigned int key = irq_lock(); + + for (fd = 0; fd < CONFIG_POSIX_MAX_OPEN_FILES; fd++) { + if (desc_array[fd].used == false) { + *ptr = &desc_array[fd].desc; + desc_array[fd].used = true; + desc_array[fd].is_dir = is_dir; + break; + } + } + irq_unlock(key); + + if (fd >= CONFIG_POSIX_MAX_OPEN_FILES) { + return -1; + } + + return fd; +} + +static int posix_fs_get_ptr(int fd, union file_desc **ptr, bool is_dir) +{ + int rc = 0; + unsigned int key; + + if (fd < 0 || fd >= CONFIG_POSIX_MAX_OPEN_FILES) { + return -1; + } + + key = irq_lock(); + + if ((desc_array[fd].used == true) && + (desc_array[fd].is_dir == is_dir)) { + *ptr = &desc_array[fd].desc; + } else { + rc = -1; + } + irq_unlock(key); + + return rc; +} + +static inline void posix_fs_free_ptr(struct posix_fs_desc *ptr) +{ + struct posix_fs_desc *desc = ptr; + unsigned int key = irq_lock(); + + desc->used = false; + desc->is_dir = false; + irq_unlock(key); +} + +static inline void posix_fs_free_fd(int fd) +{ + posix_fs_free_ptr(&desc_array[fd]); +} + +/** + * @brief Open a file. + * + * See IEEE 1003.1 + */ +int open(const char *name, int flags) +{ + int rc, fd; + struct fs_file_t *ptr = NULL; + + ARG_UNUSED(flags); + + fd = posix_fs_alloc_fd((union file_desc **)&ptr, false); + if ((fd < 0) || (ptr == NULL)) { + errno = ENFILE; + return -1; + } + memset(ptr, 0, sizeof(struct fs_file_t)); + + rc = fs_open(ptr, name); + if (rc < 0) { + posix_fs_free_fd(fd); + errno = -rc; + return -1; + } + + return fd; +} + +/** + * @brief Close a file descriptor. + * + * See IEEE 1003.1 + */ +int close(int fd) +{ + int rc; + struct fs_file_t *ptr = NULL; + + if (posix_fs_get_ptr(fd, (union file_desc **)&ptr, false)) { + errno = EBADF; + return -1; + } + + rc = fs_close(ptr); + + /* Free file ptr memory */ + posix_fs_free_fd(fd); + + if (rc < 0) { + errno = -rc; + return -1; + } + + return 0; +} + +/** + * @brief Write to a file. + * + * See IEEE 1003.1 + */ +ssize_t write(int fd, char *buffer, unsigned int count) +{ + ssize_t rc; + struct fs_file_t *ptr = NULL; + + if (posix_fs_get_ptr(fd, (union file_desc **)&ptr, false)) { + errno = EBADF; + return -1; + } + + rc = fs_write(ptr, buffer, count); + if (rc < 0) { + errno = -rc; + return -1; + } + + return rc; +} + +/** + * @brief Read from a file. + * + * See IEEE 1003.1 + */ +ssize_t read(int fd, char *buffer, unsigned int count) +{ + ssize_t rc; + struct fs_file_t *ptr = NULL; + + if (posix_fs_get_ptr(fd, (union file_desc **)&ptr, false)) { + errno = EBADF; + return -1; + } + + rc = fs_read(ptr, buffer, count); + if (rc < 0) { + errno = -rc; + return -1; + } + + return rc; +} + +/** + * @brief Move read/write file offset. + * + * See IEEE 1003.1 + */ +int lseek(int fd, int offset, int whence) +{ + int rc; + struct fs_file_t *ptr = NULL; + + if (posix_fs_get_ptr(fd, (union file_desc **)&ptr, false)) { + errno = EBADF; + return -1; + } + + rc = fs_seek(ptr, offset, whence); + if (rc < 0) { + errno = -rc; + return -1; + } + + return 0; +} + +/** + * @brief Open a directory stream. + * + * See IEEE 1003.1 + */ +DIR *opendir(const char *dirname) +{ + int rc, fd; + struct fs_dir_t *ptr = NULL; + + fd = posix_fs_alloc_fd((union file_desc **)&ptr, true); + if ((fd < 0) || (ptr == NULL)) { + errno = EMFILE; + return NULL; + } + memset(ptr, 0, sizeof(struct fs_dir_t)); + + rc = fs_opendir(ptr, dirname); + if (rc < 0) { + posix_fs_free_fd(fd); + errno = -rc; + return NULL; + } + + return ptr; +} + +/** + * @brief Close a directory stream. + * + * See IEEE 1003.1 + */ +int closedir(DIR *dirp) +{ + int rc; + + if (dirp == NULL) { + errno = EBADF; + return -1; + } + + rc = fs_closedir(dirp); + + /* Free file ptr memory */ + posix_fs_free_ptr((struct posix_fs_desc *)dirp); + + if (rc < 0) { + errno = -rc; + return -1; + } + + return 0; +} + +/** + * @brief Read a directory. + * + * See IEEE 1003.1 + */ +struct dirent *readdir(DIR *dirp) +{ + int rc; + + if (dirp == NULL) { + errno = EBADF; + return NULL; + } + + rc = fs_readdir(dirp, &fdirent); + if (rc < 0) { + errno = -rc; + return NULL; + } + + rc = strlen(fdirent.name); + memcpy(pdirent.d_name, fdirent.name, + rc <= PATH_MAX ? rc : PATH_MAX); + return &pdirent; +} + +/** + * @brief Rename a file. + * + * See IEEE 1003.1 + */ +int rename(const char *old, const char *new) +{ + int rc; + + rc = fs_rename(old, new); + if (rc < 0) { + errno = -rc; + return -1; + } + + return 0; +} + +/** + * @brief Remove a directory entry. + * + * See IEEE 1003.1 + */ +int unlink(const char *path) +{ + int rc; + + rc = fs_unlink(path); + if (rc < 0) { + errno = -rc; + return -1; + } + return 0; +} + +/** + * @brief Get file status. + * + * See IEEE 1003.1 + */ +int stat(const char *path, struct stat *buf) +{ + int rc; + struct fs_statvfs stat; + + if (buf == NULL) { + errno = EBADF; + return -1; + } + + rc = fs_statvfs(path, &stat); + if (rc < 0) { + errno = -rc; + return -1; + } + + buf->st_size = stat.f_bsize * stat.f_blocks; + buf->st_blksize = stat.f_bsize; + buf->st_blocks = stat.f_blocks; + return 0; +} + +/** + * @brief Make a directory. + * + * See IEEE 1003.1 + */ +int mkdir(const char *path, mode_t mode) +{ + int rc; + + ARG_UNUSED(mode); + + rc = fs_mkdir(path); + if (rc < 0) { + errno = -rc; + return -1; + } + + return 0; +}