|  | /* | 
|  | * Copyright (c) 2018 Intel Corporation | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <errno.h> | 
|  | #include <kernel.h> | 
|  | #include <limits.h> | 
|  | #include <posix/unistd.h> | 
|  | #include <posix/dirent.h> | 
|  | #include <string.h> | 
|  | #include <sys/fdtable.h> | 
|  | #include <sys/stat.h> | 
|  | #include <fcntl.h> | 
|  | #include <fs/fs.h> | 
|  |  | 
|  | BUILD_ASSERT(PATH_MAX >= MAX_FILE_NAME, "PATH_MAX is less than MAX_FILE_NAME"); | 
|  |  | 
|  | struct posix_fs_desc { | 
|  | union { | 
|  | struct fs_file_t file; | 
|  | struct fs_dir_t	dir; | 
|  | }; | 
|  | 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 struct fd_op_vtable fs_fd_op_vtable; | 
|  |  | 
|  | static struct posix_fs_desc *posix_fs_alloc_obj(bool is_dir) | 
|  | { | 
|  | int i; | 
|  | struct posix_fs_desc *ptr = NULL; | 
|  | unsigned int key = irq_lock(); | 
|  |  | 
|  | for (i = 0; i < CONFIG_POSIX_MAX_OPEN_FILES; i++) { | 
|  | if (desc_array[i].used == false) { | 
|  | ptr = &desc_array[i]; | 
|  | ptr->used = true; | 
|  | ptr->is_dir = is_dir; | 
|  | break; | 
|  | } | 
|  | } | 
|  | irq_unlock(key); | 
|  |  | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | static inline void posix_fs_free_obj(struct posix_fs_desc *ptr) | 
|  | { | 
|  | ptr->used = false; | 
|  | } | 
|  |  | 
|  | static int posix_mode_to_zephyr(int mf) | 
|  | { | 
|  | int mode = (mf & O_CREAT) ? FS_O_CREATE : 0; | 
|  |  | 
|  | mode |= (mf & O_APPEND) ? FS_O_APPEND : 0; | 
|  |  | 
|  | switch (mf & O_ACCMODE) { | 
|  | case O_RDONLY: | 
|  | mode |= FS_O_READ; | 
|  | break; | 
|  | case O_WRONLY: | 
|  | mode |= FS_O_WRITE; | 
|  | break; | 
|  | case O_RDWR: | 
|  | mode |= FS_O_RDWR; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | return mode; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Open a file. | 
|  | * | 
|  | * See IEEE 1003.1 | 
|  | */ | 
|  | int open(const char *name, int flags, ...) | 
|  | { | 
|  | int rc, fd; | 
|  | struct posix_fs_desc *ptr = NULL; | 
|  | int zmode = posix_mode_to_zephyr(flags); | 
|  |  | 
|  | if (zmode < 0) { | 
|  | return zmode; | 
|  | } | 
|  |  | 
|  | fd = z_reserve_fd(); | 
|  | if (fd < 0) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | ptr = posix_fs_alloc_obj(false); | 
|  | if (ptr == NULL) { | 
|  | z_free_fd(fd); | 
|  | errno = EMFILE; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | fs_file_t_init(&ptr->file); | 
|  |  | 
|  | rc = fs_open(&ptr->file, name, zmode); | 
|  |  | 
|  | if (rc < 0) { | 
|  | posix_fs_free_obj(ptr); | 
|  | z_free_fd(fd); | 
|  | errno = -rc; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | z_finalize_fd(fd, ptr, &fs_fd_op_vtable); | 
|  |  | 
|  | return fd; | 
|  | } | 
|  |  | 
|  | FUNC_ALIAS(open, _open, int); | 
|  |  | 
|  | static int fs_close_vmeth(void *obj) | 
|  | { | 
|  | struct posix_fs_desc *ptr = obj; | 
|  | int rc; | 
|  |  | 
|  | rc = fs_close(&ptr->file); | 
|  | posix_fs_free_obj(ptr); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static int fs_ioctl_vmeth(void *obj, unsigned int request, va_list args) | 
|  | { | 
|  | int rc = 0; | 
|  | struct posix_fs_desc *ptr = obj; | 
|  |  | 
|  | switch (request) { | 
|  | case ZFD_IOCTL_LSEEK: { | 
|  | off_t offset; | 
|  | int whence; | 
|  |  | 
|  | offset = va_arg(args, off_t); | 
|  | whence = va_arg(args, int); | 
|  |  | 
|  | rc = fs_seek(&ptr->file, offset, whence); | 
|  | if (rc == 0) { | 
|  | rc = fs_tell(&ptr->file); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | errno = EOPNOTSUPP; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (rc < 0) { | 
|  | errno = -rc; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Write to a file. | 
|  | * | 
|  | * See IEEE 1003.1 | 
|  | */ | 
|  | static ssize_t fs_write_vmeth(void *obj, const void *buffer, size_t count) | 
|  | { | 
|  | ssize_t rc; | 
|  | struct posix_fs_desc *ptr = obj; | 
|  |  | 
|  | rc = fs_write(&ptr->file, buffer, count); | 
|  | if (rc < 0) { | 
|  | errno = -rc; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Read from a file. | 
|  | * | 
|  | * See IEEE 1003.1 | 
|  | */ | 
|  | static ssize_t fs_read_vmeth(void *obj, void *buffer, size_t count) | 
|  | { | 
|  | ssize_t rc; | 
|  | struct posix_fs_desc *ptr = obj; | 
|  |  | 
|  | rc = fs_read(&ptr->file, buffer, count); | 
|  | if (rc < 0) { | 
|  | errno = -rc; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static struct fd_op_vtable fs_fd_op_vtable = { | 
|  | .read = fs_read_vmeth, | 
|  | .write = fs_write_vmeth, | 
|  | .close = fs_close_vmeth, | 
|  | .ioctl = fs_ioctl_vmeth, | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * @brief Open a directory stream. | 
|  | * | 
|  | * See IEEE 1003.1 | 
|  | */ | 
|  | DIR *opendir(const char *dirname) | 
|  | { | 
|  | int rc; | 
|  | struct posix_fs_desc *ptr; | 
|  |  | 
|  | ptr = posix_fs_alloc_obj(true); | 
|  | if (ptr == NULL) { | 
|  | errno = EMFILE; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | fs_dir_t_init(&ptr->dir); | 
|  |  | 
|  | rc = fs_opendir(&ptr->dir, dirname); | 
|  | if (rc < 0) { | 
|  | posix_fs_free_obj(ptr); | 
|  | errno = -rc; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return ptr; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Close a directory stream. | 
|  | * | 
|  | * See IEEE 1003.1 | 
|  | */ | 
|  | int closedir(DIR *dirp) | 
|  | { | 
|  | int rc; | 
|  | struct posix_fs_desc *ptr = dirp; | 
|  |  | 
|  | if (dirp == NULL) { | 
|  | errno = EBADF; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | rc = fs_closedir(&ptr->dir); | 
|  |  | 
|  | posix_fs_free_obj(ptr); | 
|  |  | 
|  | if (rc < 0) { | 
|  | errno = -rc; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @brief Read a directory. | 
|  | * | 
|  | * See IEEE 1003.1 | 
|  | */ | 
|  | struct dirent *readdir(DIR *dirp) | 
|  | { | 
|  | int rc; | 
|  | struct posix_fs_desc *ptr = dirp; | 
|  |  | 
|  | if (dirp == NULL) { | 
|  | errno = EBADF; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | rc = fs_readdir(&ptr->dir, &fdirent); | 
|  | if (rc < 0) { | 
|  | errno = -rc; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | rc = strlen(fdirent.name); | 
|  | rc = (rc < MAX_FILE_NAME) ? rc : (MAX_FILE_NAME - 1); | 
|  | (void)memcpy(pdirent.d_name, fdirent.name, rc); | 
|  |  | 
|  | /* Make sure the name is NULL terminated */ | 
|  | pdirent.d_name[rc] = '\0'; | 
|  | 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; | 
|  | } |