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