2018-05-03 17:17:22 +05:30
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Intel Corporation
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <errno.h>
|
2022-05-06 11:23:05 +02:00
|
|
|
#include <zephyr/kernel.h>
|
2018-05-18 12:17:07 -07:00
|
|
|
#include <limits.h>
|
2022-05-06 11:23:05 +02:00
|
|
|
#include <zephyr/posix/unistd.h>
|
|
|
|
#include <zephyr/posix/dirent.h>
|
2018-05-18 12:17:07 -07:00
|
|
|
#include <string.h>
|
2022-05-06 11:23:05 +02:00
|
|
|
#include <zephyr/sys/fdtable.h>
|
2022-11-16 17:02:02 -05:00
|
|
|
#include <zephyr/posix/sys/stat.h>
|
2022-11-16 17:04:17 -05:00
|
|
|
#include <zephyr/posix/fcntl.h>
|
2022-05-06 11:23:05 +02:00
|
|
|
#include <zephyr/fs/fs.h>
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2020-03-12 17:16:00 +02:00
|
|
|
BUILD_ASSERT(PATH_MAX >= MAX_FILE_NAME, "PATH_MAX is less than MAX_FILE_NAME");
|
2018-05-29 10:49:48 +05:30
|
|
|
|
2018-05-03 17:17:22 +05:30
|
|
|
struct posix_fs_desc {
|
2018-10-08 14:01:46 +03:00
|
|
|
union {
|
|
|
|
struct fs_file_t file;
|
2023-06-15 15:38:36 +02:00
|
|
|
struct fs_dir_t dir;
|
2018-10-08 14:01:46 +03:00
|
|
|
};
|
2018-05-03 17:17:22 +05:30
|
|
|
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;
|
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
static struct fd_op_vtable fs_fd_op_vtable;
|
|
|
|
|
|
|
|
static struct posix_fs_desc *posix_fs_alloc_obj(bool is_dir)
|
2018-05-03 17:17:22 +05:30
|
|
|
{
|
2018-10-08 14:01:46 +03:00
|
|
|
int i;
|
|
|
|
struct posix_fs_desc *ptr = NULL;
|
2018-05-03 17:17:22 +05:30
|
|
|
unsigned int key = irq_lock();
|
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
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;
|
2018-05-03 17:17:22 +05:30
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
irq_unlock(key);
|
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
return ptr;
|
2018-05-03 17:17:22 +05:30
|
|
|
}
|
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
static inline void posix_fs_free_obj(struct posix_fs_desc *ptr)
|
2018-05-03 17:17:22 +05:30
|
|
|
{
|
2018-10-08 14:01:46 +03:00
|
|
|
ptr->used = false;
|
2018-05-03 17:17:22 +05:30
|
|
|
}
|
|
|
|
|
2020-06-19 14:41:34 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-05-03 17:17:22 +05:30
|
|
|
/**
|
|
|
|
* @brief Open a file.
|
|
|
|
*
|
|
|
|
* See IEEE 1003.1
|
|
|
|
*/
|
2020-07-03 11:18:02 +00:00
|
|
|
int open(const char *name, int flags, ...)
|
2018-05-03 17:17:22 +05:30
|
|
|
{
|
|
|
|
int rc, fd;
|
2018-10-08 14:01:46 +03:00
|
|
|
struct posix_fs_desc *ptr = NULL;
|
2020-06-19 14:41:34 +00:00
|
|
|
int zmode = posix_mode_to_zephyr(flags);
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2020-06-19 14:41:34 +00:00
|
|
|
if (zmode < 0) {
|
|
|
|
return zmode;
|
|
|
|
}
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
fd = z_reserve_fd();
|
|
|
|
if (fd < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = posix_fs_alloc_obj(false);
|
|
|
|
if (ptr == NULL) {
|
|
|
|
z_free_fd(fd);
|
|
|
|
errno = EMFILE;
|
2018-05-03 17:17:22 +05:30
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-01-27 13:49:05 +00:00
|
|
|
fs_file_t_init(&ptr->file);
|
2018-10-08 14:01:46 +03:00
|
|
|
|
2020-06-19 14:41:34 +00:00
|
|
|
rc = fs_open(&ptr->file, name, zmode);
|
|
|
|
|
2018-05-03 17:17:22 +05:30
|
|
|
if (rc < 0) {
|
2018-10-08 14:01:46 +03:00
|
|
|
posix_fs_free_obj(ptr);
|
|
|
|
z_free_fd(fd);
|
2018-05-03 17:17:22 +05:30
|
|
|
errno = -rc;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
z_finalize_fd(fd, ptr, &fs_fd_op_vtable);
|
|
|
|
|
2018-05-03 17:17:22 +05:30
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2022-10-28 13:51:06 -04:00
|
|
|
#if !defined(CONFIG_NEWLIB_LIBC) && !defined(CONFIG_PICOLIBC)
|
2020-09-16 09:34:40 +02:00
|
|
|
FUNC_ALIAS(open, _open, int);
|
2022-10-28 13:51:06 -04:00
|
|
|
#endif
|
2020-09-16 09:34:40 +02:00
|
|
|
|
2020-08-11 11:43:51 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-12-11 17:48:47 +03:00
|
|
|
static int fs_ioctl_vmeth(void *obj, unsigned int request, va_list args)
|
2018-05-03 17:17:22 +05:30
|
|
|
{
|
2020-07-03 14:04:39 +00:00
|
|
|
int rc = 0;
|
2018-10-08 14:01:46 +03:00
|
|
|
struct posix_fs_desc *ptr = obj;
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
switch (request) {
|
2024-04-13 13:12:12 +05:30
|
|
|
case ZFD_IOCTL_FSYNC: {
|
|
|
|
rc = fs_sync(&ptr->file);
|
|
|
|
break;
|
|
|
|
}
|
2018-10-08 14:01:46 +03:00
|
|
|
case ZFD_IOCTL_LSEEK: {
|
|
|
|
off_t offset;
|
|
|
|
int whence;
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
offset = va_arg(args, off_t);
|
|
|
|
whence = va_arg(args, int);
|
|
|
|
|
|
|
|
rc = fs_seek(&ptr->file, offset, whence);
|
2020-07-03 14:04:39 +00:00
|
|
|
if (rc == 0) {
|
|
|
|
rc = fs_tell(&ptr->file);
|
|
|
|
}
|
2018-10-08 14:01:46 +03:00
|
|
|
break;
|
|
|
|
}
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
default:
|
|
|
|
errno = EOPNOTSUPP;
|
|
|
|
return -1;
|
|
|
|
}
|
2018-05-03 17:17:22 +05:30
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
errno = -rc;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-07-03 14:04:39 +00:00
|
|
|
return rc;
|
2018-05-03 17:17:22 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Write to a file.
|
|
|
|
*
|
|
|
|
* See IEEE 1003.1
|
|
|
|
*/
|
2018-10-08 14:01:46 +03:00
|
|
|
static ssize_t fs_write_vmeth(void *obj, const void *buffer, size_t count)
|
2018-05-03 17:17:22 +05:30
|
|
|
{
|
|
|
|
ssize_t rc;
|
2018-10-08 14:01:46 +03:00
|
|
|
struct posix_fs_desc *ptr = obj;
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
rc = fs_write(&ptr->file, buffer, count);
|
2018-05-03 17:17:22 +05:30
|
|
|
if (rc < 0) {
|
|
|
|
errno = -rc;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Read from a file.
|
|
|
|
*
|
|
|
|
* See IEEE 1003.1
|
|
|
|
*/
|
2018-10-08 14:01:46 +03:00
|
|
|
static ssize_t fs_read_vmeth(void *obj, void *buffer, size_t count)
|
2018-05-03 17:17:22 +05:30
|
|
|
{
|
|
|
|
ssize_t rc;
|
2018-10-08 14:01:46 +03:00
|
|
|
struct posix_fs_desc *ptr = obj;
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
rc = fs_read(&ptr->file, buffer, count);
|
2018-05-03 17:17:22 +05:30
|
|
|
if (rc < 0) {
|
|
|
|
errno = -rc;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
static struct fd_op_vtable fs_fd_op_vtable = {
|
|
|
|
.read = fs_read_vmeth,
|
|
|
|
.write = fs_write_vmeth,
|
2020-08-11 11:43:51 +03:00
|
|
|
.close = fs_close_vmeth,
|
2018-10-08 14:01:46 +03:00
|
|
|
.ioctl = fs_ioctl_vmeth,
|
|
|
|
};
|
2018-05-03 17:17:22 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Open a directory stream.
|
|
|
|
*
|
|
|
|
* See IEEE 1003.1
|
|
|
|
*/
|
|
|
|
DIR *opendir(const char *dirname)
|
|
|
|
{
|
2018-10-08 14:01:46 +03:00
|
|
|
int rc;
|
|
|
|
struct posix_fs_desc *ptr;
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
ptr = posix_fs_alloc_obj(true);
|
|
|
|
if (ptr == NULL) {
|
2018-05-03 17:17:22 +05:30
|
|
|
errno = EMFILE;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-02-03 12:18:05 +01:00
|
|
|
fs_dir_t_init(&ptr->dir);
|
2018-10-08 14:01:46 +03:00
|
|
|
|
|
|
|
rc = fs_opendir(&ptr->dir, dirname);
|
2018-05-03 17:17:22 +05:30
|
|
|
if (rc < 0) {
|
2018-10-08 14:01:46 +03:00
|
|
|
posix_fs_free_obj(ptr);
|
2018-05-03 17:17:22 +05:30
|
|
|
errno = -rc;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Close a directory stream.
|
|
|
|
*
|
|
|
|
* See IEEE 1003.1
|
|
|
|
*/
|
|
|
|
int closedir(DIR *dirp)
|
|
|
|
{
|
|
|
|
int rc;
|
2018-10-08 14:01:46 +03:00
|
|
|
struct posix_fs_desc *ptr = dirp;
|
2018-05-03 17:17:22 +05:30
|
|
|
|
|
|
|
if (dirp == NULL) {
|
|
|
|
errno = EBADF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
rc = fs_closedir(&ptr->dir);
|
2018-05-03 17:17:22 +05:30
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
posix_fs_free_obj(ptr);
|
2018-05-03 17:17:22 +05:30
|
|
|
|
|
|
|
if (rc < 0) {
|
|
|
|
errno = -rc;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Read a directory.
|
|
|
|
*
|
|
|
|
* See IEEE 1003.1
|
|
|
|
*/
|
|
|
|
struct dirent *readdir(DIR *dirp)
|
|
|
|
{
|
|
|
|
int rc;
|
2018-10-08 14:01:46 +03:00
|
|
|
struct posix_fs_desc *ptr = dirp;
|
2018-05-03 17:17:22 +05:30
|
|
|
|
|
|
|
if (dirp == NULL) {
|
|
|
|
errno = EBADF;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-10-08 14:01:46 +03:00
|
|
|
rc = fs_readdir(&ptr->dir, &fdirent);
|
2018-05-03 17:17:22 +05:30
|
|
|
if (rc < 0) {
|
|
|
|
errno = -rc;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-01-03 12:44:16 +01:00
|
|
|
if (fdirent.name[0] == 0) {
|
|
|
|
/* assume end-of-dir, leave errno untouched */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-05-03 17:17:22 +05:30
|
|
|
rc = strlen(fdirent.name);
|
2019-03-21 22:44:21 -07:00
|
|
|
rc = (rc < MAX_FILE_NAME) ? rc : (MAX_FILE_NAME - 1);
|
2018-12-18 12:15:54 -08:00
|
|
|
(void)memcpy(pdirent.d_name, fdirent.name, rc);
|
2018-05-29 10:49:48 +05:30
|
|
|
|
|
|
|
/* Make sure the name is NULL terminated */
|
2018-06-08 12:11:13 -07:00
|
|
|
pdirent.d_name[rc] = '\0';
|
2018-05-03 17:17:22 +05:30
|
|
|
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;
|
2023-06-15 15:38:36 +02:00
|
|
|
struct fs_statvfs stat_vfs;
|
|
|
|
struct fs_dirent stat_file;
|
2018-05-03 17:17:22 +05:30
|
|
|
|
|
|
|
if (buf == NULL) {
|
|
|
|
errno = EBADF;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-06-15 15:38:36 +02:00
|
|
|
rc = fs_statvfs(path, &stat_vfs);
|
2018-05-03 17:17:22 +05:30
|
|
|
if (rc < 0) {
|
|
|
|
errno = -rc;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2023-06-15 15:38:36 +02:00
|
|
|
rc = fs_stat(path, &stat_file);
|
|
|
|
if (rc < 0) {
|
|
|
|
errno = -rc;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(buf, 0, sizeof(struct stat));
|
|
|
|
|
|
|
|
switch (stat_file.type) {
|
|
|
|
case FS_DIR_ENTRY_FILE:
|
|
|
|
buf->st_mode = S_IFREG;
|
|
|
|
break;
|
|
|
|
case FS_DIR_ENTRY_DIR:
|
|
|
|
buf->st_mode = S_IFDIR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
errno = EIO;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
buf->st_size = stat_file.size;
|
|
|
|
buf->st_blksize = stat_vfs.f_bsize;
|
|
|
|
/*
|
|
|
|
* This is a best effort guess, as this information is not provided
|
|
|
|
* by the fs_stat function.
|
|
|
|
*/
|
|
|
|
buf->st_blocks = (stat_file.size + stat_vfs.f_bsize - 1) / stat_vfs.f_bsize;
|
|
|
|
|
2018-05-03 17:17:22 +05:30
|
|
|
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;
|
|
|
|
}
|