root/sys/sys/fusebuf.h
/* $OpenBSD: fusebuf.h,v 1.17 2026/06/17 13:29:01 helg Exp $ */
/*
 * Copyright (c) 2013 Sylvestre Gallon
 * Copyright (c) 2013 Martin Pieuchot
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef _SYS_FUSEBUF_H_
#define _SYS_FUSEBUF_H_

#include <sys/stdint.h>

/*
 * Maximum size of the read or write buffer sent from the kernel for VFS
 * syscalls: read, readdir, readlink, write.
 */
#define FUSEBUFMAXSIZE  (4096*1024)

/** Linux FUSE kernel interface major version we somewhat emulate. */
#define FUSE_KERNEL_VERSION 7

/** Linux FUSE kernel interface minor version we somewhat emulate. */
#define FUSE_KERNEL_MINOR_VERSION 19

/*
 * The root inode is the root of the mounted FUSE file system.
 * Also note that inode 0 can't be used for normal purposes.
 */
#define FUSE_ROOT_ID ((ino_t)1)

/*
 * An operation is issued by the kernel through fuse(4) when the
 * userland file system needs to execute an action (mkdir(2),
 * link(2), etc).
 *
 * F_databuf can be superior to FUSELEN for fusefs_read, fusefs_writes and
 * fusefs_readdir. If it is the case the transfer will be split in N
 * fusebuf with a changing offset in FD_io.
 *
 * When the userland file system answers to this operation it uses
 * the same ID (fh_uuid).
 */

/* flags needed by setattr */
#define FUSE_FATTR_MODE         (1 << 0)
#define FUSE_FATTR_UID          (1 << 1)
#define FUSE_FATTR_GID          (1 << 2)
#define FUSE_FATTR_SIZE         (1 << 3)
#define FUSE_FATTR_ATIME        (1 << 4)
#define FUSE_FATTR_MTIME        (1 << 5)

/* fusebuf types */
#define FUSE_LOOKUP     1
#define FUSE_GETATTR    3
#define FUSE_SETATTR    4
#define FUSE_READLINK   5
#define FUSE_SYMLINK    6
#define FUSE_MKNOD      8
#define FUSE_MKDIR      9
#define FUSE_UNLINK     10
#define FUSE_RMDIR      11
#define FUSE_RENAME     12
#define FUSE_LINK       13
#define FUSE_OPEN       14
#define FUSE_READ       15
#define FUSE_WRITE      16
#define FUSE_STATFS     17
#define FUSE_RELEASE    18
#define FUSE_FSYNC      20
#define FUSE_FLUSH      25
#define FUSE_INIT       26
#define FUSE_OPENDIR    27
#define FUSE_READDIR    28
#define FUSE_RELEASEDIR 29
#define FUSE_DESTROY    38
#define FUSE_FORGET     2

struct fuse_attr {
        uint64_t        ino;
        uint64_t        size;
        uint64_t        blocks;
        uint64_t        atime;
        uint64_t        mtime;
        uint64_t        ctime;
        uint32_t        atimensec;
        uint32_t        mtimensec;
        uint32_t        ctimensec;
        uint32_t        mode;
        uint32_t        nlink;
        uint32_t        uid;
        uint32_t        gid;
        uint32_t        rdev;
        uint32_t        blksize;
        uint32_t        padding;
};


struct fuse_entry_out {
        uint64_t        nodeid;                 /* Inode number */
        uint64_t        generation;             /* Not implemented */
        uint64_t        entry_valid;            /* Not implemented */
        uint64_t        attr_valid;             /* Not implemented */
        uint32_t        entry_valid_nsec;       /* Not implemented */
        uint32_t        attr_valid_nsec;        /* Not implemented */
        struct          fuse_attr attr;
};

struct fuse_forget_in {
        uint64_t        nlookup;
};

struct fuse_getattr_in {
        uint32_t        getattr_flags;          /* Not implemented */
        uint32_t        dummy;
        uint64_t        fh;                     /* Not implemented */
};

struct fuse_attr_out {
        uint64_t        attr_valid;             /* Not implemented */
        uint32_t        attr_valid_nsec;        /* Not implemented */
        uint32_t        dummy;
        struct          fuse_attr attr;
};

struct fuse_mknod_in {
        uint32_t        mode;
        uint32_t        rdev;
        uint32_t        umask;
        uint32_t        padding;
};

