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