xref: /netbsd/lib/librefuse/refuse/fs.c (revision 6e6a0fe1)
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*
clone_op(const void * op,int op_version)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*
__fuse_fs_new(const void * op,int op_version,void * user_data)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
clobber_context_user_data(struct fuse_fs * fs)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
fuse_fs_getattr_v27(struct fuse_fs * fs,const char * path,struct stat * buf)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
fuse_fs_getattr_v30(struct fuse_fs * fs,const char * path,struct stat * buf,struct fuse_file_info * fi)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
fuse_fs_fgetattr(struct fuse_fs * fs,const char * path,struct stat * buf,struct fuse_file_info * fi)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
fuse_fs_rename_v27(struct fuse_fs * fs,const char * oldpath,const char * newpath)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
fuse_fs_rename_v30(struct fuse_fs * fs,const char * oldpath,const char * newpath,unsigned int flags)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
fuse_fs_unlink(struct fuse_fs * fs,const char * path)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
fuse_fs_rmdir(struct fuse_fs * fs,const char * path)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
fuse_fs_symlink(struct fuse_fs * fs,const char * linkname,const char * path)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
fuse_fs_link(struct fuse_fs * fs,const char * oldpath,const char * newpath)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
fuse_fs_release(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)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
fuse_fs_open(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)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
fuse_fs_read(struct fuse_fs * fs,const char * path,char * buf,size_t size,off_t off,struct fuse_file_info * fi)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
fuse_fs_read_buf(struct fuse_fs * fs,const char * path,struct fuse_bufvec ** bufp,size_t size,off_t off,struct fuse_file_info * fi)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
fuse_fs_write(struct fuse_fs * fs,const char * path,const char * buf,size_t size,off_t off,struct fuse_file_info * fi)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
fuse_fs_write_buf(struct fuse_fs * fs,const char * path,struct fuse_bufvec * bufp,off_t off,struct fuse_file_info * fi)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
fuse_fs_fsync(struct fuse_fs * fs,const char * path,int datasync,struct fuse_file_info * fi)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
fuse_fs_flush(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)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
zero_statvfs(struct statvfs * dst)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
fuse_statfs_to_statvfs(struct statvfs * dst,const struct fuse_statfs * src)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
linux_statfs_to_statvfs(struct statvfs * dst,const struct statfs * src)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
fuse_fs_statfs(struct fuse_fs * fs,const char * path,struct statvfs * buf)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
fuse_fs_opendir(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)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
dt_to_mode(int dt)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
fuse_dirfil_v11_to_fill_dir_v23(fuse_dirh_t handle,const char * name,int type)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
fuse_dirfil_v22_to_fill_dir_v23(fuse_dirh_t handle,const char * name,int type,ino_t ino)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
fuse_fill_dir_v23_to_v30(void * buf,const char * name,const struct stat * stat,off_t off)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
fuse_fs_readdir_v27(struct fuse_fs * fs,const char * path,void * buf,fuse_fill_dir_t_v23 filler,off_t off,struct fuse_file_info * fi)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
fuse_fs_readdir_v30(struct fuse_fs * fs,const char * path,void * buf,fuse_fill_dir_t_v30 filler,off_t off,struct fuse_file_info * fi,enum fuse_readdir_flags flags)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
fuse_fs_fsyncdir(struct fuse_fs * fs,const char * path,int datasync,struct fuse_file_info * fi)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
fuse_fs_releasedir(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi)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
fuse_fs_create(struct fuse_fs * fs,const char * path,mode_t mode,struct fuse_file_info * fi)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
fuse_fs_lock(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi,int cmd,struct flock * lock)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
fuse_fs_flock(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi,int op)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
fuse_fs_chmod_v27(struct fuse_fs * fs,const char * path,mode_t mode)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
fuse_fs_chmod_v30(struct fuse_fs * fs,const char * path,mode_t mode,struct fuse_file_info * fi)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 
fuse_fs_chown_v27(struct fuse_fs * fs,const char * path,uid_t uid,gid_t gid)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
fuse_fs_chown_v30(struct fuse_fs * fs,const char * path,uid_t uid,gid_t gid,struct fuse_file_info * fi)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 
fuse_fs_truncate_v27(struct fuse_fs * fs,const char * path,off_t size)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
fuse_fs_truncate_v30(struct fuse_fs * fs,const char * path,off_t size,struct fuse_file_info * fi)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
fuse_fs_ftruncate(struct fuse_fs * fs,const char * path,off_t size,struct fuse_file_info * fi)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
fuse_fs_utimens_v27(struct fuse_fs * fs,const char * path,const struct timespec tv[2])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
fuse_fs_utimens_v30(struct fuse_fs * fs,const char * path,const struct timespec tv[2],struct fuse_file_info * fi)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
fuse_fs_access(struct fuse_fs * fs,const char * path,int mask)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
fuse_fs_readlink(struct fuse_fs * fs,const char * path,char * buf,size_t len)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
fuse_fs_mknod(struct fuse_fs * fs,const char * path,mode_t mode,dev_t rdev)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
fuse_fs_mkdir(struct fuse_fs * fs,const char * path,mode_t mode)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 
fuse_fs_setxattr(struct fuse_fs * fs,const char * path,const char * name,const char * value,size_t size,int flags)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
fuse_fs_getxattr(struct fuse_fs * fs,const char * path,const char * name,char * value,size_t size)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 
fuse_fs_listxattr(struct fuse_fs * fs,const char * path,char * list,size_t size)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
fuse_fs_removexattr(struct fuse_fs * fs,const char * path,const char * name)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
fuse_fs_bmap(struct fuse_fs * fs,const char * path,size_t blocksize,uint64_t * idx)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 
fuse_fs_ioctl_v28(struct fuse_fs * fs,const char * path,int cmd,void * arg,struct fuse_file_info * fi,unsigned int flags,void * data)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 
fuse_fs_ioctl_v35(struct fuse_fs * fs,const char * path,unsigned int cmd,void * arg,struct fuse_file_info * fi,unsigned int flags,void * data)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
fuse_fs_poll(struct fuse_fs * fs,const char * path,struct fuse_file_info * fi,struct fuse_pollhandle * ph,unsigned * reventsp)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
fuse_fs_fallocate(struct fuse_fs * fs,const char * path,int mode,off_t offset,off_t length,struct fuse_file_info * fi)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
fuse_fs_copy_file_range(struct fuse_fs * fs,const char * path_in,struct fuse_file_info * fi_in,off_t off_in,const char * path_out,struct fuse_file_info * fi_out,off_t off_out,size_t len,int flags)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
fuse_fs_lseek(struct fuse_fs * fs,const char * path,off_t off,int whence,struct fuse_file_info * fi)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
fuse_fs_init_v27(struct fuse_fs * fs,struct fuse_conn_info * conn)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
fuse_fs_init_v30(struct fuse_fs * fs,struct fuse_conn_info * conn,struct fuse_config * cfg)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
fuse_fs_destroy(struct fuse_fs * fs)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