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 52struct 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 62static void* 63clone_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 93struct 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. */ 117static void 118clobber_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... */ 123int 124fuse_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 128int 129fuse_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 165int 166fuse_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 202int 203fuse_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 207int 208fuse_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 244int 245fuse_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 272int 273fuse_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 300int 301fuse_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 328int 329fuse_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 356int 357fuse_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 392int 393fuse_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 428int 429fuse_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 465int 466fuse_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 497int 498fuse_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 534int 535fuse_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 566int 567fuse_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 602int 603fuse_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 638static void 639zero_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} 649static void 650fuse_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} 659static void 660linux_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} 669int 670fuse_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 732int 733fuse_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 769struct 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. */ 775static mode_t 776dt_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. */ 795static int 796fuse_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. */ 810static int 811fuse_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 824struct 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. */ 831static int 832fuse_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 840int 841fuse_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 898int 899fuse_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 935int 936fuse_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 966int 967fuse_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 998int 999fuse_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 1029int 1030fuse_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 1061int 1062fuse_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 1092int 1093fuse_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 1097int 1098fuse_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 1134int 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 1138int 1139fuse_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 1175int 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 1179int 1180fuse_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 1215int 1216fuse_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 1268int 1269fuse_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 1273int 1274fuse_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 1331int 1332fuse_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 1361int 1362fuse_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 1389int 1390fuse_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 1417int 1418fuse_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 1445int 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 1475int 1476fuse_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 1506int 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 1535int 1536fuse_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 1565int 1566fuse_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 1594int 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 1599int 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 1637int 1638fuse_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 1667int 1668fuse_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 1697ssize_t 1698fuse_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 1729off_t 1730fuse_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 1759void 1760fuse_fs_init_v27(struct fuse_fs *fs, struct fuse_conn_info *conn) { 1761 fuse_fs_init_v30(fs, conn, NULL); 1762} 1763 1764void 1765fuse_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 1813void 1814fuse_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