struct fuse_mkdir_in {
        uint32_t        mode;
        uint32_t        umask;
};

struct fuse_rename_in {
        uint64_t        newdir;
};

struct fuse_link_in {
        uint64_t        oldnodeid;
};

struct fuse_setattr_in {
        uint32_t        valid;
        uint32_t        padding;
        uint64_t        fh;
        uint64_t        size;
        uint64_t        lock_owner;
        uint64_t        atime;
        uint64_t        mtime;
        uint64_t        unused2;
        uint32_t        atimensec;
        uint32_t        mtimensec;
        uint32_t        unused3;
        uint32_t        mode;
        uint32_t        unused4;
        uint32_t        uid;
        uint32_t        gid;
        uint32_t        unused5;
};

struct fuse_open_in {
        uint32_t        flags;
        uint32_t        unused;
};

struct fuse_open_out {
        uint64_t        fh;
        uint32_t        open_flags;
        uint32_t        padding;
};

struct fuse_release_in {
        uint64_t        fh;
        uint32_t        flags;
        uint32_t        release_flags;
        uint64_t        lock_owner;
};

struct fuse_flush_in {
        uint64_t        fh;
        uint32_t        unused;
        uint32_t        padding;
        uint64_t        lock_owner;
};

struct fuse_read_in {
        uint64_t        fh;
        uint64_t        offset;
        uint32_t        size;
        uint32_t        read_flags;
        uint64_t        lock_owner;
        uint32_t        flags;
        uint32_t        padding;
};

struct fuse_write_in {
        uint64_t        fh;
        uint64_t        offset;
        uint32_t        size;
        uint32_t        write_flags;
        uint64_t        lock_owner;
        uint32_t        flags;
        uint32_t        padding;
};

struct fuse_write_out {
        uint32_t        size;
        uint32_t        padding;
};

struct fuse_kstatfs {
        uint64_t        blocks;
        uint64_t        bfree;
        uint64_t        bavail;
        uint64_t        files;
        uint64_t        ffree;
        uint32_t        bsize;
        uint32_t        namelen;
        uint32_t        frsize;
        uint32_t        padding;
        uint32_t        spare[6];
};

struct fuse_statfs_out {
        struct          fuse_kstatfs st;
};

struct fuse_fsync_in {
        uint64_t        fh;
        uint32_t        fsync_flags;            //XXX
        uint32_t        padding;
};

struct fuse_init_in {
        uint32_t        major;
        uint32_t        minor;
        uint32_t        max_readahead;
        uint32_t        flags;
};

struct fuse_init_out {
        uint32_t        major;
        uint32_t        minor;
        uint32_t        max_readahead;          /* Not implemented */
        uint32_t        flags;                  /* Not implemented */
        uint16_t        max_background;         /* Not implemented */
        uint16_t        congestion_threshold;   /* Not implemented */
        uint32_t        max_write;
};

struct fuse_in_header {
        uint32_t        len;
        uint32_t        opcode;
        uint64_t        unique;
        uint64_t        nodeid;
        uint32_t        uid;
        uint32_t        gid;
        uint32_t        pid;
        uint32_t        padding;
};

struct fuse_out_header {
        uint32_t        len;
        int32_t         error;
        uint64_t        unique;
};

struct fuse_dirent {
        uint64_t        ino;
        uint64_t        off;
        uint32_t        namelen;
        uint32_t        type;
        char            name[];                 /* unterminated string */
};

#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
#define FUSE_DIRENT_ALIGN(x) \
        (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
#define FUSE_DIRENT_SIZE(d) \
        FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)

#ifdef _KERNEL

/*
 * An operation is issued by the kernel through fuse(4) when the
 * userland file system needs to execute an action (mkdir(2),
 * link(2), etc).
 *
 * When the userland file system answers to this operation it uses
 * the same ID (fb_uuid).
 */
