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