From: Karel Zak Date: Tue, 30 Jun 2026 12:20:50 +0000 (+0200) Subject: include: add VFS I/O abstraction layer X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=83523c7d8a2aa3c3ab889ed44181c889f1215cb3;p=thirdparty%2Futil-linux.git include: add VFS I/O abstraction layer Add include/vfs.h with struct ul_vfs_ops — a pluggable I/O operations table with function pointers matching POSIX signatures (read, write, open, close, lseek, fsync). NULL function pointers fall back to real syscalls. The size field enables forward/backward compatible struct evolution. Refactor include/all-io.h to use VFS dispatch internally: - ul_write_all() and ul_read_all() become macros calling __write_all(NULL, ...) and __read_all(NULL, ...) - New ul_vfs_write_all() and ul_vfs_read_all() macros pass through a VFS ops struct for custom I/O Addresses: https://github.com/util-linux/util-linux/issues/4308 Signed-off-by: Karel Zak --- diff --git a/include/Makemodule.am b/include/Makemodule.am index 1cf04fe14..27dd4bb1c 100644 --- a/include/Makemodule.am +++ b/include/Makemodule.am @@ -84,6 +84,7 @@ dist_noinst_HEADERS += \ include/timer.h \ include/timeutils.h \ include/ttyutils.h \ + include/vfs.h \ include/widechar.h \ include/xalloc.h \ include/xxhash.h \ diff --git a/include/all-io.h b/include/all-io.h index f83688c0a..ded49349b 100644 --- a/include/all-io.h +++ b/include/all-io.h @@ -18,14 +18,16 @@ #endif #include "c.h" +#include "vfs.h" -static inline int ul_write_all(int fd, const void *buf, size_t count) +static inline int __write_all(const struct ul_vfs_ops *vfs, int fd, + const void *buf, size_t count) { while (count) { ssize_t tmp; errno = 0; - tmp = write(fd, buf, count); + tmp = ul_vfs_write(vfs, fd, buf, count); if (tmp > 0) { count -= tmp; if (count) @@ -38,6 +40,9 @@ static inline int ul_write_all(int fd, const void *buf, size_t count) return 0; } +#define ul_write_all(fd, buf, count) __write_all(NULL, (fd), (buf), (count)) +#define ul_vfs_write_all(vfs, fd, buf, count) __write_all((vfs), (fd), (buf), (count)) + static inline int ul_fwrite_all(const void *ptr, size_t size, size_t nmemb, FILE *stream) { @@ -58,7 +63,8 @@ static inline int ul_fwrite_all(const void *ptr, size_t size, return 0; } -static inline ssize_t ul_read_all(int fd, char *buf, size_t count) +static inline ssize_t __read_all(const struct ul_vfs_ops *vfs, int fd, + char *buf, size_t count) { ssize_t ret; ssize_t c = 0; @@ -66,7 +72,7 @@ static inline ssize_t ul_read_all(int fd, char *buf, size_t count) memset(buf, 0, count); while (count > 0) { - ret = read(fd, buf, count); + ret = ul_vfs_read(vfs, fd, buf, count); if (ret < 0) { if ((errno == EAGAIN || errno == EINTR) && (tries++ < 5)) { xusleep(250000); @@ -84,6 +90,9 @@ static inline ssize_t ul_read_all(int fd, char *buf, size_t count) return c; } +#define ul_read_all(fd, buf, count) __read_all(NULL, (fd), (buf), (count)) +#define ul_vfs_read_all(vfs, fd, buf, count) __read_all((vfs), (fd), (buf), (count)) + static inline ssize_t ul_read_all_alloc(int fd, char **buf) { size_t size = 1024, c = 0; diff --git a/include/vfs.h b/include/vfs.h new file mode 100644 index 000000000..9dfab596f --- /dev/null +++ b/include/vfs.h @@ -0,0 +1,86 @@ +/* + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + */ +#ifndef UTIL_LINUX_VFS_H +#define UTIL_LINUX_VFS_H + +#include +#include +#include +#include + +#ifndef UL_VFS_OPS_DEFINED +#define UL_VFS_OPS_DEFINED + +struct ul_vfs_ops { + size_t size; + + ssize_t (*vfs_read)(int fd, void *buf, size_t count); + ssize_t (*vfs_write)(int fd, const void *buf, size_t count); + int (*vfs_open)(const char *pathname, int flags, mode_t mode); + int (*vfs_close)(int fd); + off_t (*vfs_lseek)(int fd, off_t offset, int whence); + int (*vfs_fsync)(int fd); +}; + +#endif /* UL_VFS_OPS_DEFINED */ + +static inline void ul_vfs_init(struct ul_vfs_ops *dst, + const struct ul_vfs_ops *src) +{ + memset(dst, 0, sizeof(*dst)); + if (src && src->size > 0) { + size_t sz = src->size < sizeof(*dst) ? src->size : sizeof(*dst); + memcpy(dst, src, sz); + } + dst->size = sizeof(*dst); +} + +static inline ssize_t ul_vfs_read(const struct ul_vfs_ops *vfs, + int fd, void *buf, size_t count) +{ + if (vfs && vfs->vfs_read) + return vfs->vfs_read(fd, buf, count); + return read(fd, buf, count); +} + +static inline ssize_t ul_vfs_write(const struct ul_vfs_ops *vfs, + int fd, const void *buf, size_t count) +{ + if (vfs && vfs->vfs_write) + return vfs->vfs_write(fd, buf, count); + return write(fd, buf, count); +} + +static inline int ul_vfs_open(const struct ul_vfs_ops *vfs, + const char *pathname, int flags, mode_t mode) +{ + if (vfs && vfs->vfs_open) + return vfs->vfs_open(pathname, flags, mode); + return open(pathname, flags, mode); +} + +static inline int ul_vfs_close(const struct ul_vfs_ops *vfs, int fd) +{ + if (vfs && vfs->vfs_close) + return vfs->vfs_close(fd); + return close(fd); +} + +static inline off_t ul_vfs_lseek(const struct ul_vfs_ops *vfs, + int fd, off_t offset, int whence) +{ + if (vfs && vfs->vfs_lseek) + return vfs->vfs_lseek(fd, offset, whence); + return lseek(fd, offset, whence); +} + +static inline int ul_vfs_fsync(const struct ul_vfs_ops *vfs, int fd) +{ + if (vfs && vfs->vfs_fsync) + return vfs->vfs_fsync(fd); + return fsync(fd); +} + +#endif /* UTIL_LINUX_VFS_H */