Home | History | Annotate | Line # | Download | only in refuse
      1  1.2  pho /* $NetBSD: fs.c,v 1.2 2023/07/14 02:43:50 pho Exp $ */
      2  1.1  pho 
      3  1.1  pho /*
      4  1.1  pho  * Copyright (c) 2021 The NetBSD Foundation, Inc.
      5  1.1  pho  * All rights reserved.
      6  1.1  pho  *
      7  1.1  pho  * Redistribution and use in source and binary forms, with or without
      8  1.1  pho  * modification, are permitted provided that the following conditions
      9  1.1  pho  * are met:
     10  1.1  pho  * 1. Redistributions of source code must retain the above copyright
     11  1.1  pho  *    notice, this list of conditions and the following disclaimer.
     12  1.1  pho  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  pho  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  pho  *    documentation and/or other materials provided with the distribution.
     15  1.1  pho  * 3. The name of the author may not be used to endorse or promote
     16  1.1  pho  *    products derived from this software without specific prior written
     17  1.1  pho  *    permission.
     18  1.1  pho  *
     19  1.1  pho  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     20  1.1  pho  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  1.1  pho  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  1.1  pho  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     23  1.1  pho  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  1.1  pho  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     25  1.1  pho  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.1  pho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     27  1.1  pho  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     28  1.1  pho  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     29  1.1  pho  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  1.1  pho  */
     31  1.1  pho 
     32  1.1  pho #include <sys/cdefs.h>
     33  1.1  pho #if !defined(lint)
     34  1.2  pho __RCSID("$NetBSD: fs.c,v 1.2 2023/07/14 02:43:50 pho Exp $");
     35  1.1  pho #endif /* !lint */
     36  1.1  pho 
     37  1.1  pho /*
     38  1.1  pho  * Filesystem Stacking API, appeared on FUSE 2.7.
     39  1.1  pho  *
     40  1.1  pho  * So many callback functions in struct fuse_operations have different
     41  1.1  pho  * prototypes between versions. We use the stacking API to abstract
     42  1.1  pho  * that away to implement puffs operations in a manageable way.
     43  1.1  pho  */
     44  1.1  pho 
     45  1.1  pho #include <err.h>
     46  1.1  pho #include <fuse_internal.h>
     47  1.1  pho #include <stdlib.h>
     48  1.1  pho #include <string.h>
     49  1.1  pho #include <sys/dirent.h>
     50  1.1  pho #include <sys/errno.h>
     51  1.1  pho 
     52  1.1  pho struct fuse_fs {
     53  1.1  pho     void* op;
     54  1.1  pho     int   op_version;
     55  1.1  pho     void* user_data;
     56  1.1  pho };
     57  1.1  pho 
     58  1.1  pho #define UNKNOWN_VERSION(op_version)                                     \
     59  1.1  pho     errc(EXIT_FAILURE, ENOSYS, "%s: unknown fuse_operations version: %d", \
     60  1.1  pho          __func__, op_version)
     61  1.1  pho 
     62  1.1  pho static void*
     63  1.1  pho clone_op(const void* op, int op_version) {
     64  1.1  pho     void* cloned;
     65  1.1  pho 
     66  1.1  pho     switch (op_version) {
     67  1.1  pho #define CLONE_OP(VER)                                                   \
     68  1.1  pho     case VER:                                                           \
     69  1.1  pho         cloned = malloc(sizeof(struct __CONCAT(fuse_operations_v,VER)));      \
     70  1.1  pho         if (!cloned)                                                    \
     71  1.1  pho             return NULL;                                                \
     72  1.1  pho         memcpy(cloned, op, sizeof(struct __CONCAT(fuse_operations_v,VER)));   \
     73  1.1  pho         return cloned
     74  1.1  pho 
     75  1.1  pho         CLONE_OP(11);
     76  1.1  pho         CLONE_OP(21);
     77  1.1  pho         CLONE_OP(22);
     78  1.1  pho         CLONE_OP(23);
     79  1.1  pho         CLONE_OP(25);
     80  1.1  pho         CLONE_OP(26);
     81  1.1  pho         CLONE_OP(28);
     82  1.1  pho         CLONE_OP(29);
     83  1.1  pho         CLONE_OP(30);
     84  1.1  pho         CLONE_OP(34);
     85  1.1  pho         CLONE_OP(35);
     86  1.1  pho         CLONE_OP(38);
     87  1.1  pho #undef CLONE_OP
     88  1.1  pho     default:
     89  1.1  pho         UNKNOWN_VERSION(op_version);
     90  1.1  pho     }
     91  1.1  pho }
     92  1.1  pho 
     93  1.1  pho struct fuse_fs*
     94  1.1  pho __fuse_fs_new(const void* op, int op_version, void* user_data) {
     95  1.1  pho     struct fuse_fs* fs;
     96  1.1  pho 
     97  1.1  pho     fs = malloc(sizeof(struct fuse_fs));
     98  1.1  pho     if (!fs)
     99  1.1  pho         err(EXIT_FAILURE, __func__);
    100  1.1  pho 
    101  1.1  pho     /* Callers aren't obliged to keep "op" valid during the lifetime
    102  1.1  pho      * of struct fuse_fs*. We must clone it now, even though it's
    103  1.1  pho      * non-trivial. */
    104  1.1  pho     fs->op = clone_op(op, op_version);
    105  1.1  pho     if (!fs->op)
    106  1.1  pho         err(EXIT_FAILURE, __func__);
    107  1.1  pho 
    108  1.1  pho     fs->op_version = op_version;
    109  1.1  pho     fs->user_data  = user_data;
    110  1.1  pho 
    111  1.1  pho     return fs;
    112  1.1  pho }
    113  1.1  pho 
    114  1.1  pho /* Clobber the context private_data with that of this filesystem
    115  1.1  pho  * layer. This function needs to be called before invoking any of
    116  1.1  pho  * operation callbacks. */
    117  1.1  pho static void
    118  1.1  pho clobber_context_user_data(struct fuse_fs* fs) {
    119  1.1  pho     fuse_get_context()->private_data = fs->user_data;
    120  1.1  pho }
    121  1.1  pho 
    122  1.1  pho /* Ugly... These are like hand-written vtables... */
    123  1.1  pho int
    124  1.1  pho fuse_fs_getattr_v27(struct fuse_fs *fs, const char *path, struct stat *buf) {
    125  1.1  pho     return fuse_fs_getattr_v30(fs, path, buf, NULL);
    126  1.1  pho }
    127  1.1  pho 
    128  1.1  pho int
    129  1.1  pho fuse_fs_getattr_v30(struct fuse_fs* fs, const char* path,
    130  1.1  pho                     struct stat* buf, struct fuse_file_info* fi) {
    131  1.1  pho     clobber_context_user_data(fs);
    132  1.1  pho     switch (fs->op_version) {
    133  1.1  pho #define CALL_OLD_GETATTR(VER)                                           \
    134  1.1  pho     case VER:                                                           \
    135  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getattr) \
    136  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getattr(path, buf); \
    137  1.1  pho         else                                                            \
    138  1.1  pho             return -ENOSYS
    139  1.1  pho         CALL_OLD_GETATTR(11);
    140  1.1  pho         CALL_OLD_GETATTR(21);
    141  1.1  pho         CALL_OLD_GETATTR(22);
    142  1.1  pho         CALL_OLD_GETATTR(23);
    143  1.1  pho         CALL_OLD_GETATTR(25);
    144  1.1  pho         CALL_OLD_GETATTR(26);
    145  1.1  pho         CALL_OLD_GETATTR(28);
    146  1.1  pho         CALL_OLD_GETATTR(29);
    147  1.1  pho #undef CALL_OLD_GETATTR
    148  1.1  pho 
    149  1.1  pho #define CALL_GETATTR(VER)                                               \
    150  1.1  pho     case VER:                                                           \
    151  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getattr) \
    152  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getattr(path, buf, fi); \
    153  1.1  pho         else                                                            \
    154  1.1  pho             return -ENOSYS
    155  1.1  pho         CALL_GETATTR(30);
    156  1.1  pho         CALL_GETATTR(34);
    157  1.2  pho         CALL_GETATTR(35);
    158  1.1  pho         CALL_GETATTR(38);
    159  1.1  pho #undef CALL_GETATTR
    160  1.1  pho     default:
    161  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    162  1.1  pho     }
    163  1.1  pho }
    164  1.1  pho 
    165  1.1  pho int
    166  1.1  pho fuse_fs_fgetattr(struct fuse_fs* fs, const char* path, struct stat* buf,
    167  1.1  pho                  struct fuse_file_info* fi) {
    168  1.1  pho     clobber_context_user_data(fs);
    169  1.1  pho     /* fgetattr() was introduced on FUSE 2.5 then disappeared on FUSE
    170  1.1  pho      * 3.0. Fall back to getattr() if it's missing. */
    171  1.1  pho     switch (fs->op_version) {
    172  1.1  pho     case 11:
    173  1.1  pho     case 21:
    174  1.1  pho     case 22:
    175  1.1  pho     case 23:
    176  1.1  pho         return fuse_fs_getattr_v30(fs, path, buf, fi);
    177  1.1  pho 
    178  1.1  pho #define CALL_FGETATTR_OR_OLD_GETATTR(VER)       \
    179  1.1  pho     case VER:                                   \
    180  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fgetattr) \
    181  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fgetattr(path, buf, fi); \
    182  1.1  pho         else if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getattr) \
    183  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getattr(path, buf); \
    184  1.1  pho         else                                                            \
    185  1.1  pho             return -ENOSYS
    186  1.1  pho         CALL_FGETATTR_OR_OLD_GETATTR(25);
    187  1.1  pho         CALL_FGETATTR_OR_OLD_GETATTR(26);
    188  1.1  pho         CALL_FGETATTR_OR_OLD_GETATTR(28);
    189  1.1  pho         CALL_FGETATTR_OR_OLD_GETATTR(29);
    190  1.1  pho #undef CALL_FGETATTR_OR_OLD_GETATTR
    191  1.1  pho 
    192  1.1  pho     case 30:
    193  1.1  pho     case 34:
    194  1.2  pho     case 35:
    195  1.1  pho     case 38:
    196  1.1  pho         return fuse_fs_getattr_v30(fs, path, buf, fi);
    197  1.1  pho     default:
    198  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    199  1.1  pho     }
    200  1.1  pho }
    201  1.1  pho 
    202  1.1  pho int
    203  1.1  pho fuse_fs_rename_v27(struct fuse_fs* fs, const char* oldpath, const char* newpath) {
    204  1.1  pho     return fuse_fs_rename_v30(fs, oldpath, newpath, 0);
    205  1.1  pho }
    206  1.1  pho 
    207  1.1  pho int
    208  1.1  pho fuse_fs_rename_v30(struct fuse_fs* fs, const char* oldpath,
    209  1.1  pho                    const char* newpath, unsigned int flags) {
    210  1.1  pho     clobber_context_user_data(fs);
    211  1.1  pho     switch (fs->op_version) {
    212  1.1  pho #define CALL_OLD_RENAME(VER)                                            \
    213  1.1  pho     case VER:                                                           \
    214  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->rename) \
    215  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->rename(oldpath, newpath); \
    216  1.1  pho         else                                                            \
    217  1.1  pho             return -ENOSYS
    218  1.1  pho         CALL_OLD_RENAME(11);
    219  1.1  pho         CALL_OLD_RENAME(21);
    220  1.1  pho         CALL_OLD_RENAME(22);
    221  1.1  pho         CALL_OLD_RENAME(23);
    222  1.1  pho         CALL_OLD_RENAME(25);
    223  1.1  pho         CALL_OLD_RENAME(26);
    224  1.1  pho         CALL_OLD_RENAME(28);
    225  1.1  pho         CALL_OLD_RENAME(29);
    226  1.1  pho #undef CALL_OLD_RENAME
    227  1.1  pho 
    228  1.1  pho #define CALL_RENAME(VER)                                                \
    229  1.1  pho     case VER:                                                           \
    230  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->rename) \
    231  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->rename(oldpath, newpath, flags); \
    232  1.1  pho         else                                                            \
    233  1.1  pho             return -ENOSYS
    234  1.1  pho         CALL_RENAME(30);
    235  1.1  pho         CALL_RENAME(34);
    236  1.2  pho         CALL_RENAME(35);
    237  1.1  pho         CALL_RENAME(38);
    238  1.1  pho #undef CALL_RENAME
    239  1.1  pho     default:
    240  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    241  1.1  pho     }
    242  1.1  pho }
    243  1.1  pho 
    244  1.1  pho int
    245  1.1  pho fuse_fs_unlink(struct fuse_fs* fs, const char* path) {
    246  1.1  pho     clobber_context_user_data(fs);
    247  1.1  pho     switch (fs->op_version) {
    248  1.1  pho #define CALL_UNLINK(VER)                                                \
    249  1.1  pho     case VER:                                                           \
    250  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->unlink) \
    251  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->unlink(path); \
    252  1.1  pho         else                                                            \
    253  1.1  pho             return -ENOSYS
    254  1.1  pho         CALL_UNLINK(11);
    255  1.1  pho         CALL_UNLINK(21);
    256  1.1  pho         CALL_UNLINK(22);
    257  1.1  pho         CALL_UNLINK(23);
    258  1.1  pho         CALL_UNLINK(25);
    259  1.1  pho         CALL_UNLINK(26);
    260  1.1  pho         CALL_UNLINK(28);
    261  1.1  pho         CALL_UNLINK(29);
    262  1.1  pho         CALL_UNLINK(30);
    263  1.1  pho         CALL_UNLINK(34);
    264  1.2  pho         CALL_UNLINK(35);
    265  1.1  pho         CALL_UNLINK(38);
    266  1.1  pho #undef CALL_UNLINK
    267  1.1  pho     default:
    268  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    269  1.1  pho     }
    270  1.1  pho }
    271  1.1  pho 
    272  1.1  pho int
    273  1.1  pho fuse_fs_rmdir(struct fuse_fs* fs, const char* path) {
    274  1.1  pho     clobber_context_user_data(fs);
    275  1.1  pho     switch (fs->op_version) {
    276  1.1  pho #define CALL_RMDIR(VER)                                                 \
    277  1.1  pho     case VER:                                                           \
    278  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->rmdir) \
    279  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->rmdir(path); \
    280  1.1  pho         else                                                            \
    281  1.1  pho             return -ENOSYS
    282  1.1  pho         CALL_RMDIR(11);
    283  1.1  pho         CALL_RMDIR(21);
    284  1.1  pho         CALL_RMDIR(22);
    285  1.1  pho         CALL_RMDIR(23);
    286  1.1  pho         CALL_RMDIR(25);
    287  1.1  pho         CALL_RMDIR(26);
    288  1.1  pho         CALL_RMDIR(28);
    289  1.1  pho         CALL_RMDIR(29);
    290  1.1  pho         CALL_RMDIR(30);
    291  1.1  pho         CALL_RMDIR(34);
    292  1.2  pho         CALL_RMDIR(35);
    293  1.1  pho         CALL_RMDIR(38);
    294  1.1  pho #undef CALL_RMDIR
    295  1.1  pho     default:
    296  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    297  1.1  pho     }
    298  1.1  pho }
    299  1.1  pho 
    300  1.1  pho int
    301  1.1  pho fuse_fs_symlink(struct fuse_fs* fs, const char* linkname, const char* path) {
    302  1.1  pho     clobber_context_user_data(fs);
    303  1.1  pho     switch (fs->op_version) {
    304  1.1  pho #define CALL_SYMLINK(VER)                                               \
    305  1.1  pho     case VER:                                                           \
    306  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->symlink) \
    307  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->symlink(linkname, path); \
    308  1.1  pho         else                                                            \
    309  1.1  pho             return -ENOSYS
    310  1.1  pho         CALL_SYMLINK(11);
    311  1.1  pho         CALL_SYMLINK(21);
    312  1.1  pho         CALL_SYMLINK(22);
    313  1.1  pho         CALL_SYMLINK(23);
    314  1.1  pho         CALL_SYMLINK(25);
    315  1.1  pho         CALL_SYMLINK(26);
    316  1.1  pho         CALL_SYMLINK(28);
    317  1.1  pho         CALL_SYMLINK(29);
    318  1.1  pho         CALL_SYMLINK(30);
    319  1.1  pho         CALL_SYMLINK(34);
    320  1.2  pho         CALL_SYMLINK(35);
    321  1.1  pho         CALL_SYMLINK(38);
    322  1.1  pho #undef CALL_SYMLINK
    323  1.1  pho     default:
    324  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    325  1.1  pho     }
    326  1.1  pho }
    327  1.1  pho 
    328  1.1  pho int
    329  1.1  pho fuse_fs_link(struct fuse_fs* fs, const char* oldpath, const char* newpath) {
    330  1.1  pho     clobber_context_user_data(fs);
    331  1.1  pho     switch (fs->op_version) {
    332  1.1  pho #define CALL_LINK(VER)                                               \
    333  1.1  pho     case VER:                                                           \
    334  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->link) \
    335  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->link(oldpath, newpath); \
    336  1.1  pho         else                                                            \
    337  1.1  pho             return -ENOSYS
    338  1.1  pho         CALL_LINK(11);
    339  1.1  pho         CALL_LINK(21);
    340  1.1  pho         CALL_LINK(22);
    341  1.1  pho         CALL_LINK(23);
    342  1.1  pho         CALL_LINK(25);
    343  1.1  pho         CALL_LINK(26);
    344  1.1  pho         CALL_LINK(28);
    345  1.1  pho         CALL_LINK(29);
    346  1.1  pho         CALL_LINK(30);
    347  1.1  pho         CALL_LINK(34);
    348  1.2  pho         CALL_LINK(35);
    349  1.1  pho         CALL_LINK(38);
    350  1.1  pho #undef CALL_LINK
    351  1.1  pho     default:
    352  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    353  1.1  pho     }
    354  1.1  pho }
    355  1.1  pho 
    356  1.1  pho int
    357  1.1  pho fuse_fs_release(struct fuse_fs* fs, const char* path, struct fuse_file_info* fi) {
    358  1.1  pho     clobber_context_user_data(fs);
    359  1.1  pho     switch (fs->op_version) {
    360  1.1  pho #define CALL_OLD_RELEASE(VER)                                           \
    361  1.1  pho     case VER:                                                           \
    362  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->release) \
    363  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->release(path, fi->flags); \
    364  1.1  pho         else                                                            \
    365  1.1  pho             return 0 /* Special case */
    366  1.1  pho         CALL_OLD_RELEASE(11);
    367  1.1  pho         CALL_OLD_RELEASE(21);
    368  1.1  pho #undef CALL_OLD_RELEASE
    369  1.1  pho 
    370  1.1  pho #define CALL_RELEASE(VER)                                               \
    371  1.1  pho     case VER:                                                           \
    372  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->release) \
    373  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->release(path, fi); \
    374  1.1  pho         else                                                            \
    375  1.1  pho             return 0 /* Special case */
    376  1.1  pho         CALL_RELEASE(22);
    377  1.1  pho         CALL_RELEASE(23);
    378  1.1  pho         CALL_RELEASE(25);
    379  1.1  pho         CALL_RELEASE(26);
    380  1.1  pho         CALL_RELEASE(28);
    381  1.1  pho         CALL_RELEASE(29);
    382  1.1  pho         CALL_RELEASE(30);
    383  1.1  pho         CALL_RELEASE(34);
    384  1.2  pho         CALL_RELEASE(35);
    385  1.1  pho         CALL_RELEASE(38);
    386  1.1  pho #undef CALL_RELEASE
    387  1.1  pho     default:
    388  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    389  1.1  pho     }
    390  1.1  pho }
    391  1.1  pho 
    392  1.1  pho int
    393  1.1  pho fuse_fs_open(struct fuse_fs* fs, const char* path, struct fuse_file_info* fi) {
    394  1.1  pho     clobber_context_user_data(fs);
    395  1.1  pho     switch (fs->op_version) {
    396  1.1  pho #define CALL_OLD_OPEN(VER)                                              \
    397  1.1  pho     case VER:                                                           \
    398  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->open) \
    399  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->open(path, fi->flags); \
    400  1.1  pho         else                                                            \
    401  1.1  pho             return 0 /* Special case */
    402  1.1  pho         CALL_OLD_OPEN(11);
    403  1.1  pho         CALL_OLD_OPEN(21);
    404  1.1  pho #undef CALL_OLD_OPEN
    405  1.1  pho 
    406  1.1  pho #define CALL_OPEN(VER)                                                  \
    407  1.1  pho     case VER:                                                           \
    408  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->open) \
    409  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->open(path, fi); \
    410  1.1  pho         else                                                            \
    411  1.1  pho             return 0 /* Special case */
    412  1.1  pho         CALL_OPEN(22);
    413  1.1  pho         CALL_OPEN(23);
    414  1.1  pho         CALL_OPEN(25);
    415  1.1  pho         CALL_OPEN(26);
    416  1.1  pho         CALL_OPEN(28);
    417  1.1  pho         CALL_OPEN(29);
    418  1.1  pho         CALL_OPEN(30);
    419  1.1  pho         CALL_OPEN(34);
    420  1.2  pho         CALL_OPEN(35);
    421  1.1  pho         CALL_OPEN(38);
    422  1.1  pho #undef CALL_OPEN
    423  1.1  pho     default:
    424  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    425  1.1  pho     }
    426  1.1  pho }
    427  1.1  pho 
    428  1.1  pho int
    429  1.1  pho fuse_fs_read(struct fuse_fs* fs, const char* path, char* buf,
    430  1.1  pho              size_t size, off_t off, struct fuse_file_info* fi) {
    431  1.1  pho     clobber_context_user_data(fs);
    432  1.1  pho     switch (fs->op_version) {
    433  1.1  pho #define CALL_OLD_READ(VER)                                              \
    434  1.1  pho     case VER:                                                           \
    435  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->read) \
    436  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->read(path, buf, size, off); \
    437  1.1  pho         else                                                            \
    438  1.1  pho             return -ENOSYS
    439  1.1  pho         CALL_OLD_READ(11);
    440  1.1  pho         CALL_OLD_READ(21);
    441  1.1  pho #undef CALL_OLD_READ
    442  1.1  pho 
    443  1.1  pho #define CALL_READ(VER)                                                  \
    444  1.1  pho     case VER:                                                           \
    445  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->read) \
    446  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->read(path, buf, size, off, fi); \
    447  1.1  pho         else                                                            \
    448  1.1  pho             return -ENOSYS
    449  1.1  pho         CALL_READ(22);
    450  1.1  pho         CALL_READ(23);
    451  1.1  pho         CALL_READ(25);
    452  1.1  pho         CALL_READ(26);
    453  1.1  pho         CALL_READ(28);
    454  1.1  pho         CALL_READ(29);
    455  1.1  pho         CALL_READ(30);
    456  1.1  pho         CALL_READ(34);
    457  1.2  pho         CALL_READ(35);
    458  1.1  pho         CALL_READ(38);
    459  1.1  pho #undef CALL_READ
    460  1.1  pho     default:
    461  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    462  1.1  pho     }
    463  1.1  pho }
    464  1.1  pho 
    465  1.1  pho int
    466  1.1  pho fuse_fs_read_buf(struct fuse_fs* fs, const char* path,
    467  1.1  pho                  struct fuse_bufvec** bufp, size_t size, off_t off,
    468  1.1  pho                  struct fuse_file_info* fi) {
    469  1.1  pho     clobber_context_user_data(fs);
    470  1.1  pho     switch (fs->op_version) {
    471  1.1  pho         /* FUSE < 2.9 didn't have read_buf(). */
    472  1.1  pho     case 11:
    473  1.1  pho     case 21:
    474  1.1  pho     case 22:
    475  1.1  pho     case 23:
    476  1.1  pho     case 25:
    477  1.1  pho     case 26:
    478  1.1  pho     case 28:
    479  1.1  pho         return -ENOSYS;
    480  1.1  pho #define CALL_READ_BUF(VER)                                              \
    481  1.1  pho     case VER:                                                           \
    482  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->read_buf) \
    483  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->read_buf(path, bufp, size, off, fi); \
    484  1.1  pho         else                                                            \
    485  1.1  pho             return -ENOSYS
    486  1.1  pho         CALL_READ_BUF(29);
    487  1.1  pho         CALL_READ_BUF(30);
    488  1.1  pho         CALL_READ_BUF(34);
    489  1.2  pho         CALL_READ_BUF(35);
    490  1.1  pho         CALL_READ_BUF(38);
    491  1.1  pho #undef CALL_READ_BUF
    492  1.1  pho     default:
    493  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    494  1.1  pho     }
    495  1.1  pho }
    496  1.1  pho 
    497  1.1  pho int
    498  1.1  pho fuse_fs_write(struct fuse_fs* fs, const char* path, const char* buf,
    499  1.1  pho               size_t size, off_t off, struct fuse_file_info* fi) {
    500  1.1  pho     clobber_context_user_data(fs);
    501  1.1  pho     switch (fs->op_version) {
    502  1.1  pho #define CALL_OLD_WRITE(VER)                                             \
    503  1.1  pho     case VER:                                                           \
    504  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->write) \
    505  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->write(path, buf, size, off); \
    506  1.1  pho         else                                                            \
    507  1.1  pho             return -ENOSYS
    508  1.1  pho         CALL_OLD_WRITE(11);
    509  1.1  pho         CALL_OLD_WRITE(21);
    510  1.1  pho #undef CALL_OLD_WRITE
    511  1.1  pho 
    512  1.1  pho #define CALL_WRITE(VER)                                                 \
    513  1.1  pho     case VER:                                                           \
    514  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->write) \
    515  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->write(path, buf, size, off, fi); \
    516  1.1  pho         else                                                            \
    517  1.1  pho             return -ENOSYS
    518  1.1  pho         CALL_WRITE(22);
    519  1.1  pho         CALL_WRITE(23);
    520  1.1  pho         CALL_WRITE(25);
    521  1.1  pho         CALL_WRITE(26);
    522  1.1  pho         CALL_WRITE(28);
    523  1.1  pho         CALL_WRITE(29);
    524  1.1  pho         CALL_WRITE(30);
    525  1.1  pho         CALL_WRITE(34);
    526  1.2  pho         CALL_WRITE(35);
    527  1.1  pho         CALL_WRITE(38);
    528  1.1  pho #undef CALL_WRITE
    529  1.1  pho     default:
    530  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    531  1.1  pho     }
    532  1.1  pho }
    533  1.1  pho 
    534  1.1  pho int
    535  1.1  pho fuse_fs_write_buf(struct fuse_fs* fs, const char* path,
    536  1.1  pho                   struct fuse_bufvec* bufp, off_t off,
    537  1.1  pho                   struct fuse_file_info* fi) {
    538  1.1  pho     clobber_context_user_data(fs);
    539  1.1  pho     switch (fs->op_version) {
    540  1.1  pho         /* FUSE < 2.9 didn't have write_buf(). */
    541  1.1  pho     case 11:
    542  1.1  pho     case 21:
    543  1.1  pho     case 22:
    544  1.1  pho     case 23:
    545  1.1  pho     case 25:
    546  1.1  pho     case 26:
    547  1.1  pho     case 28:
    548  1.1  pho         return -ENOSYS;
    549  1.1  pho #define CALL_WRITE_BUF(VER)                                             \
    550  1.1  pho     case VER:                                                           \
    551  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->write_buf) \
    552  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->write_buf(path, bufp, off, fi); \
    553  1.1  pho         else                                                            \
    554  1.1  pho             return -ENOSYS
    555  1.1  pho         CALL_WRITE_BUF(29);
    556  1.1  pho         CALL_WRITE_BUF(30);
    557  1.1  pho         CALL_WRITE_BUF(34);
    558  1.2  pho         CALL_WRITE_BUF(35);
    559  1.1  pho         CALL_WRITE_BUF(38);
    560  1.1  pho #undef CALL_WRITE_BUF
    561  1.1  pho     default:
    562  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    563  1.1  pho     }
    564  1.1  pho }
    565  1.1  pho 
    566  1.1  pho int
    567  1.1  pho fuse_fs_fsync(struct fuse_fs* fs, const char* path, int datasync, struct fuse_file_info* fi) {
    568  1.1  pho     clobber_context_user_data(fs);
    569  1.1  pho     switch (fs->op_version) {
    570  1.1  pho #define CALL_OLD_FSYNC(VER)                                             \
    571  1.1  pho     case VER:                                                           \
    572  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fsync) \
    573  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fsync(path, datasync); \
    574  1.1  pho         else                                                            \
    575  1.1  pho             return -ENOSYS
    576  1.1  pho         CALL_OLD_FSYNC(11);
    577  1.1  pho         CALL_OLD_FSYNC(21);
    578  1.1  pho #undef CALL_OLD_FSYNC
    579  1.1  pho 
    580  1.1  pho #define CALL_FSYNC(VER)                                                 \
    581  1.1  pho     case VER:                                                           \
    582  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fsync) \
    583  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fsync(path, datasync, fi); \
    584  1.1  pho         else                                                            \
    585  1.1  pho             return -ENOSYS
    586  1.1  pho         CALL_FSYNC(22);
    587  1.1  pho         CALL_FSYNC(23);
    588  1.1  pho         CALL_FSYNC(25);
    589  1.1  pho         CALL_FSYNC(26);
    590  1.1  pho         CALL_FSYNC(28);
    591  1.1  pho         CALL_FSYNC(29);
    592  1.1  pho         CALL_FSYNC(30);
    593  1.1  pho         CALL_FSYNC(34);
    594  1.2  pho         CALL_FSYNC(35);
    595  1.1  pho         CALL_FSYNC(38);
    596  1.1  pho #undef CALL_FSYNC
    597  1.1  pho     default:
    598  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    599  1.1  pho     }
    600  1.1  pho }
    601  1.1  pho 
    602  1.1  pho int
    603  1.1  pho fuse_fs_flush(struct fuse_fs* fs, const char* path, struct fuse_file_info* fi) {
    604  1.1  pho     clobber_context_user_data(fs);
    605  1.1  pho     /* flush() appeared on FUSE 2.1 and its prototype was changed on
    606  1.1  pho      * 2.2. */
    607  1.1  pho     switch (fs->op_version) {
    608  1.1  pho     case 11:
    609  1.1  pho         return -ENOSYS;
    610  1.1  pho     case 21:
    611  1.1  pho         if (((const struct fuse_operations_v21 *)fs->op)->flush)
    612  1.1  pho             return ((const struct fuse_operations_v21 *)fs->op)->flush(path);
    613  1.1  pho         else
    614  1.1  pho             return -ENOSYS;
    615  1.1  pho 
    616  1.1  pho #define CALL_FLUSH(VER)                                                 \
    617  1.1  pho     case VER:                                                           \
    618  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->flush) \
    619  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->flush(path, fi); \
    620  1.1  pho         else                                                            \
    621  1.1  pho             return -ENOSYS
    622  1.1  pho         CALL_FLUSH(22);
    623  1.1  pho         CALL_FLUSH(23);
    624  1.1  pho         CALL_FLUSH(25);
    625  1.1  pho         CALL_FLUSH(26);
    626  1.1  pho         CALL_FLUSH(28);
    627  1.1  pho         CALL_FLUSH(29);
    628  1.1  pho         CALL_FLUSH(30);
    629  1.1  pho         CALL_FLUSH(34);
    630  1.2  pho         CALL_FLUSH(35);
    631  1.1  pho         CALL_FLUSH(38);
    632  1.1  pho #undef CALL_FLUSH
    633  1.1  pho     default:
    634  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    635  1.1  pho     }
    636  1.1  pho }
    637  1.1  pho 
    638  1.1  pho static void
    639  1.1  pho zero_statvfs(struct statvfs* dst) {
    640  1.1  pho     dst->f_bsize   = 0;
    641  1.1  pho     dst->f_frsize  = 0;
    642  1.1  pho     dst->f_blocks  = 0;
    643  1.1  pho     dst->f_bfree   = 0;
    644  1.1  pho     dst->f_bavail  = 0;
    645  1.1  pho     dst->f_files   = 0;
    646  1.1  pho     dst->f_ffree   = 0;
    647  1.1  pho     dst->f_fresvd  = 0;
    648  1.1  pho }
    649  1.1  pho static void
    650  1.1  pho fuse_statfs_to_statvfs(struct statvfs* dst, const struct fuse_statfs* src) {
    651  1.1  pho     dst->f_bsize   = (unsigned long)src->block_size;
    652  1.1  pho     dst->f_frsize  = (unsigned long)src->block_size; /* Dunno if this is correct. */
    653  1.1  pho     dst->f_blocks  = (fsblkcnt_t)src->blocks;
    654  1.1  pho     dst->f_bfree   = (fsblkcnt_t)src->blocks_free;
    655  1.1  pho     dst->f_bavail  = (fsblkcnt_t)src->blocks_free;
    656  1.1  pho     dst->f_files   = (fsfilcnt_t)src->files;
    657  1.1  pho     dst->f_ffree   = (fsfilcnt_t)src->files_free;
    658  1.1  pho }
    659  1.1  pho static void
    660  1.1  pho linux_statfs_to_statvfs(struct statvfs* dst, const struct statfs* src) {
    661  1.1  pho     dst->f_bsize   = (unsigned long)src->f_bsize;
    662  1.1  pho     dst->f_frsize  = (unsigned long)src->f_bsize; /* Dunno if this is correct. */
    663  1.1  pho     dst->f_blocks  = src->f_blocks;
    664  1.1  pho     dst->f_bfree   = src->f_bfree;
    665  1.1  pho     dst->f_bavail  = src->f_bavail;
    666  1.1  pho     dst->f_files   = src->f_files;
    667  1.1  pho     dst->f_ffree   = src->f_ffree;
    668  1.1  pho }
    669  1.1  pho int
    670  1.1  pho fuse_fs_statfs(struct fuse_fs* fs, const char* path, struct statvfs* buf) {
    671  1.1  pho     clobber_context_user_data(fs);
    672  1.1  pho 
    673  1.1  pho     zero_statvfs(buf);
    674  1.1  pho 
    675  1.1  pho     switch (fs->op_version) {
    676  1.1  pho         /* FUSE < 2.1 used "struct fuse_statfs". */
    677  1.1  pho     case 11:
    678  1.1  pho         if (((const struct fuse_operations_v11*)fs->op)->statfs) {
    679  1.1  pho             struct fuse_statfs statfs_v11;
    680  1.1  pho             int ret;
    681  1.1  pho 
    682  1.1  pho             ret = ((const struct fuse_operations_v11*)fs->op)->statfs(path, &statfs_v11);
    683  1.1  pho             if (ret == 0)
    684  1.1  pho                 fuse_statfs_to_statvfs(buf, &statfs_v11);
    685  1.1  pho 
    686  1.1  pho             return ret;
    687  1.1  pho         }
    688  1.1  pho         else
    689  1.1  pho             return 0; /* Special case */
    690  1.1  pho 
    691  1.1  pho         /* FUSE >= 2.2 && < 2.5 used Linux-specific "struct
    692  1.1  pho          * statfs". */
    693  1.1  pho #define CALL_LINUX_STATFS(VER)                                          \
    694  1.1  pho     case VER:                                                           \
    695  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->statfs) { \
    696  1.1  pho             struct statfs statfs_v22;                                   \
    697  1.1  pho             int ret;                                                    \
    698  1.1  pho                                                                         \
    699  1.1  pho             ret = ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->statfs(path, &statfs_v22); \
    700  1.1  pho             if (ret == 0)                                               \
    701  1.1  pho                 linux_statfs_to_statvfs(buf, &statfs_v22);              \
    702  1.1  pho                                                                         \
    703  1.1  pho             return ret;                                                 \
    704  1.1  pho         }                                                               \
    705  1.1  pho         else                                                            \
    706  1.1  pho             return 0; /* Special case */
    707  1.1  pho         CALL_LINUX_STATFS(22);
    708  1.1  pho         CALL_LINUX_STATFS(23);
    709  1.1  pho #undef CALL_STATFS
    710  1.1  pho 
    711  1.1  pho         /* FUSE >= 2.5 use struct statvfs. */
    712  1.1  pho #define CALL_STATFS(VER)                                                \
    713  1.1  pho     case VER:                                                           \
    714  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->statfs) \
    715  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->statfs(path, buf); \
    716  1.1  pho         else                                                            \
    717  1.1  pho             return 0; /* Special case */
    718  1.1  pho         CALL_STATFS(25);
    719  1.1  pho         CALL_STATFS(26);
    720  1.1  pho         CALL_STATFS(28);
    721  1.1  pho         CALL_STATFS(29);
    722  1.1  pho         CALL_STATFS(30);
    723  1.1  pho         CALL_STATFS(34);
    724  1.2  pho         CALL_STATFS(35);
    725  1.1  pho         CALL_STATFS(38);
    726  1.1  pho #undef CALL_STATFS
    727  1.1  pho     default:
    728  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    729  1.1  pho     }
    730  1.1  pho }
    731  1.1  pho 
    732  1.1  pho int
    733  1.1  pho fuse_fs_opendir(struct fuse_fs* fs, const char* path, struct fuse_file_info* fi) {
    734  1.1  pho     clobber_context_user_data(fs);
    735  1.1  pho     switch (fs->op_version) {
    736  1.1  pho         /* FUSE < 2.3 didn't have opendir() and used to read
    737  1.1  pho          * directories without opening them. */
    738  1.1  pho     case 11:
    739  1.1  pho     case 21:
    740  1.1  pho     case 22:
    741  1.1  pho         return 0; /* Special case */
    742  1.1  pho 
    743  1.1  pho #define CALL_OPENDIR(VER)                                               \
    744  1.1  pho     case VER:                                                           \
    745  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->opendir) \
    746  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->opendir(path, fi); \
    747  1.1  pho         else                                                            \
    748  1.1  pho             return 0 /* Special case */
    749  1.1  pho         CALL_OPENDIR(23);
    750  1.1  pho         CALL_OPENDIR(25);
    751  1.1  pho         CALL_OPENDIR(26);
    752  1.1  pho         CALL_OPENDIR(28);
    753  1.1  pho         CALL_OPENDIR(29);
    754  1.1  pho         CALL_OPENDIR(30);
    755  1.1  pho         CALL_OPENDIR(34);
    756  1.2  pho         CALL_OPENDIR(35);
    757  1.1  pho         CALL_OPENDIR(38);
    758  1.1  pho #undef CALL_OPENDIR
    759  1.1  pho     default:
    760  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    761  1.1  pho     }
    762  1.1  pho }
    763  1.1  pho 
    764  1.1  pho /* ===================================
    765  1.1  pho  *     -=- The readdir Madness -=-
    766  1.1  pho  *     Juggling with Nested Shims
    767  1.1  pho  * =================================== */
    768  1.1  pho 
    769  1.1  pho struct fuse_fill_dir_v23_shim {
    770  1.1  pho     void*               dirh;
    771  1.1  pho     fuse_fill_dir_t_v23 fill_dir_v23;
    772  1.1  pho };
    773  1.1  pho 
    774  1.1  pho /* Translate dirent DT_* to mode_t. Needed by shim functions. */
    775  1.1  pho static mode_t
    776  1.1  pho dt_to_mode(int dt) {
    777  1.1  pho     switch (dt) {
    778  1.1  pho     case DT_UNKNOWN: return 0;
    779  1.1  pho     case DT_FIFO:    return S_IFIFO;
    780  1.1  pho     case DT_CHR:     return S_IFCHR;
    781  1.1  pho     case DT_DIR:     return S_IFCHR;
    782  1.1  pho     case DT_BLK:     return S_IFBLK;
    783  1.1  pho     case DT_REG:     return S_IFREG;
    784  1.1  pho     case DT_LNK:     return S_IFLNK;
    785  1.1  pho     case DT_SOCK:    return S_IFSOCK;
    786  1.1  pho     case DT_WHT:     return S_IFWHT;
    787  1.1  pho     default:
    788  1.1  pho         errx(EXIT_FAILURE, "%s: unknown dirent type: %d",
    789  1.1  pho              __func__, dt);
    790  1.1  pho     }
    791  1.1  pho }
    792  1.1  pho 
    793  1.1  pho /* This is a shim function that satisfies the type of
    794  1.1  pho  * fuse_dirfil_t_v11 but calls fuse_fill_dir_v23. */
    795  1.1  pho static int
    796  1.1  pho fuse_dirfil_v11_to_fill_dir_v23(fuse_dirh_t handle, const char* name, int type) {
    797  1.1  pho     struct fuse_fill_dir_v23_shim* shim = handle;
    798  1.1  pho     struct stat stbuf;
    799  1.1  pho     int res; /* 1 or 0 */
    800  1.1  pho 
    801  1.1  pho     memset(&stbuf, 0, sizeof(stbuf));
    802  1.1  pho     stbuf.st_mode = dt_to_mode(type);
    803  1.1  pho 
    804  1.1  pho     res = shim->fill_dir_v23(shim->dirh, name, &stbuf, 0);
    805  1.1  pho     return res ? -ENOMEM : 0;
    806  1.1  pho }
    807  1.1  pho 
    808  1.1  pho /* This is a shim function that satisfies the type of
    809  1.1  pho  * fuse_dirfil_t_v22 but calls fuse_fill_dir_v23. */
    810  1.1  pho static int
    811  1.1  pho fuse_dirfil_v22_to_fill_dir_v23(fuse_dirh_t handle, const char* name, int type, ino_t ino) {
    812  1.1  pho     struct fuse_fill_dir_v23_shim* shim = handle;
    813  1.1  pho     struct stat stbuf;
    814  1.1  pho     int res; /* 1 or 0 */
    815  1.1  pho 
    816  1.1  pho     memset(&stbuf, 0, sizeof(stbuf));
    817  1.1  pho     stbuf.st_mode = dt_to_mode(type);
    818  1.1  pho     stbuf.st_ino  = ino;
    819  1.1  pho 
    820  1.1  pho     res = shim->fill_dir_v23(shim->dirh, name, &stbuf, 0);
    821  1.1  pho     return res ? -ENOMEM : 0;
    822  1.1  pho }
    823  1.1  pho 
    824  1.1  pho struct fuse_fill_dir_v30_shim {
    825  1.1  pho     void*               dirh;
    826  1.1  pho     fuse_fill_dir_t_v30 fill_dir_v30;
    827  1.1  pho };
    828  1.1  pho 
    829  1.1  pho /* This is a shim function that satisfies the type of
    830  1.1  pho  * fuse_fill_dir_v23 but calls fuse_fill_dir_v30. */
    831  1.1  pho static int
    832  1.1  pho fuse_fill_dir_v23_to_v30(void* buf, const char* name,
    833  1.1  pho                          const struct stat* stat, off_t off) {
    834  1.1  pho 
    835  1.1  pho     struct fuse_fill_dir_v30_shim* shim = buf;
    836  1.1  pho 
    837  1.1  pho     return shim->fill_dir_v30(shim->dirh, name, stat, off, (enum fuse_fill_dir_flags)0);
    838  1.1  pho }
    839  1.1  pho 
    840  1.1  pho int
    841  1.1  pho fuse_fs_readdir_v27(struct fuse_fs* fs, const char* path, void* buf,
    842  1.1  pho                     fuse_fill_dir_t_v23 filler, off_t off,
    843  1.1  pho                     struct fuse_file_info* fi) {
    844  1.1  pho 
    845  1.1  pho     struct fuse_fill_dir_v23_shim v23_shim;
    846  1.1  pho 
    847  1.1  pho     v23_shim.dirh         = buf;
    848  1.1  pho     v23_shim.fill_dir_v23 = filler;
    849  1.1  pho 
    850  1.1  pho     clobber_context_user_data(fs);
    851  1.1  pho 
    852  1.1  pho     switch (fs->op_version) {
    853  1.1  pho         /* FUSE < 2.2 had getdir() that used fuse_dirfil_t_v11. */
    854  1.1  pho #define CALL_GETDIR_V11(VER)                                        \
    855  1.1  pho     case VER:                                                       \
    856  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getdir) \
    857  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getdir(path, &v23_shim, fuse_dirfil_v11_to_fill_dir_v23); \
    858  1.1  pho         else                                                            \
    859  1.1  pho             return -ENOSYS
    860  1.1  pho         CALL_GETDIR_V11(11);
    861  1.1  pho         CALL_GETDIR_V11(21);
    862  1.1  pho #undef CALL_GETDIR_V11
    863  1.1  pho 
    864  1.1  pho         /* FUSE 2.2 had getdir() that used fuse_dirfil_t_v22 but
    865  1.1  pho          * didn't have readdir(). */
    866  1.1  pho     case 22:
    867  1.1  pho         if (((const struct fuse_operations_v22*)fs->op)->getdir)
    868  1.1  pho             return ((const struct fuse_operations_v22*)fs->op)->getdir(path, &v23_shim, fuse_dirfil_v22_to_fill_dir_v23);
    869  1.1  pho         else
    870  1.1  pho             return -ENOSYS;
    871  1.1  pho 
    872  1.1  pho         /* FUSE 2.3 introduced readdir() but still had getdir() as
    873  1.1  pho          * a deprecated operation. It had been this way until FUSE 3.0
    874  1.1  pho          * finally removed getdir() and also changed the prototype of
    875  1.1  pho          * readdir(). */
    876  1.1  pho #define CALL_READDIR_OR_GETDIR(VER)                                     \
    877  1.1  pho     case VER:                                                           \
    878  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->readdir) \
    879  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->readdir(path, buf, filler, off, fi); \
    880  1.1  pho         else if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getdir) \
    881  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getdir(path, &v23_shim, fuse_dirfil_v22_to_fill_dir_v23); \
    882  1.1  pho         else                                                            \
    883  1.1  pho             return -ENOSYS
    884  1.1  pho         CALL_READDIR_OR_GETDIR(23);
    885  1.1  pho         CALL_READDIR_OR_GETDIR(25);
    886  1.1  pho         CALL_READDIR_OR_GETDIR(26);
    887  1.1  pho         CALL_READDIR_OR_GETDIR(28);
    888  1.1  pho         CALL_READDIR_OR_GETDIR(29);
    889  1.1  pho #undef CALL_READDIR_OR_GETDIR
    890  1.1  pho 
    891  1.1  pho     default:
    892  1.1  pho         /* FUSE >= 3.0 filesystems will never call this function. We
    893  1.1  pho          * can safely ignore them here. */
    894  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    895  1.1  pho     }
    896  1.1  pho }
    897  1.1  pho 
    898  1.1  pho int
    899  1.1  pho fuse_fs_readdir_v30(struct fuse_fs* fs, const char* path, void* buf,
    900  1.1  pho                     fuse_fill_dir_t_v30 filler, off_t off,
    901  1.1  pho                     struct fuse_file_info* fi, enum fuse_readdir_flags flags) {
    902  1.1  pho     clobber_context_user_data(fs);
    903  1.1  pho 
    904  1.1  pho     if (fs->op_version < 30) {
    905  1.1  pho         struct fuse_fill_dir_v30_shim v30_shim;
    906  1.1  pho 
    907  1.1  pho         v30_shim.dirh         = buf;
    908  1.1  pho         v30_shim.fill_dir_v30 = filler;
    909  1.1  pho 
    910  1.1  pho         return fuse_fs_readdir_v27(fs, path, &v30_shim, fuse_fill_dir_v23_to_v30, off, fi);
    911  1.1  pho     }
    912  1.1  pho     else {
    913  1.1  pho         switch (fs->op_version) {
    914  1.1  pho #define CALL_READDIR(VER)                                               \
    915  1.1  pho             case VER:                                                   \
    916  1.1  pho                 if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->readdir) \
    917  1.1  pho                     return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->readdir(path, buf, filler, off, fi, flags); \
    918  1.1  pho                 else                                                    \
    919  1.1  pho                     return -ENOSYS
    920  1.1  pho             CALL_READDIR(30);
    921  1.1  pho             CALL_READDIR(34);
    922  1.2  pho             CALL_READDIR(35);
    923  1.1  pho             CALL_READDIR(38);
    924  1.1  pho #undef CALL_READDIR
    925  1.1  pho         default:
    926  1.1  pho             UNKNOWN_VERSION(fs->op_version);
    927  1.1  pho         }
    928  1.1  pho     }
    929  1.1  pho }
    930  1.1  pho 
    931  1.1  pho /* ==============================
    932  1.1  pho  *   The End of readdir Madness
    933  1.1  pho  * ============================== */
    934  1.1  pho 
    935  1.1  pho int
    936  1.1  pho fuse_fs_fsyncdir(struct fuse_fs* fs, const char* path, int datasync, struct fuse_file_info* fi) {
    937  1.1  pho     clobber_context_user_data(fs);
    938  1.1  pho     /* fsyncdir() appeared on FUSE 2.3. */
    939  1.1  pho     switch (fs->op_version) {
    940  1.1  pho     case 11:
    941  1.1  pho     case 21:
    942  1.1  pho     case 22:
    943  1.1  pho         return -ENOSYS;
    944  1.1  pho 
    945  1.1  pho #define CALL_FSYNCDIR(VER)                                              \
    946  1.1  pho     case VER:                                                           \
    947  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fsyncdir) \
    948  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fsyncdir(path, datasync, fi); \
    949  1.1  pho         else                                                            \
    950  1.1  pho             return -ENOSYS
    951  1.1  pho         CALL_FSYNCDIR(23);
    952  1.1  pho         CALL_FSYNCDIR(25);
    953  1.1  pho         CALL_FSYNCDIR(26);
    954  1.1  pho         CALL_FSYNCDIR(28);
    955  1.1  pho         CALL_FSYNCDIR(29);
    956  1.1  pho         CALL_FSYNCDIR(30);
    957  1.1  pho         CALL_FSYNCDIR(34);
    958  1.2  pho         CALL_FSYNCDIR(35);
    959  1.1  pho         CALL_FSYNCDIR(38);
    960  1.1  pho #undef CALL_FSYNCDIR
    961  1.1  pho     default:
    962  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    963  1.1  pho     }
    964  1.1  pho }
    965  1.1  pho 
    966  1.1  pho int
    967  1.1  pho fuse_fs_releasedir(struct fuse_fs* fs, const char* path, struct fuse_file_info* fi) {
    968  1.1  pho     clobber_context_user_data(fs);
    969  1.1  pho     switch (fs->op_version) {
    970  1.1  pho         /* FUSE < 2.3 didn't have releasedir() and was reading
    971  1.1  pho          * directories without opening them. */
    972  1.1  pho     case 11:
    973  1.1  pho     case 21:
    974  1.1  pho     case 22:
    975  1.1  pho         return 0; /* Special case */
    976  1.1  pho 
    977  1.1  pho #define CALL_RELEASEDIR(VER)                                            \
    978  1.1  pho     case VER:                                                           \
    979  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->releasedir) \
    980  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->releasedir(path, fi); \
    981  1.1  pho         else                                                            \
    982  1.1  pho             return 0 /* Special case */
    983  1.1  pho         CALL_RELEASEDIR(23);
    984  1.1  pho         CALL_RELEASEDIR(25);
    985  1.1  pho         CALL_RELEASEDIR(26);
    986  1.1  pho         CALL_RELEASEDIR(28);
    987  1.1  pho         CALL_RELEASEDIR(29);
    988  1.1  pho         CALL_RELEASEDIR(30);
    989  1.1  pho         CALL_RELEASEDIR(34);
    990  1.2  pho         CALL_RELEASEDIR(35);
    991  1.1  pho         CALL_RELEASEDIR(38);
    992  1.1  pho #undef CALL_RELEASEDIR
    993  1.1  pho     default:
    994  1.1  pho         UNKNOWN_VERSION(fs->op_version);
    995  1.1  pho     }
    996  1.1  pho }
    997  1.1  pho 
    998  1.1  pho int
    999  1.1  pho fuse_fs_create(struct fuse_fs* fs, const char* path, mode_t mode, struct fuse_file_info* fi) {
   1000  1.1  pho     clobber_context_user_data(fs);
   1001  1.1  pho     switch (fs->op_version) {
   1002  1.1  pho         /* FUSE < 2.5 didn't have create(). */
   1003  1.1  pho     case 11:
   1004  1.1  pho     case 21:
   1005  1.1  pho     case 22:
   1006  1.1  pho     case 23:
   1007  1.1  pho         return -ENOSYS;
   1008  1.1  pho 
   1009  1.1  pho #define CALL_CREATE(VER)                                                \
   1010  1.1  pho     case VER:                                                           \
   1011  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->create) \
   1012  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->create(path, mode, fi); \
   1013  1.1  pho         else                                                            \
   1014  1.1  pho             return -ENOSYS
   1015  1.1  pho         CALL_CREATE(25);
   1016  1.1  pho         CALL_CREATE(26);
   1017  1.1  pho         CALL_CREATE(28);
   1018  1.1  pho         CALL_CREATE(29);
   1019  1.1  pho         CALL_CREATE(30);
   1020  1.1  pho         CALL_CREATE(34);
   1021  1.2  pho         CALL_CREATE(35);
   1022  1.1  pho         CALL_CREATE(38);
   1023  1.1  pho #undef CALL_CREATE
   1024  1.1  pho     default:
   1025  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1026  1.1  pho     }
   1027  1.1  pho }
   1028  1.1  pho 
   1029  1.1  pho int
   1030  1.1  pho fuse_fs_lock(struct fuse_fs* fs, const char* path, struct fuse_file_info* fi,
   1031  1.1  pho              int cmd, struct flock* lock) {
   1032  1.1  pho     clobber_context_user_data(fs);
   1033  1.1  pho     /* locK() appeared on FUSE 2.6. */
   1034  1.1  pho     switch (fs->op_version) {
   1035  1.1  pho     case 11:
   1036  1.1  pho     case 21:
   1037  1.1  pho     case 22:
   1038  1.1  pho     case 23:
   1039  1.1  pho     case 25:
   1040  1.1  pho         return -ENOSYS;
   1041  1.1  pho 
   1042  1.1  pho #define CALL_LOCK(VER)                                                  \
   1043  1.1  pho     case VER:                                                           \
   1044  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->lock) \
   1045  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->lock(path, fi, cmd, lock); \
   1046  1.1  pho         else                                                            \
   1047  1.1  pho             return -ENOSYS
   1048  1.1  pho         CALL_LOCK(26);
   1049  1.1  pho         CALL_LOCK(28);
   1050  1.1  pho         CALL_LOCK(29);
   1051  1.1  pho         CALL_LOCK(30);
   1052  1.1  pho         CALL_LOCK(34);
   1053  1.2  pho         CALL_LOCK(35);
   1054  1.1  pho         CALL_LOCK(38);
   1055  1.1  pho #undef CALL_LOCK
   1056  1.1  pho     default:
   1057  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1058  1.1  pho     }
   1059  1.1  pho }
   1060  1.1  pho 
   1061  1.1  pho int
   1062  1.1  pho fuse_fs_flock(struct fuse_fs* fs, const char* path, struct fuse_file_info* fi, int op) {
   1063  1.1  pho     clobber_context_user_data(fs);
   1064  1.1  pho     /* flocK() appeared on FUSE 2.9. */
   1065  1.1  pho     switch (fs->op_version) {
   1066  1.1  pho     case 11:
   1067  1.1  pho     case 21:
   1068  1.1  pho     case 22:
   1069  1.1  pho     case 23:
   1070  1.1  pho     case 25:
   1071  1.1  pho     case 26:
   1072  1.1  pho     case 28:
   1073  1.1  pho         return -ENOSYS;
   1074  1.1  pho 
   1075  1.1  pho #define CALL_FLOCK(VER)                                                 \
   1076  1.1  pho     case VER:                                                           \
   1077  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->flock) \
   1078  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->flock(path, fi, op); \
   1079  1.1  pho         else                                                            \
   1080  1.1  pho             return -ENOSYS
   1081  1.1  pho         CALL_FLOCK(29);
   1082  1.1  pho         CALL_FLOCK(30);
   1083  1.1  pho         CALL_FLOCK(34);
   1084  1.2  pho         CALL_FLOCK(35);
   1085  1.1  pho         CALL_FLOCK(38);
   1086  1.1  pho #undef CALL_FLOCK
   1087  1.1  pho     default:
   1088  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1089  1.1  pho     }
   1090  1.1  pho }
   1091  1.1  pho 
   1092  1.1  pho int
   1093  1.1  pho fuse_fs_chmod_v27(struct fuse_fs *fs, const char *path, mode_t mode) {
   1094  1.1  pho     return fuse_fs_chmod_v30(fs, path, mode, NULL);
   1095  1.1  pho }
   1096  1.1  pho 
   1097  1.1  pho int
   1098  1.1  pho fuse_fs_chmod_v30(struct fuse_fs* fs, const char* path,
   1099  1.1  pho                   mode_t mode, struct fuse_file_info* fi) {
   1100  1.1  pho     clobber_context_user_data(fs);
   1101  1.1  pho     switch (fs->op_version) {
   1102  1.1  pho #define CALL_OLD_CHMOD(VER)                                             \
   1103  1.1  pho     case VER:                                                           \
   1104  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->chmod) \
   1105  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->chmod(path, mode); \
   1106  1.1  pho         else                                                            \
   1107  1.1  pho             return -ENOSYS
   1108  1.1  pho         CALL_OLD_CHMOD(11);
   1109  1.1  pho         CALL_OLD_CHMOD(21);
   1110  1.1  pho         CALL_OLD_CHMOD(22);
   1111  1.1  pho         CALL_OLD_CHMOD(23);
   1112  1.1  pho         CALL_OLD_CHMOD(25);
   1113  1.1  pho         CALL_OLD_CHMOD(26);
   1114  1.1  pho         CALL_OLD_CHMOD(28);
   1115  1.1  pho         CALL_OLD_CHMOD(29);
   1116  1.1  pho #undef CALL_OLD_CHMOD
   1117  1.1  pho 
   1118  1.1  pho #define CALL_CHMOD(VER)                                                 \
   1119  1.1  pho     case VER:                                                           \
   1120  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->chmod) \
   1121  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->chmod(path, mode, fi); \
   1122  1.1  pho         else                                                            \
   1123  1.1  pho             return -ENOSYS
   1124  1.1  pho         CALL_CHMOD(30);
   1125  1.1  pho         CALL_CHMOD(34);
   1126  1.2  pho         CALL_CHMOD(35);
   1127  1.1  pho         CALL_CHMOD(38);
   1128  1.1  pho #undef CALL_CHMOD
   1129  1.1  pho     default:
   1130  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1131  1.1  pho     }
   1132  1.1  pho }
   1133  1.1  pho 
   1134  1.1  pho int fuse_fs_chown_v27(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid) {
   1135  1.1  pho     return fuse_fs_chown_v30(fs, path, uid, gid, NULL);
   1136  1.1  pho }
   1137  1.1  pho 
   1138  1.1  pho int
   1139  1.1  pho fuse_fs_chown_v30(struct fuse_fs* fs, const char* path,
   1140  1.1  pho                   uid_t uid, gid_t gid, struct fuse_file_info* fi) {
   1141  1.1  pho     clobber_context_user_data(fs);
   1142  1.1  pho     switch (fs->op_version) {
   1143  1.1  pho #define CALL_OLD_CHOWN(VER)                                             \
   1144  1.1  pho     case VER:                                                           \
   1145  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->chown) \
   1146  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->chown(path, uid, gid); \
   1147  1.1  pho         else                                                            \
   1148  1.1  pho             return -ENOSYS
   1149  1.1  pho         CALL_OLD_CHOWN(11);
   1150  1.1  pho         CALL_OLD_CHOWN(21);
   1151  1.1  pho         CALL_OLD_CHOWN(22);
   1152  1.1  pho         CALL_OLD_CHOWN(23);
   1153  1.1  pho         CALL_OLD_CHOWN(25);
   1154  1.1  pho         CALL_OLD_CHOWN(26);
   1155  1.1  pho         CALL_OLD_CHOWN(28);
   1156  1.1  pho         CALL_OLD_CHOWN(29);
   1157  1.1  pho #undef CALL_OLD_CHOWN
   1158  1.1  pho 
   1159  1.1  pho #define CALL_CHOWN(VER)                         \
   1160  1.1  pho     case VER:                                   \
   1161  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->chown) \
   1162  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->chown(path, uid, gid, fi); \
   1163  1.1  pho         else                                                            \
   1164  1.1  pho             return -ENOSYS
   1165  1.1  pho         CALL_CHOWN(30);
   1166  1.1  pho         CALL_CHOWN(34);
   1167  1.2  pho         CALL_CHOWN(35);
   1168  1.1  pho         CALL_CHOWN(38);
   1169  1.1  pho #undef CALL_CHOWN
   1170  1.1  pho     default:
   1171  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1172  1.1  pho     }
   1173  1.1  pho }
   1174  1.1  pho 
   1175  1.1  pho int fuse_fs_truncate_v27(struct fuse_fs *fs, const char *path, off_t size) {
   1176  1.1  pho     return fuse_fs_truncate_v30(fs, path, size, NULL);
   1177  1.1  pho }
   1178  1.1  pho 
   1179  1.1  pho int
   1180  1.1  pho fuse_fs_truncate_v30(struct fuse_fs* fs, const char* path, off_t size, struct fuse_file_info* fi) {
   1181  1.1  pho     clobber_context_user_data(fs);
   1182  1.1  pho     switch (fs->op_version) {
   1183  1.1  pho #define CALL_OLD_TRUNCATE(VER)                                          \
   1184  1.1  pho     case VER:                                                           \
   1185  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate) \
   1186  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate(path, size); \
   1187  1.1  pho         else                                                            \
   1188  1.1  pho             return -ENOSYS
   1189  1.1  pho         CALL_OLD_TRUNCATE(11);
   1190  1.1  pho         CALL_OLD_TRUNCATE(21);
   1191  1.1  pho         CALL_OLD_TRUNCATE(22);
   1192  1.1  pho         CALL_OLD_TRUNCATE(23);
   1193  1.1  pho         CALL_OLD_TRUNCATE(25);
   1194  1.1  pho         CALL_OLD_TRUNCATE(26);
   1195  1.1  pho         CALL_OLD_TRUNCATE(28);
   1196  1.1  pho         CALL_OLD_TRUNCATE(29);
   1197  1.1  pho #undef CALL_OLD_TRUNCATE
   1198  1.1  pho 
   1199  1.1  pho #define CALL_TRUNCATE(VER)                      \
   1200  1.1  pho     case VER:                                   \
   1201  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate) \
   1202  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate(path, size, fi); \
   1203  1.1  pho         else                                                            \
   1204  1.1  pho             return -ENOSYS
   1205  1.1  pho         CALL_TRUNCATE(30);
   1206  1.1  pho         CALL_TRUNCATE(34);
   1207  1.2  pho         CALL_TRUNCATE(35);
   1208  1.1  pho         CALL_TRUNCATE(38);
   1209  1.1  pho #undef CALL_TRUNCATE
   1210  1.1  pho     default:
   1211  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1212  1.1  pho     }
   1213  1.1  pho }
   1214  1.1  pho 
   1215  1.1  pho int
   1216  1.1  pho fuse_fs_ftruncate(struct fuse_fs* fs, const char* path, off_t size, struct fuse_file_info* fi) {
   1217  1.1  pho     clobber_context_user_data(fs);
   1218  1.1  pho     switch (fs->op_version) {
   1219  1.1  pho         /* FUSE < 2.5 didn't have ftruncate(). Always fall back to
   1220  1.1  pho          * truncate(). */
   1221  1.1  pho #define CALL_OLD_TRUNCATE(VER)                                          \
   1222  1.1  pho     case VER:                                                           \
   1223  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate) \
   1224  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate(path, size); \
   1225  1.1  pho         else                                                            \
   1226  1.1  pho             return -ENOSYS
   1227  1.1  pho         CALL_OLD_TRUNCATE(11);
   1228  1.1  pho         CALL_OLD_TRUNCATE(21);
   1229  1.1  pho         CALL_OLD_TRUNCATE(22);
   1230  1.1  pho         CALL_OLD_TRUNCATE(23);
   1231  1.1  pho #undef CALL_OLD_TRUNCATE
   1232  1.1  pho 
   1233  1.1  pho         /* ftruncate() appeared on FUSE 2.5 and then disappeared on
   1234  1.1  pho          * FUSE 3.0. Call it if it exists, or fall back to truncate()
   1235  1.1  pho          * otherwise. */
   1236  1.1  pho #define CALL_FTRUNCATE_OR_TRUNCATE(VER)                                 \
   1237  1.1  pho     case VER:                                                           \
   1238  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->ftruncate) \
   1239  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->ftruncate(path, size, fi); \
   1240  1.1  pho         else if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate) \
   1241  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate(path, size); \
   1242  1.1  pho         else                                                            \
   1243  1.1  pho             return -ENOSYS
   1244  1.1  pho         CALL_FTRUNCATE_OR_TRUNCATE(25);
   1245  1.1  pho         CALL_FTRUNCATE_OR_TRUNCATE(26);
   1246  1.1  pho         CALL_FTRUNCATE_OR_TRUNCATE(28);
   1247  1.1  pho         CALL_FTRUNCATE_OR_TRUNCATE(29);
   1248  1.1  pho #undef CALL_FTRUNCATE_OR_TRUNCATE
   1249  1.1  pho 
   1250  1.1  pho         /* FUSE >= 3.0 have truncate() but with a different function
   1251  1.1  pho          * type. */
   1252  1.1  pho #define CALL_TRUNCATE(VER)                      \
   1253  1.1  pho     case VER:                                   \
   1254  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate) \
   1255  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->truncate(path, size, fi); \
   1256  1.1  pho         else                                                            \
   1257  1.1  pho             return -ENOSYS
   1258  1.1  pho         CALL_TRUNCATE(30);
   1259  1.1  pho         CALL_TRUNCATE(34);
   1260  1.2  pho         CALL_TRUNCATE(35);
   1261  1.1  pho         CALL_TRUNCATE(38);
   1262  1.1  pho #undef CALL_TRUNCATE
   1263  1.1  pho     default:
   1264  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1265  1.1  pho     }
   1266  1.1  pho }
   1267  1.1  pho 
   1268  1.1  pho int
   1269  1.1  pho fuse_fs_utimens_v27(struct fuse_fs *fs, const char *path, const struct timespec tv[2]) {
   1270  1.1  pho     return fuse_fs_utimens_v30(fs, path, tv, NULL);
   1271  1.1  pho }
   1272  1.1  pho 
   1273  1.1  pho int
   1274  1.1  pho fuse_fs_utimens_v30(struct fuse_fs* fs, const char* path,
   1275  1.1  pho                     const struct timespec tv[2], struct fuse_file_info* fi) {
   1276  1.1  pho     struct utimbuf timbuf;
   1277  1.1  pho 
   1278  1.1  pho     timbuf.actime  = tv[0].tv_sec;
   1279  1.1  pho     timbuf.modtime = tv[1].tv_sec;
   1280  1.1  pho 
   1281  1.1  pho     clobber_context_user_data(fs);
   1282  1.1  pho 
   1283  1.1  pho     switch (fs->op_version) {
   1284  1.1  pho         /* FUSE < 2.6 didn't have utimens() but had utime()
   1285  1.1  pho          * instead. */
   1286  1.1  pho #define CALL_UTIME(VER)                                                 \
   1287  1.1  pho     case VER:                                                           \
   1288  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->utime) \
   1289  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->utime(path, &timbuf); \
   1290  1.1  pho         else                                                            \
   1291  1.1  pho             return -ENOSYS
   1292  1.1  pho         CALL_UTIME(11);
   1293  1.1  pho         CALL_UTIME(21);
   1294  1.1  pho         CALL_UTIME(22);
   1295  1.1  pho         CALL_UTIME(23);
   1296  1.1  pho         CALL_UTIME(25);
   1297  1.1  pho #undef CALL_UTIME
   1298  1.1  pho 
   1299  1.1  pho         /* utimens() appeared on FUSE 2.6. Call it if it exists, or fall back to
   1300  1.1  pho          * utime() otherwise. */
   1301  1.1  pho #define CALL_UTIMENS_OR_UTIME(VER)                                      \
   1302  1.1  pho     case VER:                                                           \
   1303  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->utimens) \
   1304  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->utimens(path, tv); \
   1305  1.1  pho         else if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->utime) \
   1306  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->utime(path, &timbuf); \
   1307  1.1  pho         else                                                            \
   1308  1.1  pho             return -ENOSYS
   1309  1.1  pho         CALL_UTIMENS_OR_UTIME(26);
   1310  1.1  pho         CALL_UTIMENS_OR_UTIME(28);
   1311  1.1  pho         CALL_UTIMENS_OR_UTIME(29);
   1312  1.1  pho #undef CALL_UTIMENS_OR_UTIME
   1313  1.1  pho 
   1314  1.1  pho         /* utime() disappeared on FUSE 3.0. */
   1315  1.1  pho #define CALL_UTIMENS(VER)                       \
   1316  1.1  pho     case VER:                                   \
   1317  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->utimens) \
   1318  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->utimens(path, tv, fi); \
   1319  1.1  pho         else                                                            \
   1320  1.1  pho             return -ENOSYS
   1321  1.1  pho         CALL_UTIMENS(30);
   1322  1.1  pho         CALL_UTIMENS(34);
   1323  1.2  pho         CALL_UTIMENS(35);
   1324  1.1  pho         CALL_UTIMENS(38);
   1325  1.1  pho #undef CALL_UTIMENS
   1326  1.1  pho     default:
   1327  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1328  1.1  pho     }
   1329  1.1  pho }
   1330  1.1  pho 
   1331  1.1  pho int
   1332  1.1  pho fuse_fs_access(struct fuse_fs* fs, const char* path, int mask) {
   1333  1.1  pho     clobber_context_user_data(fs);
   1334  1.1  pho     /* access() appeared on FUSE 2.5. */
   1335  1.1  pho     switch (fs->op_version) {
   1336  1.1  pho     case 11:
   1337  1.1  pho     case 21:
   1338  1.1  pho     case 22:
   1339  1.1  pho     case 23:
   1340  1.1  pho         return -ENOSYS;
   1341  1.1  pho #define CALL_ACCESS(VER)                                                \
   1342  1.1  pho     case VER:                                                           \
   1343  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->access) \
   1344  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->access(path, mask); \
   1345  1.1  pho         else                                                            \
   1346  1.1  pho             return -ENOSYS
   1347  1.1  pho         CALL_ACCESS(25);
   1348  1.1  pho         CALL_ACCESS(26);
   1349  1.1  pho         CALL_ACCESS(28);
   1350  1.1  pho         CALL_ACCESS(29);
   1351  1.1  pho         CALL_ACCESS(30);
   1352  1.1  pho         CALL_ACCESS(34);
   1353  1.2  pho         CALL_ACCESS(35);
   1354  1.1  pho         CALL_ACCESS(38);
   1355  1.1  pho #undef CALL_ACCESS
   1356  1.1  pho     default:
   1357  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1358  1.1  pho     }
   1359  1.1  pho }
   1360  1.1  pho 
   1361  1.1  pho int
   1362  1.1  pho fuse_fs_readlink(struct fuse_fs* fs, const char* path, char* buf, size_t len) {
   1363  1.1  pho     clobber_context_user_data(fs);
   1364  1.1  pho     switch (fs->op_version) {
   1365  1.1  pho #define CALL_READLINK(VER)                                              \
   1366  1.1  pho     case VER:                                                           \
   1367  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->readlink) \
   1368  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->readlink(path, buf, len); \
   1369  1.1  pho         else                                                            \
   1370  1.1  pho             return -ENOSYS
   1371  1.1  pho         CALL_READLINK(11);
   1372  1.1  pho         CALL_READLINK(21);
   1373  1.1  pho         CALL_READLINK(22);
   1374  1.1  pho         CALL_READLINK(23);
   1375  1.1  pho         CALL_READLINK(25);
   1376  1.1  pho         CALL_READLINK(26);
   1377  1.1  pho         CALL_READLINK(28);
   1378  1.1  pho         CALL_READLINK(29);
   1379  1.1  pho         CALL_READLINK(30);
   1380  1.1  pho         CALL_READLINK(34);
   1381  1.2  pho         CALL_READLINK(35);
   1382  1.1  pho         CALL_READLINK(38);
   1383  1.1  pho #undef CALL_READLINK
   1384  1.1  pho     default:
   1385  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1386  1.1  pho     }
   1387  1.1  pho }
   1388  1.1  pho 
   1389  1.1  pho int
   1390  1.1  pho fuse_fs_mknod(struct fuse_fs* fs, const char* path, mode_t mode, dev_t rdev) {
   1391  1.1  pho     clobber_context_user_data(fs);
   1392  1.1  pho     switch (fs->op_version) {
   1393  1.1  pho #define CALL_MKNOD(VER)                                                 \
   1394  1.1  pho     case VER:                                                           \
   1395  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->mknod) \
   1396  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->mknod(path, mode, rdev); \
   1397  1.1  pho         else                                                            \
   1398  1.1  pho             return -ENOSYS
   1399  1.1  pho         CALL_MKNOD(11);
   1400  1.1  pho         CALL_MKNOD(21);
   1401  1.1  pho         CALL_MKNOD(22);
   1402  1.1  pho         CALL_MKNOD(23);
   1403  1.1  pho         CALL_MKNOD(25);
   1404  1.1  pho         CALL_MKNOD(26);
   1405  1.1  pho         CALL_MKNOD(28);
   1406  1.1  pho         CALL_MKNOD(29);
   1407  1.1  pho         CALL_MKNOD(30);
   1408  1.1  pho         CALL_MKNOD(34);
   1409  1.2  pho         CALL_MKNOD(35);
   1410  1.1  pho         CALL_MKNOD(38);
   1411  1.1  pho #undef CALL_MKNOD
   1412  1.1  pho     default:
   1413  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1414  1.1  pho     }
   1415  1.1  pho }
   1416  1.1  pho 
   1417  1.1  pho int
   1418  1.1  pho fuse_fs_mkdir(struct fuse_fs* fs, const char* path, mode_t mode) {
   1419  1.1  pho     clobber_context_user_data(fs);
   1420  1.1  pho     switch (fs->op_version) {
   1421  1.1  pho #define CALL_MKDIR(VER)                                                 \
   1422  1.1  pho     case VER:                                                           \
   1423  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->mkdir) \
   1424  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->mkdir(path, mode); \
   1425  1.1  pho         else                                                            \
   1426  1.1  pho             return -ENOSYS
   1427  1.1  pho         CALL_MKDIR(11);
   1428  1.1  pho         CALL_MKDIR(21);
   1429  1.1  pho         CALL_MKDIR(22);
   1430  1.1  pho         CALL_MKDIR(23);
   1431  1.1  pho         CALL_MKDIR(25);
   1432  1.1  pho         CALL_MKDIR(26);
   1433  1.1  pho         CALL_MKDIR(28);
   1434  1.1  pho         CALL_MKDIR(29);
   1435  1.1  pho         CALL_MKDIR(30);
   1436  1.1  pho         CALL_MKDIR(34);
   1437  1.2  pho         CALL_MKDIR(35);
   1438  1.1  pho         CALL_MKDIR(38);
   1439  1.1  pho #undef CALL_MKDIR
   1440  1.1  pho     default:
   1441  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1442  1.1  pho     }
   1443  1.1  pho }
   1444  1.1  pho 
   1445  1.1  pho int fuse_fs_setxattr(struct fuse_fs* fs, const char* path, const char* name,
   1446  1.1  pho                      const char* value, size_t size, int flags) {
   1447  1.1  pho     clobber_context_user_data(fs);
   1448  1.1  pho     /* setxattr() appeared on FUSE 2.1. */
   1449  1.1  pho     switch (fs->op_version) {
   1450  1.1  pho     case 11:
   1451  1.1  pho         return -ENOSYS;
   1452  1.1  pho #define CALL_SETXATTR(VER)                                              \
   1453  1.1  pho     case VER:                                                           \
   1454  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->setxattr) \
   1455  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->setxattr(path, name, value, size, flags); \
   1456  1.1  pho         else                                                            \
   1457  1.1  pho             return -ENOSYS
   1458  1.1  pho         CALL_SETXATTR(21);
   1459  1.1  pho         CALL_SETXATTR(22);
   1460  1.1  pho         CALL_SETXATTR(23);
   1461  1.1  pho         CALL_SETXATTR(25);
   1462  1.1  pho         CALL_SETXATTR(26);
   1463  1.1  pho         CALL_SETXATTR(28);
   1464  1.1  pho         CALL_SETXATTR(29);
   1465  1.1  pho         CALL_SETXATTR(30);
   1466  1.1  pho         CALL_SETXATTR(34);
   1467  1.2  pho         CALL_SETXATTR(35);
   1468  1.1  pho         CALL_SETXATTR(38);
   1469  1.1  pho #undef CALL_SETXATTR
   1470  1.1  pho     default:
   1471  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1472  1.1  pho     }
   1473  1.1  pho }
   1474  1.1  pho 
   1475  1.1  pho int
   1476  1.1  pho fuse_fs_getxattr(struct fuse_fs* fs, const char* path, const char* name,
   1477  1.1  pho                  char* value, size_t size) {
   1478  1.1  pho     clobber_context_user_data(fs);
   1479  1.1  pho     /* getxattr() appeared on FUSE 2.1. */
   1480  1.1  pho     switch (fs->op_version) {
   1481  1.1  pho     case 11:
   1482  1.1  pho         return -ENOSYS;
   1483  1.1  pho #define CALL_GETXATTR(VER)                                              \
   1484  1.1  pho     case VER:                                                           \
   1485  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getxattr) \
   1486  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->getxattr(path, name, value, size); \
   1487  1.1  pho         else                                                            \
   1488  1.1  pho             return -ENOSYS
   1489  1.1  pho         CALL_GETXATTR(21);
   1490  1.1  pho         CALL_GETXATTR(22);
   1491  1.1  pho         CALL_GETXATTR(23);
   1492  1.1  pho         CALL_GETXATTR(25);
   1493  1.1  pho         CALL_GETXATTR(26);
   1494  1.1  pho         CALL_GETXATTR(28);
   1495  1.1  pho         CALL_GETXATTR(29);
   1496  1.1  pho         CALL_GETXATTR(30);
   1497  1.1  pho         CALL_GETXATTR(34);
   1498  1.2  pho         CALL_GETXATTR(35);
   1499  1.1  pho         CALL_GETXATTR(38);
   1500  1.1  pho #undef CALL_GETXATTR
   1501  1.1  pho     default:
   1502  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1503  1.1  pho     }
   1504  1.1  pho }
   1505  1.1  pho 
   1506  1.1  pho int fuse_fs_listxattr(struct fuse_fs* fs, const char* path, char* list, size_t size) {
   1507  1.1  pho     clobber_context_user_data(fs);
   1508  1.1  pho     /* listxattr() appeared on FUSE 2.1. */
   1509  1.1  pho     switch (fs->op_version) {
   1510  1.1  pho     case 11:
   1511  1.1  pho         return -ENOSYS;
   1512  1.1  pho #define CALL_LISTXATTR(VER)                                             \
   1513  1.1  pho     case VER:                                                           \
   1514  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->listxattr) \
   1515  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->listxattr(path, list, size); \
   1516  1.1  pho         else                                                            \
   1517  1.1  pho             return -ENOSYS
   1518  1.1  pho         CALL_LISTXATTR(21);
   1519  1.1  pho         CALL_LISTXATTR(22);
   1520  1.1  pho         CALL_LISTXATTR(23);
   1521  1.1  pho         CALL_LISTXATTR(25);
   1522  1.1  pho         CALL_LISTXATTR(26);
   1523  1.1  pho         CALL_LISTXATTR(28);
   1524  1.1  pho         CALL_LISTXATTR(29);
   1525  1.1  pho         CALL_LISTXATTR(30);
   1526  1.1  pho         CALL_LISTXATTR(34);
   1527  1.2  pho         CALL_LISTXATTR(35);
   1528  1.1  pho         CALL_LISTXATTR(38);
   1529  1.1  pho #undef CALL_LISTXATTR
   1530  1.1  pho     default:
   1531  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1532  1.1  pho     }
   1533  1.1  pho }
   1534  1.1  pho 
   1535  1.1  pho int
   1536  1.1  pho fuse_fs_removexattr(struct fuse_fs* fs, const char* path, const char* name) {
   1537  1.1  pho     clobber_context_user_data(fs);
   1538  1.1  pho     /* removexattr() appeared on FUSE 2.1. */
   1539  1.1  pho     switch (fs->op_version) {
   1540  1.1  pho     case 11:
   1541  1.1  pho         return -ENOSYS;
   1542  1.1  pho #define CALL_REMOVEXATTR(VER)                                           \
   1543  1.1  pho     case VER:                                                           \
   1544  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->removexattr) \
   1545  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->removexattr(path, name); \
   1546  1.1  pho         else                                                            \
   1547  1.1  pho             return -ENOSYS
   1548  1.1  pho         CALL_REMOVEXATTR(21);
   1549  1.1  pho         CALL_REMOVEXATTR(22);
   1550  1.1  pho         CALL_REMOVEXATTR(23);
   1551  1.1  pho         CALL_REMOVEXATTR(25);
   1552  1.1  pho         CALL_REMOVEXATTR(26);
   1553  1.1  pho         CALL_REMOVEXATTR(28);
   1554  1.1  pho         CALL_REMOVEXATTR(29);
   1555  1.1  pho         CALL_REMOVEXATTR(30);
   1556  1.1  pho         CALL_REMOVEXATTR(34);
   1557  1.2  pho         CALL_REMOVEXATTR(35);
   1558  1.1  pho         CALL_REMOVEXATTR(38);
   1559  1.1  pho #undef CALL_REMOVEXATTR
   1560  1.1  pho     default:
   1561  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1562  1.1  pho     }
   1563  1.1  pho }
   1564  1.1  pho 
   1565  1.1  pho int
   1566  1.1  pho fuse_fs_bmap(struct fuse_fs* fs, const char* path, size_t blocksize, uint64_t *idx) {
   1567  1.1  pho     clobber_context_user_data(fs);
   1568  1.1  pho     /* bmap() appeared on FUSE 2.6. */
   1569  1.1  pho     switch (fs->op_version) {
   1570  1.1  pho     case 11:
   1571  1.1  pho     case 22:
   1572  1.1  pho     case 23:
   1573  1.1  pho     case 25:
   1574  1.1  pho         return -ENOSYS;
   1575  1.1  pho #define CALL_BMAP(VER)                                                  \
   1576  1.1  pho     case VER:                                                           \
   1577  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->bmap) \
   1578  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->bmap(path, blocksize, idx); \
   1579  1.1  pho         else                                                            \
   1580  1.1  pho             return -ENOSYS
   1581  1.1  pho         CALL_BMAP(26);
   1582  1.1  pho         CALL_BMAP(28);
   1583  1.1  pho         CALL_BMAP(29);
   1584  1.1  pho         CALL_BMAP(30);
   1585  1.1  pho         CALL_BMAP(34);
   1586  1.2  pho         CALL_BMAP(35);
   1587  1.1  pho         CALL_BMAP(38);
   1588  1.1  pho #undef CALL_BMAP
   1589  1.1  pho     default:
   1590  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1591  1.1  pho     }
   1592  1.1  pho }
   1593  1.1  pho 
   1594  1.1  pho int fuse_fs_ioctl_v28(struct fuse_fs* fs, const char* path, int cmd, void* arg,
   1595  1.1  pho                       struct fuse_file_info* fi, unsigned int flags, void* data) {
   1596  1.1  pho     return fuse_fs_ioctl_v35(fs, path, (unsigned int)cmd, arg, fi, flags, data);
   1597  1.1  pho }
   1598  1.1  pho 
   1599  1.1  pho int fuse_fs_ioctl_v35(struct fuse_fs* fs, const char* path, unsigned int cmd, void* arg,
   1600  1.1  pho                       struct fuse_file_info* fi, unsigned int flags, void* data) {
   1601  1.1  pho     clobber_context_user_data(fs);
   1602  1.1  pho     switch (fs->op_version) {
   1603  1.1  pho         /* ioctl() appeared on FUSE 2.8 but with (int)cmd. */
   1604  1.1  pho     case 11:
   1605  1.1  pho     case 22:
   1606  1.1  pho     case 23:
   1607  1.1  pho     case 25:
   1608  1.1  pho     case 26:
   1609  1.1  pho         return -ENOSYS;
   1610  1.1  pho #define CALL_OLD_IOCTL(VER)                                                 \
   1611  1.1  pho     case VER:                                                           \
   1612  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->ioctl) \
   1613  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->ioctl(path, (int)cmd, arg, fi, flags, data); \
   1614  1.1  pho         else                                                            \
   1615  1.1  pho             return -ENOSYS
   1616  1.1  pho         CALL_OLD_IOCTL(28);
   1617  1.1  pho         CALL_OLD_IOCTL(29);
   1618  1.1  pho         CALL_OLD_IOCTL(30);
   1619  1.1  pho         CALL_OLD_IOCTL(34);
   1620  1.1  pho #undef CALL_OLD_IOCTL
   1621  1.1  pho 
   1622  1.1  pho         /* It was then changed to (unsigned int)cmd on FUSE 3.5. */
   1623  1.1  pho #define CALL_IOCTL(VER)                                                 \
   1624  1.1  pho     case VER:                                                           \
   1625  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->ioctl) \
   1626  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->ioctl(path, cmd, arg, fi, flags, data); \
   1627  1.1  pho         else                                                            \
   1628  1.1  pho             return -ENOSYS
   1629  1.1  pho         CALL_IOCTL(35);
   1630  1.1  pho         CALL_IOCTL(38);
   1631  1.1  pho #undef CALL_IOCTL
   1632  1.1  pho     default:
   1633  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1634  1.1  pho     }
   1635  1.1  pho }
   1636  1.1  pho 
   1637  1.1  pho int
   1638  1.1  pho fuse_fs_poll(struct fuse_fs* fs, const char* path, struct fuse_file_info* fi,
   1639  1.1  pho              struct fuse_pollhandle* ph, unsigned* reventsp) {
   1640  1.1  pho     clobber_context_user_data(fs);
   1641  1.1  pho     /* poll() appeared on FUSE 2.8. */
   1642  1.1  pho     switch (fs->op_version) {
   1643  1.1  pho     case 11:
   1644  1.1  pho     case 22:
   1645  1.1  pho     case 23:
   1646  1.1  pho     case 25:
   1647  1.1  pho     case 26:
   1648  1.1  pho         return -ENOSYS;
   1649  1.1  pho #define CALL_POLL(VER)                                                  \
   1650  1.1  pho     case VER:                                                           \
   1651  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->poll) \
   1652  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->poll(path, fi, ph, reventsp); \
   1653  1.1  pho         else                                                            \
   1654  1.1  pho             return -ENOSYS
   1655  1.1  pho         CALL_POLL(28);
   1656  1.1  pho         CALL_POLL(29);
   1657  1.1  pho         CALL_POLL(30);
   1658  1.1  pho         CALL_POLL(34);
   1659  1.2  pho         CALL_POLL(35);
   1660  1.1  pho         CALL_POLL(38);
   1661  1.1  pho #undef CALL_POLL
   1662  1.1  pho     default:
   1663  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1664  1.1  pho     }
   1665  1.1  pho }
   1666  1.1  pho 
   1667  1.1  pho int
   1668  1.1  pho fuse_fs_fallocate(struct fuse_fs* fs, const char* path, int mode, off_t offset,
   1669  1.1  pho                   off_t length, struct fuse_file_info* fi) {
   1670  1.1  pho     clobber_context_user_data(fs);
   1671  1.1  pho     /* fallocate() appeared on FUSE 2.9. */
   1672  1.1  pho     switch (fs->op_version) {
   1673  1.1  pho     case 11:
   1674  1.1  pho     case 22:
   1675  1.1  pho     case 23:
   1676  1.1  pho     case 25:
   1677  1.1  pho     case 26:
   1678  1.1  pho     case 28:
   1679  1.1  pho         return -ENOSYS;
   1680  1.1  pho #define CALL_FALLOCATE(VER)                                             \
   1681  1.1  pho     case VER:                                                           \
   1682  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fallocate) \
   1683  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->fallocate(path, mode, offset, length, fi); \
   1684  1.1  pho         else                                                            \
   1685  1.1  pho             return -ENOSYS
   1686  1.1  pho         CALL_FALLOCATE(29);
   1687  1.1  pho         CALL_FALLOCATE(30);
   1688  1.1  pho         CALL_FALLOCATE(34);
   1689  1.2  pho         CALL_FALLOCATE(35);
   1690  1.1  pho         CALL_FALLOCATE(38);
   1691  1.1  pho #undef CALL_FALLOCATE
   1692  1.1  pho     default:
   1693  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1694  1.1  pho     }
   1695  1.1  pho }
   1696  1.1  pho 
   1697  1.1  pho ssize_t
   1698  1.1  pho fuse_fs_copy_file_range(struct fuse_fs *fs,
   1699  1.1  pho                         const char *path_in, struct fuse_file_info *fi_in, off_t off_in,
   1700  1.1  pho                         const char *path_out, struct fuse_file_info *fi_out, off_t off_out,
   1701  1.1  pho                         size_t len, int flags) {
   1702  1.1  pho     clobber_context_user_data(fs);
   1703  1.1  pho     /* copy_file_range() appeared on FUSE 3.4. */
   1704  1.1  pho     switch (fs->op_version) {
   1705  1.1  pho     case 11:
   1706  1.1  pho     case 22:
   1707  1.1  pho     case 23:
   1708  1.1  pho     case 25:
   1709  1.1  pho     case 26:
   1710  1.1  pho     case 28:
   1711  1.1  pho     case 29:
   1712  1.1  pho     case 30:
   1713  1.1  pho         return -ENOSYS;
   1714  1.1  pho #define CALL_COPY_FILE_RANGE(VER)                                       \
   1715  1.1  pho     case VER:                                                           \
   1716  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->copy_file_range) \
   1717  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->copy_file_range(path_in, fi_in, off_in, path_out, fi_out, off_out, len, flags); \
   1718  1.1  pho         else                                                            \
   1719  1.1  pho             return -ENOSYS
   1720  1.1  pho         CALL_COPY_FILE_RANGE(34);
   1721  1.2  pho         CALL_COPY_FILE_RANGE(35);
   1722  1.1  pho         CALL_COPY_FILE_RANGE(38);
   1723  1.1  pho #undef CALL_COPY_FILE_RANGE
   1724  1.1  pho     default:
   1725  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1726  1.1  pho     }
   1727  1.1  pho }
   1728  1.1  pho 
   1729  1.1  pho off_t
   1730  1.1  pho fuse_fs_lseek(struct fuse_fs* fs, const char* path, off_t off, int whence,
   1731  1.1  pho               struct fuse_file_info* fi) {
   1732  1.1  pho     clobber_context_user_data(fs);
   1733  1.1  pho     /* lseek() appeared on FUSE 3.8. */
   1734  1.1  pho     switch (fs->op_version) {
   1735  1.1  pho     case 11:
   1736  1.1  pho     case 22:
   1737  1.1  pho     case 23:
   1738  1.1  pho     case 25:
   1739  1.1  pho     case 26:
   1740  1.1  pho     case 28:
   1741  1.1  pho     case 29:
   1742  1.1  pho     case 30:
   1743  1.1  pho     case 34:
   1744  1.2  pho     case 35:
   1745  1.1  pho         return -ENOSYS;
   1746  1.1  pho #define CALL_LSEEK(VER)                         \
   1747  1.1  pho     case VER:                                   \
   1748  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->lseek) \
   1749  1.1  pho             return ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->lseek(path, off, whence, fi); \
   1750  1.1  pho         else                                                            \
   1751  1.1  pho             return -ENOSYS
   1752  1.1  pho         CALL_LSEEK(38);
   1753  1.1  pho #undef CALL_LSEEK
   1754  1.1  pho     default:
   1755  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1756  1.1  pho     }
   1757  1.1  pho }
   1758  1.1  pho 
   1759  1.1  pho void
   1760  1.1  pho fuse_fs_init_v27(struct fuse_fs *fs, struct fuse_conn_info *conn) {
   1761  1.1  pho     fuse_fs_init_v30(fs, conn, NULL);
   1762  1.1  pho }
   1763  1.1  pho 
   1764  1.1  pho void
   1765  1.1  pho fuse_fs_init_v30(struct fuse_fs* fs, struct fuse_conn_info* conn,
   1766  1.1  pho                  struct fuse_config* cfg) {
   1767  1.1  pho     clobber_context_user_data(fs);
   1768  1.1  pho     switch (fs->op_version) {
   1769  1.1  pho     case 11:
   1770  1.1  pho     case 21:
   1771  1.1  pho     case 22:
   1772  1.1  pho         break;
   1773  1.1  pho 
   1774  1.1  pho         /* init() appeared on FUSE 2.3 as init(void). */
   1775  1.1  pho #define CALL_NULLARY_INIT(VER)                                          \
   1776  1.1  pho     case VER:                                                           \
   1777  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->init) \
   1778  1.1  pho             fs->user_data = ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->init(); \
   1779  1.1  pho         break
   1780  1.1  pho         CALL_NULLARY_INIT(23);
   1781  1.1  pho         CALL_NULLARY_INIT(25);
   1782  1.1  pho #undef CALL_NULLARY_INIT
   1783  1.1  pho 
   1784  1.1  pho         /* It was changed to init(struct fuse_conn_info*) on FUSE
   1785  1.1  pho          * 2.6. */
   1786  1.1  pho #define CALL_UNARY_INIT(VER)                                            \
   1787  1.1  pho     case VER:                                                           \
   1788  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->init) \
   1789  1.1  pho             fs->user_data = ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->init(conn); \
   1790  1.1  pho         break
   1791  1.1  pho         CALL_UNARY_INIT(26);
   1792  1.1  pho         CALL_UNARY_INIT(28);
   1793  1.1  pho         CALL_UNARY_INIT(29);
   1794  1.1  pho #undef CALL_INIT
   1795  1.1  pho 
   1796  1.1  pho         /* It was again changed to init(struct fuse_conn_info*, struct
   1797  1.1  pho          * fuse_config*) on FUSE 3.0. */
   1798  1.1  pho #define CALL_BINARY_INIT(VER)                   \
   1799  1.1  pho     case VER:                                   \
   1800  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->init) \
   1801  1.1  pho             fs->user_data = ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->init(conn, cfg); \
   1802  1.1  pho         break
   1803  1.1  pho         CALL_BINARY_INIT(30);
   1804  1.1  pho         CALL_BINARY_INIT(34);
   1805  1.2  pho         CALL_BINARY_INIT(35);
   1806  1.1  pho         CALL_BINARY_INIT(38);
   1807  1.1  pho #undef CALL_BINARY_INIT
   1808  1.1  pho     default:
   1809  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1810  1.1  pho     }
   1811  1.1  pho }
   1812  1.1  pho 
   1813  1.1  pho void
   1814  1.1  pho fuse_fs_destroy(struct fuse_fs *fs) {
   1815  1.1  pho     clobber_context_user_data(fs);
   1816  1.1  pho     switch (fs->op_version) {
   1817  1.1  pho         /* destroy() appeared on FUSE 2.3. */
   1818  1.1  pho     case 11:
   1819  1.1  pho     case 21:
   1820  1.1  pho     case 22:
   1821  1.1  pho         break;
   1822  1.1  pho 
   1823  1.1  pho #define CALL_DESTROY(VER)                                               \
   1824  1.1  pho     case VER:                                                           \
   1825  1.1  pho         if (((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->destroy) \
   1826  1.1  pho             ((const struct __CONCAT(fuse_operations_v,VER)*)fs->op)->destroy(fs->user_data); \
   1827  1.1  pho         break
   1828  1.1  pho         CALL_DESTROY(23);
   1829  1.1  pho         CALL_DESTROY(25);
   1830  1.1  pho         CALL_DESTROY(26);
   1831  1.1  pho         CALL_DESTROY(28);
   1832  1.1  pho         CALL_DESTROY(29);
   1833  1.1  pho         CALL_DESTROY(30);
   1834  1.1  pho         CALL_DESTROY(34);
   1835  1.2  pho         CALL_DESTROY(35);
   1836  1.1  pho         CALL_DESTROY(38);
   1837  1.1  pho #undef CALL_DESTROY
   1838  1.1  pho     default:
   1839  1.1  pho         UNKNOWN_VERSION(fs->op_version);
   1840  1.1  pho     }
   1841  1.1  pho 
   1842  1.1  pho     /* fuse_fs_destroy(3) also deallocates struct fuse_fs itself. */
   1843  1.1  pho     free(fs->op);
   1844  1.1  pho     free(fs);
   1845  1.1  pho }
   1846