| /* |
| * Copyright (c) 2018 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <errno.h> |
| #include <kernel.h> |
| #include <limits.h> |
| #include <posix/pthread.h> |
| #include <posix/unistd.h> |
| #include <string.h> |
| |
| 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; |
| } |