struct fusebuf {
        SIMPLEQ_ENTRY(fusebuf)  next;           /* next buffer in chain */
        struct fuse_in_header   hdr;
        int32_t                 error;          /* error returned by daemon */
        size_t                  op_in_len;      /* size of input */
        size_t                  op_out_len;     /* size of output */
        uint8_t                 op_out_buf;     /* whether to expect data */
        union {
                union {
                        struct fuse_forget_in   forget;
                        struct fuse_getattr_in  getattr;
                        struct fuse_setattr_in  setattr;
                        struct fuse_mknod_in    mknod;
                        struct fuse_mkdir_in    mkdir;
                        struct fuse_rename_in   rename;
                        struct fuse_link_in     link;
                        struct fuse_open_in     open;
                        struct fuse_read_in     read;
                        struct fuse_write_in    write;
                        struct fuse_release_in  release;
                        struct fuse_fsync_in    fsync;
                        struct fuse_flush_in    flush;
                        struct fuse_init_in     init;
                } in;
                union {
                        struct fuse_entry_out   entry;
                        struct fuse_attr_out    attr;
                        struct fuse_open_out    open;
                        struct fuse_write_out   write;
                        struct fuse_statfs_out  statfs;
                        struct fuse_init_out    init;
                } out;
        } op;
        uint64_t dat_len;
        uint8_t *dat;
};

#define fb_dat          dat
#define fb_next         next
#define fb_err          error
#define fb_len          dat_len
#define fb_type         hdr.opcode
#define fb_uuid         hdr.unique
#define fb_ino          hdr.nodeid
#define fb_tid          hdr.pid
#define fb_uid          hdr.uid
#define fb_gid          hdr.gid

/* fusebuf prototypes */
struct  fusebuf *fb_setup(size_t, ino_t, int, struct proc *);
int     fb_queue(dev_t, struct fusebuf *);
void    fb_delete(struct fusebuf *);

#else /* _KERNEL */

/*
 * Userland fusebuf more directly maps to the protocol binary layout for each
 * file operation request (input). This consists of a header followed by an
 * optional input struct with data immediately following either the header or
 * input struct.
 *
 * FUSE_LOOKUP:         hdr,            dat (filename)
 * FUSE_GETATTR:        hdr, getattr
 * FUSE_SETATTR:        hdr, setattr
 * FUSE_READLINK:       hdr
 * FUSE_SYMLINK:        hdr,            dat (source\0target)
 * FUSE_MKNOD:          hdr, mknod,     dat (filename)
 * FUSE_MKDIR:          hdr, mkdir,     dat (dirname)
 * FUSE_UNLINK:         hdr,            dat (filename)
 * FUSE_RMDIR:          hdr,            dat (dirname)
 * FUSE_RENAME:         hdr, rename,    dat (oldname\0newname)
 * FUSE_LINK:           hdr,            dat (source\0target)
 * FUSE_OPEN:           hdr, open
 * FUSE_READ:           hdr, read
 * FUSE_WRITE:          hdr, write,     dat
 * FUSE_STATFS:         hdr, statfs
 * FUSE_RELEASE:        hdr, release
 * FUSE_FSYNC:          hdr, fsync
 * FUSE_FLUSH:          hdr, flush
 * FUSE_INIT:           hdr, init
 * FUSE_OPENDIR:        hdr, open
 * FUSE_READDIR:        hdr, read
 * FUSE_RELEASEDIR:     hdr, release
 * FUSE_DESTROY:        hdr
 * FUSE_FORGET:         hdr, forget
 */
struct fusebuf {
        struct fuse_in_header hdr;
        union {
                struct fuse_forget_in   forget;
                struct fuse_getattr_in  getattr;
                struct fuse_setattr_in  setattr;
                struct fuse_mknod_in    mknod;
                struct fuse_mkdir_in    mkdir;
                struct fuse_rename_in   rename;
                struct fuse_link_in     link;
                struct fuse_open_in     open;
                struct fuse_read_in     read;
                struct fuse_write_in    write;
                struct fuse_release_in  release;
                struct fuse_fsync_in    fsync;
                struct fuse_flush_in    flush;
                struct fuse_init_in     init;
        } in;
};

#define fb_type hdr.opcode
#define fb_uuid hdr.unique
#define fb_ino  hdr.nodeid
#define fb_tid  hdr.pid
#define fb_uid  hdr.uid
#define fb_gid  hdr.gid

/*
 * Macro to get the additional data for operations that have it.
 * The data starts immediately after the related input struct.
 */
#define fb_dat(in) (((char *)&(in)) + sizeof(in))

#endif /* _KERNEL */
#endif /* _SYS_FUSEBUF_H_ */