]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
include: add VFS I/O abstraction layer
authorKarel Zak <kzak@redhat.com>
Tue, 30 Jun 2026 12:20:50 +0000 (14:20 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 9 Jul 2026 10:18:04 +0000 (12:18 +0200)
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 <kzak@redhat.com>
include/Makemodule.am
include/all-io.h
include/vfs.h [new file with mode: 0644]

index 1cf04fe14d5ceaa130a2e4f61d0e41d1710d2447..27dd4bb1c8853f85ad7b75c2bf8ddab372b2eff4 100644 (file)
@@ -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 \
index f83688c0a8d5dfc2680ff2333cefc95360292723..ded49349b8e3f11b36dbd5906cffa0744d86018b 100644 (file)
 #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 (file)
index 0000000..9dfab59
--- /dev/null
@@ -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 <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <string.h>
+
+#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 */