1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 23:12:45 +01:00
RIOT/cpu/native/fs/native_fs.c
2023-04-26 00:53:14 +02:00

292 lines
6.1 KiB
C

/*
* Copyright (C) 2023 ML!PA Consulting GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_fs_native
* @{
*
* @file
* @brief native integration with vfs
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*
* @}
*/
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "mutex.h"
#include "native_internal.h"
#include "fs/native_fs.h"
#include "vfs.h"
#define ENABLE_DEBUG 0
#include <debug.h>
/**
* @brief Assign each native instance a sub-sirectory based on `_native_id`
*/
#ifndef CONFIG_NATIVE_ISOLATE_FS
#define CONFIG_NATIVE_ISOLATE_FS 0
#endif
/* Not using static inline functions here because they are also assigned to. */
#define FD(filep) filp->private_data.value
#define DIRP(dirp) dirp->private_data.ptr
/* Reentrancy guard required by the various static locals of the implementation */
static mutex_t _lock;
static void _do_prefix(vfs_mount_t *mountp, const char *name, char *buffer, size_t len)
{
const native_desc_t *fs_desc = mountp->private_data;
size_t res;
assert(len > strlen(fs_desc->hostpath));
if (CONFIG_NATIVE_ISOLATE_FS) {
res = snprintf(buffer, len, "%s/%u%s", fs_desc->hostpath, _native_id, name);
} else {
res = snprintf(buffer, len, "%s%s", fs_desc->hostpath, name);
}
#ifdef NDEBUG
if (res > len) {
puts("fs_native: path larger than PATH_MAX");
exit(ENOBUFS);
}
#else
assert(res <= len);
#endif
}
static char *_prefix_path(vfs_mount_t *mountp, const char *name)
{
static char buffer[PATH_MAX];
_do_prefix(mountp, name, buffer, sizeof(buffer));
return buffer;
}
static int _mount(vfs_mount_t *mountp)
{
int res;
mutex_lock(&_lock);
/* create common root dir first */
if (CONFIG_NATIVE_ISOLATE_FS) {
char *parent = _prefix_path(mountp, "");
/* remove node specific suffix */
char *end = strrchr(parent, '/');
*end = '\0';
/* Ignoring errors: they're caught by the subsequent real_mkdir */
real_mkdir(parent, 0777);
}
real_mkdir(_prefix_path(mountp, ""), 0777);
res = errno == EEXIST ? 0 : -errno;
mutex_unlock(&_lock);
return res;
}
static int _unmount(vfs_mount_t *mountp)
{
mutex_lock(&_lock);
/* Ignoring errors: directories with any content are left in place. */
real_rmdir(_prefix_path(mountp, ""));
mutex_unlock(&_lock);
return 0;
}
static int _mkdir(vfs_mount_t *mountp, const char *name, mode_t mode)
{
int res = 0;
mutex_lock(&_lock);
if (real_mkdir(_prefix_path(mountp, name), mode) < 0) {
res = -errno;
}
mutex_unlock(&_lock);
return res;
}
static int _rmdir(vfs_mount_t *mountp, const char *name)
{
int res = 0;
mutex_lock(&_lock);
if (real_rmdir(_prefix_path(mountp, name)) < 0) {
res = -errno;
}
mutex_unlock(&_lock);
return res;
}
static int _statvfs(vfs_mount_t *mountp, const char *restrict path, struct statvfs *restrict buf)
{
int res = 0;
mutex_lock(&_lock);
if (real_statvfs(_prefix_path(mountp, path), buf) < 0) {
res = -errno;
}
mutex_unlock(&_lock);
return res;
}
static int _open(vfs_file_t *filp, const char *name, int flags, mode_t mode)
{
int res = 0;
mutex_lock(&_lock);
if ((FD(filep) = real_open(_prefix_path(filp->mp, name), flags, mode)) < 0) {
res = -errno;
}
mutex_unlock(&_lock);
return res;
}
static ssize_t _read(vfs_file_t *filp, void *dest, size_t nbytes)
{
return real_read(FD(filep), dest, nbytes);
}
static ssize_t _write(vfs_file_t *filp, const void *src, size_t nbytes)
{
return real_write(FD(filep), src, nbytes);
}
static off_t _lseek(vfs_file_t *filp, off_t off, int whence)
{
return real_lseek(FD(filep), off, whence);
}
static int _fstat(vfs_file_t *filp, struct stat *buf)
{
return real_fstat(FD(filep), buf);
}
static int _fsync(vfs_file_t *filp)
{
return real_fsync(FD(filep));
}
static int _close(vfs_file_t *filp)
{
return real_close(FD(filep));
}
static int _unlink(vfs_mount_t *mountp, const char *name)
{
int res = 0;
mutex_lock(&_lock);
if (real_unlink(_prefix_path(mountp, name)) < 0) {
res = -errno;
}
mutex_unlock(&_lock);
return res;
}
static int _rename(vfs_mount_t *mountp, const char *from_path, const char *to_path)
{
static char path_a[PATH_MAX];
static char path_b[PATH_MAX];
int res = 0;
mutex_lock(&_lock);
_do_prefix(mountp, from_path, path_a, sizeof(path_a));
_do_prefix(mountp, to_path, path_b, sizeof(path_b));
if (real_rename(path_a, path_b) < 0) {
res = -errno;
}
mutex_unlock(&_lock);
return res;
}
static int _opendir(vfs_DIR *dirp, const char *dirname)
{
int res = 0;
mutex_lock(&_lock);
if ((DIRP(dirp) = real_opendir(_prefix_path(dirp->mp, dirname))) == NULL) {
res = -errno;
}
mutex_unlock(&_lock);
return res;
}
static int _readdir(vfs_DIR *dirp, vfs_dirent_t *entry)
{
struct dirent *dirent = real_readdir(DIRP(dirp));
if (dirent == NULL) {
return 0;
}
entry->d_ino = dirent->d_ino;
strncpy(entry->d_name, (char *)dirent->d_name, sizeof(entry->d_name));
return 1;
}
static int _closedir(vfs_DIR *dirp)
{
return real_closedir(DIRP(dirp));
}
static const vfs_file_system_ops_t native_fs_ops = {
.mount = _mount,
.umount = _unmount,
.unlink = _unlink,
.mkdir = _mkdir,
.rmdir = _rmdir,
.rename = _rename,
.stat = vfs_sysop_stat_from_fstat,
.statvfs = _statvfs,
};
static const vfs_file_ops_t native_file_ops = {
.open = _open,
.close = _close,
.read = _read,
.write = _write,
.lseek = _lseek,
.fstat = _fstat,
.fsync = _fsync,
};
static const vfs_dir_ops_t native_dir_ops = {
.opendir = _opendir,
.readdir = _readdir,
.closedir = _closedir,
};
const vfs_file_system_t native_file_system = {
.fs_op = &native_fs_ops,
.f_op = &native_file_ops,
.d_op = &native_dir_ops,
};