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