From 3c1454dcdb494957e8ee052b8a63b7e8d641b70c Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 3 Apr 2026 13:26:24 +0200 Subject: [PATCH 1/2] Make the "AddDevice" and "RemoveDevice" more robust against ABI changes --- Makefile | 5 +- include/content_redirection/defines.h | 240 +++++++ .../devoptab_cpp_wrapper.h | 680 ++++++++++++++++++ include/content_redirection/redirection.h | 36 +- source/utils.cpp | 113 ++- 5 files changed, 987 insertions(+), 87 deletions(-) create mode 100644 include/content_redirection/defines.h create mode 100644 include/content_redirection/devoptab_cpp_wrapper.h diff --git a/Makefile b/Makefile index 056a146..3de53e2 100644 --- a/Makefile +++ b/Makefile @@ -117,7 +117,10 @@ lib: @[ -d $@ ] || mkdir -p $@ release: - @[ -d $@ ] || mkdir -p $@ + @$(shell [ ! -d 'release' ] && mkdir -p 'release') + +debug: + @$(shell [ ! -d 'debug' ] && mkdir -p 'debug') lib/libcontentredirection.a :$(SOURCES) $(INCLUDES) | lib release @$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \ diff --git a/include/content_redirection/defines.h b/include/content_redirection/defines.h new file mode 100644 index 0000000..81cc165 --- /dev/null +++ b/include/content_redirection/defines.h @@ -0,0 +1,240 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CONTENT_REDIRECTION_DEVICE_MAGIC 0x43524456 // "CRDV" +#define CONTENT_REDIRECTION_DEVICE_VERSION 1 + +typedef struct { + uint32_t dev; + uint32_t ino; + uint32_t mode; + uint32_t nlink; + uint32_t uid; + uint32_t gid; + uint32_t rdev; + int64_t size; + int64_t atime; + int64_t mtime; + int64_t ctime; + int64_t blksize; + int64_t blocks; +} CR_Stat; + +typedef struct { + uint64_t bsize; + uint64_t frsize; + uint64_t blocks; + uint64_t bfree; + uint64_t bavail; + uint64_t files; + uint64_t ffree; + uint64_t favail; + uint64_t fsid; + uint64_t flag; + uint64_t namemax; +} CR_Statvfs; + +typedef struct { + int64_t tv_sec; + int64_t tv_usec; +} CR_Timeval; + +/** + * @brief ABI-safe representation of a devoptab_t device. + * * This structure bridges native devoptab implementations across the + * module boundary. It removes newlib-specific types (like struct _reent + * and native struct stat) in favor of standard-sized equivalents. + * + * * @note ERROR HANDLING: On failure, every function must return the + * NEGATIVE standard errno value (e.g., `return -ENOENT;`). + */ +typedef struct ContentRedirectionDeviceABI { + uint32_t magic; /**< Identifier magic number (CONTENT_REDIRECTION_DEVICE_MAGIC) */ + uint32_t version; /**< ABI version (CONTENT_REDIRECTION_DEVICE_VERSION) */ + const char *name; /**< Name of the registered device (e.g., "romfs") */ + int structSize; /**< Size of the internal file struct */ + int dirStateSize; /**< Size of the internal dir struct */ + void *deviceData; /**< Opaque pointer to device-specific instance data */ + + // --- File Operations --- + /** + * @brief Opens a file. + * @return 0 or a positive identifier on success, negative errno on failure. + */ + int (*open)(void *fileStruct, const char *path, int flags, uint32_t mode); + + /** + * @brief Closes an open file. + * @return 0 on success, negative errno on failure. + */ + int (*close)(void *fd); + + /** + * @brief Writes data to an open file. + * @return Number of bytes written on success, negative errno on failure. + */ + ssize_t (*write)(void *fd, const char *ptr, size_t len); + + /** + * @brief Reads data from an open file. + * @return Number of bytes read on success, 0 on EOF, negative errno on failure. + */ + ssize_t (*read)(void *fd, char *ptr, size_t len); + + /** + * @brief Repositions the file offset. + * @return The new offset from the beginning of the file, negative errno on failure. + */ + int64_t (*seek)(void *fd, int64_t pos, int dir); + + /** + * @brief Retrieves information about an open file descriptor. + * @return 0 on success, negative errno on failure. + */ + int (*fstat)(void *fd, CR_Stat *st); + + /** + * @brief Retrieves information about a file by its path. + * @return 0 on success, negative errno on failure. + */ + int (*stat)(const char *file, CR_Stat *st); + + /** + * @brief Creates a hard link to an existing file. + * @return 0 on success, negative errno on failure. + */ + int (*link)(const char *existing, const char *newLink); + + /** + * @brief Deletes a name and possibly the file it refers to. + * @return 0 on success, negative errno on failure. + */ + int (*unlink)(const char *name); + + /** + * @brief Changes the current working directory. + * @return 0 on success, negative errno on failure. + */ + int (*chdir)(const char *name); + + /** + * @brief Renames a file or directory. + * @return 0 on success, negative errno on failure. + */ + int (*rename)(const char *oldName, const char *newName); + + /** + * @brief Creates a new directory. + * @return 0 on success, negative errno on failure. + */ + int (*mkdir)(const char *path, uint32_t mode); + + // --- Directory Operations --- + + /** + * @brief Opens a directory stream. + * @return 0 on success, negative errno on failure. + */ + int (*diropen)(void *dirStruct, const char *path); + + /** + * @brief Resets a directory stream to the beginning. + * @return 0 on success, negative errno on failure. + */ + int (*dirreset)(void *dirStruct); + + /** + * @brief Reads the next entry from a directory stream. + * @return 0 on success, negative errno on failure (e.g., -ENOENT for end of stream). + */ + int (*dirnext)(void *dirStruct, char *filename, CR_Stat *filestat); + + /** + * @brief Closes a directory stream. + * @return 0 on success, negative errno on failure. + */ + int (*dirclose)(void *dirStruct); + + // --- Advanced / VFS Operations --- + /** + * @brief Retrieves filesystem statistics. + * @return 0 on success, negative errno on failure. + */ + int (*statvfs)(const char *path, CR_Statvfs *buf); + + /** + * @brief Truncates an open file to a specified length. + * @return 0 on success, negative errno on failure. + */ + int (*ftruncate)(void *fd, int64_t len); + + /** + * @brief Flushes file modifications to physical storage. + * @return 0 on success, negative errno on failure. + */ + int (*fsync)(void *fd); + + /** + * @brief Changes the permissions of a file by path. + * @return 0 on success, negative errno on failure. + */ + int (*chmod)(const char *path, uint32_t mode); + + /** + * @brief Changes the permissions of an open file. + * @return 0 on success, negative errno on failure. + */ + int (*fchmod)(void *fd, uint32_t mode); + + /** + * @brief Removes a directory. + * @return 0 on success, negative errno on failure. + */ + int (*rmdir)(const char *name); + + /** + * @brief Retrieves information about a file, not following symlinks. + * @return 0 on success, negative errno on failure. + */ + int (*lstat)(const char *file, CR_Stat *st); + + /** + * @brief Changes the access and modification times of a file. + * @return 0 on success, negative errno on failure. + */ + int (*utimes)(const char *filename, const CR_Timeval times[2]); + + /** + * @brief Retrieves configuration values for an open file descriptor. + * @return The requested configuration value, negative errno on failure. + */ + int64_t (*fpathconf)(void *fd, int name); + + /** + * @brief Retrieves configuration values for a file by path. + * @return The requested configuration value, negative errno on failure. + */ + int64_t (*pathconf)(const char *path, int name); + + /** + * @brief Creates a symbolic link. + * @return 0 on success, negative errno on failure. + */ + int (*symlink)(const char *target, const char *linkpath); + + /** + * @brief Reads the value of a symbolic link. + * @return Number of bytes placed in buf on success, negative errno on failure. + */ + ssize_t (*readlink)(const char *path, char *buf, size_t bufsiz); +} ContentRedirectionDeviceABI; + +#ifdef __cplusplus +} // extern "C" +#endif \ No newline at end of file diff --git a/include/content_redirection/devoptab_cpp_wrapper.h b/include/content_redirection/devoptab_cpp_wrapper.h new file mode 100644 index 0000000..eaa4ee6 --- /dev/null +++ b/include/content_redirection/devoptab_cpp_wrapper.h @@ -0,0 +1,680 @@ +#pragma once + +#ifdef __cplusplus + +#include "defines.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CR_DevoptabWrapper { +#ifndef CR_MAX_RUNTIME_DEVICES +#define CR_MAX_RUNTIME_DEVICES 4 +#endif + constexpr size_t MAX_RUNTIME_DEVICES = CR_MAX_RUNTIME_DEVICES; + + struct Backend { + static void stat_to_cr_stat(const struct stat &src, CR_Stat *dst) { + if (!dst) { + return; + } + dst->dev = src.st_dev; + dst->ino = src.st_ino; + dst->mode = src.st_mode; + dst->nlink = src.st_nlink; + dst->uid = src.st_uid; + dst->gid = src.st_gid; + dst->rdev = src.st_rdev; + dst->size = src.st_size; + dst->atime = src.st_atime; + dst->mtime = src.st_mtime; + dst->ctime = src.st_ctime; + dst->blksize = src.st_blksize; + dst->blocks = src.st_blocks; + } + + static void statvfs_to_cr_statvfs(const struct statvfs &src, CR_Statvfs *dst) { + if (!dst) { + return; + } + dst->bsize = src.f_bsize; + dst->frsize = src.f_frsize; + dst->blocks = src.f_blocks; + dst->bfree = src.f_bfree; + dst->bavail = src.f_bavail; + dst->files = src.f_files; + dst->ffree = src.f_ffree; + dst->favail = src.f_favail; + dst->fsid = src.f_fsid; + dst->flag = src.f_flag; + dst->namemax = src.f_namemax; + } + + static int get_error(struct _reent *r) { + return r->_errno != 0 ? -(r->_errno) : -EIO; + } + + static struct _reent *get_reent(const devoptab_t *dev) { + auto *r = _REENT; + r->deviceData = dev->deviceData; + return r; + } + + static int open(const devoptab_t *dev, void *fileStruct, const char *path, int flags, uint32_t mode) { + if (!dev || !dev->open_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->open_r(r, fileStruct, path, flags, static_cast(mode)); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int close(const devoptab_t *dev, void *fd) { + if (!dev || !dev->close_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->close_r(r, fd); + if (res == -1) { + return get_error(r); + } + return res; + } + + static ssize_t write(const devoptab_t *dev, void *fd, const char *ptr, size_t len) { + if (!dev || !dev->write_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const ssize_t res = dev->write_r(r, fd, ptr, len); + if (res == -1) { + return get_error(r); + } + return res; + } + + static ssize_t read(const devoptab_t *dev, void *fd, char *ptr, size_t len) { + if (!dev || !dev->read_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const ssize_t res = dev->read_r(r, fd, ptr, len); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int64_t seek(const devoptab_t *dev, void *fd, int64_t pos, int dir) { + if (!dev || !dev->seek_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const off_t res = dev->seek_r(r, fd, static_cast(pos), dir); + if (res == static_cast(-1)) { + return get_error(r); + } + return static_cast(res); + } + + static int fstat(const devoptab_t *dev, void *fd, CR_Stat *st) { + if (!dev || !dev->fstat_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + struct stat local_st {}; + const int res = dev->fstat_r(r, fd, &local_st); + if (res == -1) { + return get_error(r); + } + stat_to_cr_stat(local_st, st); + return res; + } + + static int stat(const devoptab_t *dev, const char *file, CR_Stat *st) { + if (!dev || !dev->stat_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + struct stat local_st {}; + const int res = dev->stat_r(r, file, &local_st); + if (res == -1) { + return get_error(r); + } + stat_to_cr_stat(local_st, st); + return res; + } + + static int link(const devoptab_t *dev, const char *existing, const char *newLink) { + if (!dev || !dev->link_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->link_r(r, existing, newLink); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int unlink(const devoptab_t *dev, const char *name) { + if (!dev || !dev->unlink_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->unlink_r(r, name); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int chdir(const devoptab_t *dev, const char *name) { + if (!dev || !dev->chdir_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->chdir_r(r, name); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int rename(const devoptab_t *dev, const char *oldName, const char *newName) { + if (!dev || !dev->rename_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->rename_r(r, oldName, newName); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int mkdir(const devoptab_t *dev, const char *path, uint32_t mode) { + if (!dev || !dev->mkdir_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->mkdir_r(r, path, static_cast(mode)); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int diropen(const devoptab_t *dev, int deviceId, void *dirStruct, const char *path) { + if (!dev || !dev->diropen_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + DIR_ITER dummy{}; + dummy.device = deviceId; + dummy.dirStruct = dirStruct; + + if (dev->diropen_r(r, &dummy, path) == nullptr) { + return get_error(r); + } + return 0; + } + + static int dirreset(const devoptab_t *dev, int deviceId, void *dirStruct) { + if (!dev || !dev->dirreset_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + DIR_ITER dummy{}; + dummy.device = deviceId; + dummy.dirStruct = dirStruct; + + const int res = dev->dirreset_r(r, &dummy); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int dirnext(const devoptab_t *dev, int deviceId, void *dirStruct, char *filename, CR_Stat *filestat) { + if (!dev || !dev->dirnext_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + DIR_ITER dummy{}; + dummy.device = deviceId; + dummy.dirStruct = dirStruct; + struct stat local_st {}; + const int res = dev->dirnext_r(r, &dummy, filename, &local_st); + if (res == -1) { + return get_error(r); + } + stat_to_cr_stat(local_st, filestat); + return res; + } + + static int dirclose(const devoptab_t *dev, int deviceId, void *dirStruct) { + if (!dev || !dev->dirclose_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + DIR_ITER dummy{}; + dummy.device = deviceId; + dummy.dirStruct = dirStruct; + const int res = dev->dirclose_r(r, &dummy); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int statvfs(const devoptab_t *dev, const char *path, CR_Statvfs *buf) { + if (!dev || !dev->statvfs_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + struct statvfs local_buf {}; + const int res = dev->statvfs_r(r, path, &local_buf); + if (res == -1) { + return get_error(r); + } + statvfs_to_cr_statvfs(local_buf, buf); + return res; + } + + static int ftruncate(const devoptab_t *dev, void *fd, int64_t len) { + if (!dev || !dev->ftruncate_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->ftruncate_r(r, fd, static_cast(len)); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int fsync(const devoptab_t *dev, void *fd) { + if (!dev || !dev->fsync_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->fsync_r(r, fd); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int chmod(const devoptab_t *dev, const char *path, uint32_t mode) { + if (!dev || !dev->chmod_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->chmod_r(r, path, static_cast(mode)); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int fchmod(const devoptab_t *dev, void *fd, uint32_t mode) { + if (!dev || !dev->fchmod_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->fchmod_r(r, fd, static_cast(mode)); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int rmdir(const devoptab_t *dev, const char *name) { + if (!dev || !dev->rmdir_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + int res = dev->rmdir_r(r, name); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int lstat(const devoptab_t *dev, const char *file, CR_Stat *st) { + if (!dev || !dev->lstat_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + struct stat local_st {}; + const int res = dev->lstat_r(r, file, &local_st); + if (res == -1) { + return get_error(r); + } + stat_to_cr_stat(local_st, st); + return res; + } + + static int utimes(const devoptab_t *dev, const char *filename, const CR_Timeval times[2]) { + if (!dev || !dev->utimes_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + + int res; + if (!times) { + res = dev->utimes_r(r, filename, nullptr); + } else { + timeval local_times[2]; + local_times[0].tv_sec = static_cast(times[0].tv_sec); + local_times[0].tv_usec = static_cast(times[0].tv_usec); + local_times[1].tv_sec = static_cast(times[1].tv_sec); + local_times[1].tv_usec = static_cast(times[1].tv_usec); + res = dev->utimes_r(r, filename, local_times); + } + if (res == -1) { + return get_error(r); + } + return res; + } + + static int64_t fpathconf(const devoptab_t *dev, void *fd, int name) { + if (!dev || !dev->fpathconf_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const long res = dev->fpathconf_r(r, fd, name); + if (res == -1) { + return get_error(r); + } + return res; + } + + static int64_t pathconf(const devoptab_t *dev, const char *path, int name) { + if (!dev || !dev->pathconf_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const long res = dev->pathconf_r(r, path, name); + if (res == -1) { + return get_error(r); + } + return static_cast(res); + } + + static int symlink(const devoptab_t *dev, const char *target, const char *linkpath) { + if (!dev || !dev->symlink_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const int res = dev->symlink_r(r, target, linkpath); + if (res == -1) { + return get_error(r); + } + return res; + } + + static ssize_t readlink(const devoptab_t *dev, const char *path, char *buf, size_t bufsiz) { + if (!dev || !dev->readlink_r) { + return -ENOSYS; + } + auto *r = get_reent(dev); + const ssize_t res = dev->readlink_r(r, path, buf, bufsiz); + if (res == -1) { + return get_error(r); + } + return res; + } + }; + + template + struct RuntimeSlot { + inline static const devoptab_t *dev = nullptr; + inline static ContentRedirectionDeviceABI abi = {}; + inline static int deviceId = -1; + + static int open(void *fileStruct, const char *path, int flags, uint32_t mode) { + return Backend::open(dev, fileStruct, path, flags, mode); + } + + static int close(void *fd) { + return Backend::close(dev, fd); + } + + static ssize_t write(void *fd, const char *ptr, size_t len) { + return Backend::write(dev, fd, ptr, len); + } + + static ssize_t read(void *fd, char *ptr, size_t len) { + return Backend::read(dev, fd, ptr, len); + } + + static int64_t seek(void *fd, int64_t pos, int dir) { + return Backend::seek(dev, fd, pos, dir); + } + + static int fstat(void *fd, CR_Stat *st) { + return Backend::fstat(dev, fd, st); + } + + static int stat(const char *file, CR_Stat *st) { + return Backend::stat(dev, file, st); + } + + static int link(const char *existing, const char *newLink) { + return Backend::link(dev, existing, newLink); + } + + static int unlink(const char *name) { + return Backend::unlink(dev, name); + } + static int chdir(const char *name) { + return Backend::chdir(dev, name); + } + + static int rename(const char *oldName, const char *newName) { + return Backend::rename(dev, oldName, newName); + } + + static int mkdir(const char *path, uint32_t mode) { + return Backend::mkdir(dev, path, mode); + } + + static int diropen(void *dirStruct, const char *path) { + return Backend::diropen(dev, deviceId, dirStruct, path); + } + + static int dirreset(void *dirStruct) { + return Backend::dirreset(dev, deviceId, dirStruct); + } + + static int dirnext(void *dirStruct, char *filename, CR_Stat *filestat) { + return Backend::dirnext(dev, deviceId, dirStruct, filename, filestat); + } + + static int dirclose(void *dirStruct) { + return Backend::dirclose(dev, deviceId, dirStruct); + } + + static int statvfs(const char *path, CR_Statvfs *buf) { + return Backend::statvfs(dev, path, buf); + } + + static int ftruncate(void *fd, int64_t len) { + return Backend::ftruncate(dev, fd, len); + } + + static int fsync(void *fd) { + return Backend::fsync(dev, fd); + } + + static int chmod(const char *path, uint32_t mode) { + return Backend::chmod(dev, path, mode); + } + + static int fchmod(void *fd, uint32_t mode) { + return Backend::fchmod(dev, fd, mode); + } + + static int rmdir(const char *name) { + return Backend::rmdir(dev, name); + } + + static int lstat(const char *file, CR_Stat *st) { + return Backend::lstat(dev, file, st); + } + + static int utimes(const char *filename, const CR_Timeval times[2]) { + return Backend::utimes(dev, filename, times); + } + + static int64_t fpathconf(void *fd, int name) { + return Backend::fpathconf(dev, fd, name); + } + + static int64_t pathconf(const char *path, int name) { + return Backend::pathconf(dev, path, name); + } + + static int symlink(const char *target, const char *linkpath) { + return Backend::symlink(dev, target, linkpath); + } + + static ssize_t readlink(const char *path, char *buf, size_t bufsiz) { + return Backend::readlink(dev, path, buf, bufsiz); + } + + static ContentRedirectionDeviceABI *bind(const devoptab_t *device) { + dev = device; + abi.magic = CONTENT_REDIRECTION_DEVICE_MAGIC; + abi.version = CONTENT_REDIRECTION_DEVICE_VERSION; + abi.name = dev->name; + abi.structSize = dev->structSize; + abi.dirStateSize = dev->dirStateSize; + abi.deviceData = dev->deviceData; + + deviceId = -1; + for (int i = 0; i < STD_MAX; i++) { + if (devoptab_list[i] == dev) { + deviceId = i; + break; + } + } + + abi.open = dev->open_r ? open : nullptr; + abi.close = dev->close_r ? close : nullptr; + abi.write = dev->write_r ? write : nullptr; + abi.read = dev->read_r ? read : nullptr; + abi.seek = dev->seek_r ? seek : nullptr; + abi.fstat = dev->fstat_r ? fstat : nullptr; + abi.stat = dev->stat_r ? stat : nullptr; + abi.link = dev->link_r ? link : nullptr; + abi.unlink = dev->unlink_r ? unlink : nullptr; + abi.chdir = dev->chdir_r ? chdir : nullptr; + abi.rename = dev->rename_r ? rename : nullptr; + abi.mkdir = dev->mkdir_r ? mkdir : nullptr; + + abi.diropen = dev->diropen_r ? diropen : nullptr; + abi.dirreset = dev->dirreset_r ? dirreset : nullptr; + abi.dirnext = dev->dirnext_r ? dirnext : nullptr; + abi.dirclose = dev->dirclose_r ? dirclose : nullptr; + + abi.statvfs = dev->statvfs_r ? statvfs : nullptr; + abi.ftruncate = dev->ftruncate_r ? ftruncate : nullptr; + abi.fsync = dev->fsync_r ? fsync : nullptr; + abi.chmod = dev->chmod_r ? chmod : nullptr; + abi.fchmod = dev->fchmod_r ? fchmod : nullptr; + abi.rmdir = dev->rmdir_r ? rmdir : nullptr; + abi.lstat = dev->lstat_r ? lstat : nullptr; + abi.utimes = dev->utimes_r ? utimes : nullptr; + abi.fpathconf = dev->fpathconf_r ? fpathconf : nullptr; + abi.pathconf = dev->pathconf_r ? pathconf : nullptr; + abi.symlink = dev->symlink_r ? symlink : nullptr; + abi.readlink = dev->readlink_r ? readlink : nullptr; + + return &abi; + } + }; + + using RuntimeBinder = ContentRedirectionDeviceABI *(*) (const devoptab_t *); + + template + constexpr auto make_runtime_binders(std::index_sequence) { + return std::array{RuntimeSlot::bind...}; + } + + struct GlobalState { + static constexpr auto binders = make_runtime_binders(std::make_index_sequence{}); + inline static std::array activeDevices = {}; + inline static std::recursive_mutex deviceMutex; + }; + +} // namespace CR_DevoptabWrapper + +/** + * @brief Transparent, ABI-safe wrapper for registering devoptab_t devices. + * Because this is inline C++, it is compiled entirely inside the calling plugin's environment. + */ +inline ContentRedirectionStatus ContentRedirection_AddDevice(const devoptab_t *device, int *resultOut) { + if (!device || !resultOut) { + return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT; + } + + using namespace CR_DevoptabWrapper; + + std::lock_guard lock(GlobalState::deviceMutex); + + for (size_t i = 0; i < MAX_RUNTIME_DEVICES; i++) { + if (GlobalState::activeDevices[i] == nullptr || GlobalState::activeDevices[i] == device) { + GlobalState::activeDevices[i] = device; + + const auto *abiDevice = GlobalState::binders[i](device); + + return ContentRedirection_AddDeviceABI(abiDevice, resultOut); + } + } + return CONTENT_REDIRECTION_RESULT_NO_MEMORY; +} + +inline ContentRedirectionStatus ContentRedirection_RemoveDevice(const char *deviceName, int *resultOut) { + if (!deviceName || !resultOut) { + return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT; + } + + using namespace CR_DevoptabWrapper; + + std::lock_guard lock(GlobalState::deviceMutex); + + auto *separator = strchr(deviceName, ':'); + size_t deviceNameLen = (separator != nullptr) ? (separator - deviceName) : strlen(deviceName); + + for (size_t i = 0; i < MAX_RUNTIME_DEVICES; i++) { + if (GlobalState::activeDevices[i]) { + size_t namelen = strlen(GlobalState::activeDevices[i]->name); + + if (deviceNameLen == namelen) { + if (strncmp(GlobalState::activeDevices[i]->name, deviceName, deviceNameLen) == 0) { + GlobalState::activeDevices[i] = nullptr; + } + } + } + } + + return ::ContentRedirection_RemoveDeviceABI(deviceName, resultOut); +} + +#endif // __cplusplus \ No newline at end of file diff --git a/include/content_redirection/redirection.h b/include/content_redirection/redirection.h index 90fb979..fc10d55 100644 --- a/include/content_redirection/redirection.h +++ b/include/content_redirection/redirection.h @@ -1,7 +1,7 @@ #pragma once +#include "defines.h" #include -#include #ifdef __cplusplus extern "C" { @@ -185,29 +185,35 @@ ContentRedirectionStatus ContentRedirection_SetActive(CRLayerHandle handle, bool * * @param device Device that will be added * @param resultOut Will hold the result of the "AddDevice" call. - * @return CONTENT_REDIRECTION_RESULT_SUCCESS: AddDevice has been called, result is written to resultOut.
- * See documentation of AddDevice for more information
+ * @return CONTENT_REDIRECTION_RESULT_SUCCESS: AddDevice has been called, result is written to resultOut. * CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED: "ContentRedirection_InitLibrary()" was not called.
* CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND: This command is not supported by the currently loaded Module.
* CONTENT_REDIRECTION_RESULT_INVALID_ARG: resultOut is NULL.
* CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR: Unknown error.
*/ -ContentRedirectionStatus ContentRedirection_AddDevice(const devoptab_t *device, int *resultOut); +ContentRedirectionStatus ContentRedirection_AddDeviceABI(const ContentRedirectionDeviceABI *device, int *resultOut); /** * Calls "RemoveDevice" for the ContentRedirection Module. * - * @param name name of the device that will be added. e.g. "romfs:" - * @param resultOut Will hold the result of the "AddDevice" call. - * @return CONTENT_REDIRECTION_RESULT_SUCCESS: RemoveDevice has been called, result is written to resultOut.
- * See documentation of RemoveDevice for more information
- * CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED: "ContentRedirection_InitLibrary()" was not called.
- * CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND: This command is not supported by the currently loaded Module.
- * CONTENT_REDIRECTION_RESULT_INVALID_ARG: resultOut is NULL.
- * CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR: Unknown error. + * @param name name of the device that will be removed. e.g. "romfs:" + * @param resultOut Will hold the result of the "RemoveDevice" call. + * @return CONTENT_REDIRECTION_RESULT_SUCCESS: RemoveDevice has been called, result is written to resultOut.
+ * CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED: "ContentRedirection_InitLibrary()" was not called.
+ * CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND: This command is not supported by the currently loaded Module.
+ * CONTENT_REDIRECTION_RESULT_INVALID_ARG: resultOut is NULL.
+ * CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR: Unknown error. */ -ContentRedirectionStatus ContentRedirection_RemoveDevice(const char *name, int *resultOut); - +ContentRedirectionStatus ContentRedirection_RemoveDeviceABI(const char *device_name, int *resultOut); #ifdef __cplusplus } // extern "C" -#endif \ No newline at end of file +#endif + +#ifdef __cplusplus +#include "devoptab_cpp_wrapper.h" +#else +static inline ContentRedirectionStatus ContentRedirection_RemoveDevice(const char *device_name, int *resultOut) { + return ContentRedirection_RemoveDeviceABI(device_name, resultOut); +} + +#endif diff --git a/source/utils.cpp b/source/utils.cpp index 50651f2..246f9d4 100644 --- a/source/utils.cpp +++ b/source/utils.cpp @@ -2,7 +2,6 @@ #include "logger.h" #include #include -#include static OSDynLoad_Module sModuleHandle = nullptr; @@ -11,11 +10,28 @@ static ContentRedirectionApiErrorType (*sCRAddFSLayer)(CRLayerHandle *, const ch static ContentRedirectionApiErrorType (*sCRRemoveFSLayer)(CRLayerHandle) = nullptr; static ContentRedirectionApiErrorType (*sCRSetActive)(CRLayerHandle, bool) = nullptr; static ContentRedirectionApiErrorType (*sCRGetVersion)(ContentRedirectionVersion *) = nullptr; -static int (*sCRAddDevice)(const devoptab_t *, int *) = nullptr; -static int (*sCRRemoveDevice)(const char *) = nullptr; +static ContentRedirectionApiErrorType (*sCRAddDeviceABI)(const ContentRedirectionDeviceABI *, int *) = nullptr; +static ContentRedirectionApiErrorType (*sCRRemoveDeviceABI)(const char *, int *) = nullptr; static ContentRedirectionVersion sContentRedirectionVersion = CONTENT_REDIRECTION_MODULE_VERSION_ERROR; +static ContentRedirectionStatus ConvertApiError(ContentRedirectionApiErrorType apiError) { + switch (apiError) { + case CONTENT_REDIRECTION_API_ERROR_NONE: + return CONTENT_REDIRECTION_RESULT_SUCCESS; + case CONTENT_REDIRECTION_API_ERROR_INVALID_ARG: + return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT; + case CONTENT_REDIRECTION_API_ERROR_NO_MEMORY: + return CONTENT_REDIRECTION_RESULT_NO_MEMORY; + case CONTENT_REDIRECTION_API_ERROR_UNKNOWN_FS_LAYER_TYPE: + return CONTENT_REDIRECTION_RESULT_UNKNOWN_FS_LAYER_TYPE; + case CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND: + return CONTENT_REDIRECTION_RESULT_LAYER_NOT_FOUND; + default: + return CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR; + } +} + const char *ContentRedirection_GetStatusStr(ContentRedirectionStatus status) { switch (status) { case CONTENT_REDIRECTION_RESULT_SUCCESS: @@ -78,14 +94,14 @@ ContentRedirectionStatus ContentRedirection_InitLibrary() { sCRSetActive = nullptr; } - if (OSDynLoad_FindExport(sModuleHandle, OS_DYNLOAD_EXPORT_FUNC, "CRAddDevice", (void **) &sCRAddDevice) != OS_DYNLOAD_OK) { - DEBUG_FUNCTION_LINE_ERR("FindExport CRAddDevice failed."); - sCRAddDevice = nullptr; + if (OSDynLoad_FindExport(sModuleHandle, OS_DYNLOAD_EXPORT_FUNC, "CRAddDeviceABI", (void **) &sCRAddDeviceABI) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_ERR("FindExport CRAddDeviceABI failed."); + sCRAddDeviceABI = nullptr; } - if (OSDynLoad_FindExport(sModuleHandle, OS_DYNLOAD_EXPORT_FUNC, "CRRemoveDevice", (void **) &sCRRemoveDevice) != OS_DYNLOAD_OK) { - DEBUG_FUNCTION_LINE_ERR("FindExport CRRemoveDevice failed."); - sCRRemoveDevice = nullptr; + if (OSDynLoad_FindExport(sModuleHandle, OS_DYNLOAD_EXPORT_FUNC, "CRRemoveDeviceABI", (void **) &sCRRemoveDeviceABI) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_ERR("FindExport CRRemoveDeviceABI failed."); + sCRRemoveDeviceABI = nullptr; } return CONTENT_REDIRECTION_RESULT_SUCCESS; @@ -108,11 +124,7 @@ ContentRedirectionStatus ContentRedirection_GetVersion(ContentRedirectionVersion } } - const auto res = sCRGetVersion(outVersion); - if (res == CONTENT_REDIRECTION_API_ERROR_NONE) { - return CONTENT_REDIRECTION_RESULT_SUCCESS; - } - return res == CONTENT_REDIRECTION_API_ERROR_INVALID_ARG ? CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT : CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR; + return ConvertApiError(sCRGetVersion(outVersion)); } @@ -123,20 +135,8 @@ ContentRedirectionStatus ContentRedirection_AddFSLayer(CRLayerHandle *handlePtr, if (sCRAddFSLayer == nullptr || sContentRedirectionVersion < 1) { return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND; } - auto res = sCRAddFSLayer(handlePtr, layerName, replacementDir, layerType); - if (res == CONTENT_REDIRECTION_API_ERROR_NONE) { - return CONTENT_REDIRECTION_RESULT_SUCCESS; - } - switch (res) { - case CONTENT_REDIRECTION_API_ERROR_INVALID_ARG: - return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT; - case CONTENT_REDIRECTION_API_ERROR_NO_MEMORY: - return CONTENT_REDIRECTION_RESULT_NO_MEMORY; - case CONTENT_REDIRECTION_API_ERROR_UNKNOWN_FS_LAYER_TYPE: - return CONTENT_REDIRECTION_RESULT_UNKNOWN_FS_LAYER_TYPE; - default: - return CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR; - } + + return ConvertApiError(sCRAddFSLayer(handlePtr, layerName, replacementDir, layerType)); } ContentRedirectionStatus ContentRedirection_AddFSLayerEx(CRLayerHandle *handlePtr, const char *layerName, const char *targetPath, const char *replacementDir, const FSLayerTypeEx layerType) { @@ -146,20 +146,8 @@ ContentRedirectionStatus ContentRedirection_AddFSLayerEx(CRLayerHandle *handlePt if (sCRAddFSLayerEx == nullptr || sContentRedirectionVersion < 2) { return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND; } - const auto res = sCRAddFSLayerEx(handlePtr, layerName, targetPath, replacementDir, layerType); - if (res == CONTENT_REDIRECTION_API_ERROR_NONE) { - return CONTENT_REDIRECTION_RESULT_SUCCESS; - } - switch (res) { - case CONTENT_REDIRECTION_API_ERROR_INVALID_ARG: - return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT; - case CONTENT_REDIRECTION_API_ERROR_NO_MEMORY: - return CONTENT_REDIRECTION_RESULT_NO_MEMORY; - case CONTENT_REDIRECTION_API_ERROR_UNKNOWN_FS_LAYER_TYPE: - return CONTENT_REDIRECTION_RESULT_UNKNOWN_FS_LAYER_TYPE; - default: - return CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR; - } + + return ConvertApiError(sCRAddFSLayerEx(handlePtr, layerName, targetPath, replacementDir, layerType)); } ContentRedirectionStatus ContentRedirection_RemoveFSLayer(CRLayerHandle handlePtr) { @@ -169,16 +157,8 @@ ContentRedirectionStatus ContentRedirection_RemoveFSLayer(CRLayerHandle handlePt if (sCRRemoveFSLayer == nullptr || sContentRedirectionVersion < 1) { return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND; } - const auto res = sCRRemoveFSLayer(handlePtr); - if (res == CONTENT_REDIRECTION_API_ERROR_NONE) { - return CONTENT_REDIRECTION_RESULT_SUCCESS; - } - - if (res == CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND) { - return CONTENT_REDIRECTION_RESULT_LAYER_NOT_FOUND; - } - return CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR; + return ConvertApiError(sCRRemoveFSLayer(handlePtr)); } ContentRedirectionStatus ContentRedirection_SetActive(CRLayerHandle handle, bool active) { @@ -188,44 +168,35 @@ ContentRedirectionStatus ContentRedirection_SetActive(CRLayerHandle handle, bool if (sCRSetActive == nullptr || sContentRedirectionVersion < 1) { return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND; } - const auto res = sCRSetActive(handle, active); - if (res == CONTENT_REDIRECTION_API_ERROR_NONE) { - return CONTENT_REDIRECTION_RESULT_SUCCESS; - } - if (res == CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND) { - return CONTENT_REDIRECTION_RESULT_LAYER_NOT_FOUND; - } - - return CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR; + return ConvertApiError(sCRSetActive(handle, active)); } -ContentRedirectionStatus ContentRedirection_AddDevice(const devoptab_t *device, int *resultOut) { +ContentRedirectionStatus ContentRedirection_AddDeviceABI(const ContentRedirectionDeviceABI *device, int *resultOut) { if (sContentRedirectionVersion == CONTENT_REDIRECTION_MODULE_VERSION_ERROR) { return CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED; } - if (sCRAddDevice == nullptr || sContentRedirectionVersion < 1) { + if (sCRAddDeviceABI == nullptr || sContentRedirectionVersion < 3) { return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND; } - if (resultOut == nullptr) { + if (device == nullptr || resultOut == nullptr) { return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT; } - *resultOut = reinterpret_cast(sCRAddDevice)(device); - return CONTENT_REDIRECTION_RESULT_SUCCESS; + return ConvertApiError(sCRAddDeviceABI(device, resultOut)); } -ContentRedirectionStatus ContentRedirection_RemoveDevice(const char *name, int *resultOut) { +ContentRedirectionStatus ContentRedirection_RemoveDeviceABI(const char *device_name, int *resultOut) { if (sContentRedirectionVersion == CONTENT_REDIRECTION_MODULE_VERSION_ERROR) { return CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED; } - if (sCRRemoveDevice == nullptr || sContentRedirectionVersion < 1) { + if (sCRRemoveDeviceABI == nullptr || sContentRedirectionVersion < 3) { return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND; } - if (resultOut == nullptr) { + if (device_name == nullptr || resultOut == nullptr) { return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT; } - *resultOut = reinterpret_cast(sCRRemoveDevice)(name); - return CONTENT_REDIRECTION_RESULT_SUCCESS; -} + + return ConvertApiError(sCRRemoveDeviceABI(device_name, resultOut)); +} \ No newline at end of file From 2b641b6e5d0de9f1ab8cd9e72391d16ab8a9bcb4 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 3 Apr 2026 15:28:13 +0200 Subject: [PATCH 2/2] Pass in the deviceData ptr into the each function of the ContentRedirectionDeviceABI --- include/content_redirection/defines.h | 58 ++++----- .../devoptab_cpp_wrapper.h | 121 ++++++++++++------ 2 files changed, 110 insertions(+), 69 deletions(-) diff --git a/include/content_redirection/defines.h b/include/content_redirection/defines.h index 81cc165..4eeef97 100644 --- a/include/content_redirection/defines.h +++ b/include/content_redirection/defines.h @@ -60,80 +60,80 @@ typedef struct ContentRedirectionDeviceABI { const char *name; /**< Name of the registered device (e.g., "romfs") */ int structSize; /**< Size of the internal file struct */ int dirStateSize; /**< Size of the internal dir struct */ - void *deviceData; /**< Opaque pointer to device-specific instance data */ + void *deviceData; /**< Context data passed into each function call */ // --- File Operations --- /** * @brief Opens a file. * @return 0 or a positive identifier on success, negative errno on failure. */ - int (*open)(void *fileStruct, const char *path, int flags, uint32_t mode); + int (*open)(void *deviceData, void *fileStruct, const char *path, int flags, uint32_t mode); /** * @brief Closes an open file. * @return 0 on success, negative errno on failure. */ - int (*close)(void *fd); + int (*close)(void *deviceData, void *fd); /** * @brief Writes data to an open file. * @return Number of bytes written on success, negative errno on failure. */ - ssize_t (*write)(void *fd, const char *ptr, size_t len); + ssize_t (*write)(void *deviceData, void *fd, const char *ptr, size_t len); /** * @brief Reads data from an open file. * @return Number of bytes read on success, 0 on EOF, negative errno on failure. */ - ssize_t (*read)(void *fd, char *ptr, size_t len); + ssize_t (*read)(void *deviceData, void *fd, char *ptr, size_t len); /** * @brief Repositions the file offset. * @return The new offset from the beginning of the file, negative errno on failure. */ - int64_t (*seek)(void *fd, int64_t pos, int dir); + int64_t (*seek)(void *deviceData, void *fd, int64_t pos, int dir); /** * @brief Retrieves information about an open file descriptor. * @return 0 on success, negative errno on failure. */ - int (*fstat)(void *fd, CR_Stat *st); + int (*fstat)(void *deviceData, void *fd, CR_Stat *st); /** * @brief Retrieves information about a file by its path. * @return 0 on success, negative errno on failure. */ - int (*stat)(const char *file, CR_Stat *st); + int (*stat)(void *deviceData, const char *file, CR_Stat *st); /** * @brief Creates a hard link to an existing file. * @return 0 on success, negative errno on failure. */ - int (*link)(const char *existing, const char *newLink); + int (*link)(void *deviceData, const char *existing, const char *newLink); /** * @brief Deletes a name and possibly the file it refers to. * @return 0 on success, negative errno on failure. */ - int (*unlink)(const char *name); + int (*unlink)(void *deviceData, const char *name); /** * @brief Changes the current working directory. * @return 0 on success, negative errno on failure. */ - int (*chdir)(const char *name); + int (*chdir)(void *deviceData, const char *name); /** * @brief Renames a file or directory. * @return 0 on success, negative errno on failure. */ - int (*rename)(const char *oldName, const char *newName); + int (*rename)(void *deviceData, const char *oldName, const char *newName); /** * @brief Creates a new directory. * @return 0 on success, negative errno on failure. */ - int (*mkdir)(const char *path, uint32_t mode); + int (*mkdir)(void *deviceData, const char *path, uint32_t mode); // --- Directory Operations --- @@ -141,98 +141,98 @@ typedef struct ContentRedirectionDeviceABI { * @brief Opens a directory stream. * @return 0 on success, negative errno on failure. */ - int (*diropen)(void *dirStruct, const char *path); + int (*diropen)(void *deviceData, void *dirStruct, const char *path); /** * @brief Resets a directory stream to the beginning. * @return 0 on success, negative errno on failure. */ - int (*dirreset)(void *dirStruct); + int (*dirreset)(void *deviceData, void *dirStruct); /** * @brief Reads the next entry from a directory stream. * @return 0 on success, negative errno on failure (e.g., -ENOENT for end of stream). */ - int (*dirnext)(void *dirStruct, char *filename, CR_Stat *filestat); + int (*dirnext)(void *deviceData, void *dirStruct, char *filename, CR_Stat *filestat); /** * @brief Closes a directory stream. * @return 0 on success, negative errno on failure. */ - int (*dirclose)(void *dirStruct); + int (*dirclose)(void *deviceData, void *dirStruct); // --- Advanced / VFS Operations --- /** * @brief Retrieves filesystem statistics. * @return 0 on success, negative errno on failure. */ - int (*statvfs)(const char *path, CR_Statvfs *buf); + int (*statvfs)(void *deviceData, const char *path, CR_Statvfs *buf); /** * @brief Truncates an open file to a specified length. * @return 0 on success, negative errno on failure. */ - int (*ftruncate)(void *fd, int64_t len); + int (*ftruncate)(void *deviceData, void *fd, int64_t len); /** * @brief Flushes file modifications to physical storage. * @return 0 on success, negative errno on failure. */ - int (*fsync)(void *fd); + int (*fsync)(void *deviceData, void *fd); /** * @brief Changes the permissions of a file by path. * @return 0 on success, negative errno on failure. */ - int (*chmod)(const char *path, uint32_t mode); + int (*chmod)(void *deviceData, const char *path, uint32_t mode); /** * @brief Changes the permissions of an open file. * @return 0 on success, negative errno on failure. */ - int (*fchmod)(void *fd, uint32_t mode); + int (*fchmod)(void *deviceData, void *fd, uint32_t mode); /** * @brief Removes a directory. * @return 0 on success, negative errno on failure. */ - int (*rmdir)(const char *name); + int (*rmdir)(void *deviceData, const char *name); /** * @brief Retrieves information about a file, not following symlinks. * @return 0 on success, negative errno on failure. */ - int (*lstat)(const char *file, CR_Stat *st); + int (*lstat)(void *deviceData, const char *file, CR_Stat *st); /** * @brief Changes the access and modification times of a file. * @return 0 on success, negative errno on failure. */ - int (*utimes)(const char *filename, const CR_Timeval times[2]); + int (*utimes)(void *deviceData, const char *filename, const CR_Timeval times[2]); /** * @brief Retrieves configuration values for an open file descriptor. * @return The requested configuration value, negative errno on failure. */ - int64_t (*fpathconf)(void *fd, int name); + int64_t (*fpathconf)(void *deviceData, void *fd, int name); /** * @brief Retrieves configuration values for a file by path. * @return The requested configuration value, negative errno on failure. */ - int64_t (*pathconf)(const char *path, int name); + int64_t (*pathconf)(void *deviceData, const char *path, int name); /** * @brief Creates a symbolic link. * @return 0 on success, negative errno on failure. */ - int (*symlink)(const char *target, const char *linkpath); + int (*symlink)(void *deviceData, const char *target, const char *linkpath); /** * @brief Reads the value of a symbolic link. * @return Number of bytes placed in buf on success, negative errno on failure. */ - ssize_t (*readlink)(const char *path, char *buf, size_t bufsiz); + ssize_t (*readlink)(void *deviceData, const char *path, char *buf, size_t bufsiz); } ContentRedirectionDeviceABI; #ifdef __cplusplus diff --git a/include/content_redirection/devoptab_cpp_wrapper.h b/include/content_redirection/devoptab_cpp_wrapper.h index eaa4ee6..1ae424f 100644 --- a/include/content_redirection/devoptab_cpp_wrapper.h +++ b/include/content_redirection/devoptab_cpp_wrapper.h @@ -447,114 +447,142 @@ namespace CR_DevoptabWrapper { inline static ContentRedirectionDeviceABI abi = {}; inline static int deviceId = -1; - static int open(void *fileStruct, const char *path, int flags, uint32_t mode) { + static int open(void *deviceData, void *fileStruct, const char *path, int flags, uint32_t mode) { + (void) deviceData; return Backend::open(dev, fileStruct, path, flags, mode); } - static int close(void *fd) { + static int close(void *deviceData, void *fd) { + (void) deviceData; return Backend::close(dev, fd); } - static ssize_t write(void *fd, const char *ptr, size_t len) { + static ssize_t write(void *deviceData, void *fd, const char *ptr, size_t len) { + (void) deviceData; return Backend::write(dev, fd, ptr, len); } - static ssize_t read(void *fd, char *ptr, size_t len) { + static ssize_t read(void *deviceData, void *fd, char *ptr, size_t len) { + (void) deviceData; return Backend::read(dev, fd, ptr, len); } - static int64_t seek(void *fd, int64_t pos, int dir) { + static int64_t seek(void *deviceData, void *fd, int64_t pos, int dir) { + (void) deviceData; return Backend::seek(dev, fd, pos, dir); } - static int fstat(void *fd, CR_Stat *st) { + static int fstat(void *deviceData, void *fd, CR_Stat *st) { + (void) deviceData; return Backend::fstat(dev, fd, st); } - static int stat(const char *file, CR_Stat *st) { + static int stat(void *deviceData, const char *file, CR_Stat *st) { + (void) deviceData; return Backend::stat(dev, file, st); } - static int link(const char *existing, const char *newLink) { + static int link(void *deviceData, const char *existing, const char *newLink) { + (void) deviceData; return Backend::link(dev, existing, newLink); } - static int unlink(const char *name) { + static int unlink(void *deviceData, const char *name) { + (void) deviceData; return Backend::unlink(dev, name); } - static int chdir(const char *name) { + static int chdir(void *deviceData, const char *name) { + (void) deviceData; return Backend::chdir(dev, name); } - static int rename(const char *oldName, const char *newName) { + static int rename(void *deviceData, const char *oldName, const char *newName) { + (void) deviceData; return Backend::rename(dev, oldName, newName); } - static int mkdir(const char *path, uint32_t mode) { + static int mkdir(void *deviceData, const char *path, uint32_t mode) { + (void) deviceData; return Backend::mkdir(dev, path, mode); } - static int diropen(void *dirStruct, const char *path) { + static int diropen(void *deviceData, void *dirStruct, const char *path) { + (void) deviceData; return Backend::diropen(dev, deviceId, dirStruct, path); } - static int dirreset(void *dirStruct) { + static int dirreset(void *deviceData, void *dirStruct) { + (void) deviceData; return Backend::dirreset(dev, deviceId, dirStruct); } - static int dirnext(void *dirStruct, char *filename, CR_Stat *filestat) { + static int dirnext(void *deviceData, void *dirStruct, char *filename, CR_Stat *filestat) { + (void) deviceData; return Backend::dirnext(dev, deviceId, dirStruct, filename, filestat); } - static int dirclose(void *dirStruct) { + static int dirclose(void *deviceData, void *dirStruct) { + (void) deviceData; return Backend::dirclose(dev, deviceId, dirStruct); } - static int statvfs(const char *path, CR_Statvfs *buf) { + static int statvfs(void *deviceData, const char *path, CR_Statvfs *buf) { + (void) deviceData; return Backend::statvfs(dev, path, buf); } - static int ftruncate(void *fd, int64_t len) { + static int ftruncate(void *deviceData, void *fd, int64_t len) { + (void) deviceData; return Backend::ftruncate(dev, fd, len); } - static int fsync(void *fd) { + static int fsync(void *deviceData, void *fd) { + (void) deviceData; return Backend::fsync(dev, fd); } - static int chmod(const char *path, uint32_t mode) { + static int chmod(void *deviceData, const char *path, uint32_t mode) { + (void) deviceData; return Backend::chmod(dev, path, mode); } - static int fchmod(void *fd, uint32_t mode) { + static int fchmod(void *deviceData, void *fd, uint32_t mode) { + (void) deviceData; return Backend::fchmod(dev, fd, mode); } - static int rmdir(const char *name) { + static int rmdir(void *deviceData, const char *name) { + (void) deviceData; return Backend::rmdir(dev, name); } - static int lstat(const char *file, CR_Stat *st) { + static int lstat(void *deviceData, const char *file, CR_Stat *st) { + (void) deviceData; return Backend::lstat(dev, file, st); } - static int utimes(const char *filename, const CR_Timeval times[2]) { + static int utimes(void *deviceData, const char *filename, const CR_Timeval times[2]) { + (void) deviceData; return Backend::utimes(dev, filename, times); } - static int64_t fpathconf(void *fd, int name) { + static int64_t fpathconf(void *deviceData, void *fd, int name) { + (void) deviceData; return Backend::fpathconf(dev, fd, name); } - static int64_t pathconf(const char *path, int name) { + static int64_t pathconf(void *deviceData, const char *path, int name) { + (void) deviceData; return Backend::pathconf(dev, path, name); } - static int symlink(const char *target, const char *linkpath) { + static int symlink(void *deviceData, const char *target, const char *linkpath) { + (void) deviceData; return Backend::symlink(dev, target, linkpath); } - static ssize_t readlink(const char *path, char *buf, size_t bufsiz) { + static ssize_t readlink(void *deviceData, const char *path, char *buf, size_t bufsiz) { + (void) deviceData; return Backend::readlink(dev, path, buf, bufsiz); } @@ -629,14 +657,14 @@ namespace CR_DevoptabWrapper { * @brief Transparent, ABI-safe wrapper for registering devoptab_t devices. * Because this is inline C++, it is compiled entirely inside the calling plugin's environment. */ -inline ContentRedirectionStatus ContentRedirection_AddDevice(const devoptab_t *device, int *resultOut) { +static inline ContentRedirectionStatus ContentRedirection_AddDevice(const devoptab_t *device, int *resultOut) { if (!device || !resultOut) { return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT; } using namespace CR_DevoptabWrapper; - std::lock_guard lock(GlobalState::deviceMutex); + std::unique_lock lock(GlobalState::deviceMutex); for (size_t i = 0; i < MAX_RUNTIME_DEVICES; i++) { if (GlobalState::activeDevices[i] == nullptr || GlobalState::activeDevices[i] == device) { @@ -644,31 +672,44 @@ inline ContentRedirectionStatus ContentRedirection_AddDevice(const devoptab_t *d const auto *abiDevice = GlobalState::binders[i](device); - return ContentRedirection_AddDeviceABI(abiDevice, resultOut); + lock.unlock(); + + auto res = ContentRedirection_AddDeviceABI(abiDevice, resultOut); + + if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) { + lock.lock(); + if (GlobalState::activeDevices[i] == device) { + GlobalState::activeDevices[i] = nullptr; + } + lock.unlock(); + } + return res; } } return CONTENT_REDIRECTION_RESULT_NO_MEMORY; } -inline ContentRedirectionStatus ContentRedirection_RemoveDevice(const char *deviceName, int *resultOut) { +static inline ContentRedirectionStatus ContentRedirection_RemoveDevice(const char *deviceName, int *resultOut) { if (!deviceName || !resultOut) { return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT; } using namespace CR_DevoptabWrapper; - std::lock_guard lock(GlobalState::deviceMutex); - auto *separator = strchr(deviceName, ':'); size_t deviceNameLen = (separator != nullptr) ? (separator - deviceName) : strlen(deviceName); - for (size_t i = 0; i < MAX_RUNTIME_DEVICES; i++) { - if (GlobalState::activeDevices[i]) { - size_t namelen = strlen(GlobalState::activeDevices[i]->name); + { + std::lock_guard lock(GlobalState::deviceMutex); - if (deviceNameLen == namelen) { - if (strncmp(GlobalState::activeDevices[i]->name, deviceName, deviceNameLen) == 0) { - GlobalState::activeDevices[i] = nullptr; + for (size_t i = 0; i < MAX_RUNTIME_DEVICES; i++) { + if (GlobalState::activeDevices[i]) { + size_t namelen = strlen(GlobalState::activeDevices[i]->name); + + if (deviceNameLen == namelen) { + if (strncmp(GlobalState::activeDevices[i]->name, deviceName, deviceNameLen) == 0) { + GlobalState::activeDevices[i] = nullptr; + } } } }