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