1/* $OpenBSD: fuse_ops.c,v 1.35 2018/07/16 13:10:53 helg Exp $ */ 2/* 3 * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <errno.h> 19#include <string.h> 20#include <stdlib.h> 21 22#include "fuse_private.h" 23#include "debug.h" 24 25#define CHECK_OPT(opname) DPRINTF("Opcode: %s\t", #opname); \ 26 DPRINTF("Inode: %llu\t", \ 27 (unsigned long long)fbuf->fb_ino); \ 28 if (!f->op.opname) { \ 29 fbuf->fb_err = -ENOSYS; \ 30 return (0); \ 31 } 32 33static int 34update_attr(struct fuse *f, struct stat *attr, const char *realname, 35 struct fuse_vnode *vn) 36{ 37 int ret; 38 39 memset(attr, 0, sizeof(struct stat)); 40 ret = f->op.getattr(realname, attr); 41 42 if (attr->st_blksize == 0) 43 attr->st_blksize = 512; 44 if (attr->st_blocks == 0) 45 attr->st_blocks = 4; 46 47 if (!f->conf.use_ino) 48 attr->st_ino = vn->ino; 49 50 if (f->conf.set_mode) 51 attr->st_mode = (attr->st_mode & S_IFMT) | (0777 & ~f->conf.umask); 52 53 if (f->conf.set_uid) 54 attr->st_uid = f->conf.uid; 55 56 if (f->conf.set_gid) 57 attr->st_gid = f->conf.gid; 58 59 return (ret); 60} 61 62static int 63ifuse_ops_init(struct fuse *f) 64{ 65 struct fuse_conn_info fci; 66 67 DPRINTF("Opcode: init\t"); 68 69 if (f->op.init) { 70 memset(&fci, 0, sizeof(fci)); 71 fci.proto_minor = FUSE_MINOR_VERSION; 72 fci.proto_major = FUSE_MAJOR_VERSION; 73 74 f->op.init(&fci); 75 } 76 return (0); 77} 78 79static int 80ifuse_ops_getattr(struct fuse *f, struct fusebuf *fbuf) 81{ 82 struct fuse_vnode *vn; 83 char *realname; 84 85 DPRINTF("Opcode: getattr\t"); 86 DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino); 87 88 memset(&fbuf->fb_attr, 0, sizeof(struct stat)); 89 90 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 91 if (vn == NULL) { 92 fbuf->fb_err = -errno; 93 return (0); 94 } 95 96 realname = build_realname(f, vn->ino); 97 if (realname == NULL) { 98 fbuf->fb_err = -errno; 99 return (0); 100 } 101 102 fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn); 103 free(realname); 104 105 return (0); 106} 107 108static int 109ifuse_ops_access(struct fuse *f, struct fusebuf *fbuf) 110{ 111 struct fuse_vnode *vn; 112 char *realname; 113 114 CHECK_OPT(access); 115 116 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 117 if (vn == NULL) { 118 fbuf->fb_err = -errno; 119 return (0); 120 } 121 122 realname = build_realname(f, vn->ino); 123 if (realname == NULL) { 124 fbuf->fb_err = -errno; 125 return (0); 126 } 127 128 fbuf->fb_err = f->op.access(realname, fbuf->fb_io_mode); 129 free(realname); 130 131 return (0); 132} 133 134static int 135ifuse_ops_open(struct fuse *f, struct fusebuf *fbuf) 136{ 137 struct fuse_file_info ffi; 138 struct fuse_vnode *vn; 139 char *realname; 140 141 CHECK_OPT(open); 142 143 memset(&ffi, 0, sizeof(ffi)); 144 ffi.flags = fbuf->fb_io_flags; 145 146 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 147 if (vn == NULL) { 148 fbuf->fb_err = -errno; 149 return (0); 150 } 151 152 realname = build_realname(f, vn->ino); 153 if (realname == NULL) { 154 fbuf->fb_err = -errno; 155 return (0); 156 } 157 158 fbuf->fb_err = f->op.open(realname, &ffi); 159 free(realname); 160 161 if (!fbuf->fb_err) 162 fbuf->fb_io_fd = ffi.fh; 163 164 return (0); 165} 166 167static int 168ifuse_ops_opendir(struct fuse *f, struct fusebuf *fbuf) 169{ 170 struct fuse_file_info ffi; 171 struct fuse_vnode *vn; 172 char *realname; 173 174 DPRINTF("Opcode: opendir\t"); 175 DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino); 176 177 memset(&ffi, 0, sizeof(ffi)); 178 ffi.flags = fbuf->fb_io_flags; 179 180 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 181 if (vn == NULL) { 182 fbuf->fb_err = -errno; 183 return (0); 184 } 185 186 if (f->op.opendir) { 187 realname = build_realname(f, vn->ino); 188 if (realname == NULL) { 189 fbuf->fb_err = -errno; 190 return (0); 191 } 192 193 fbuf->fb_err = f->op.opendir(realname, &ffi); 194 free(realname); 195 } 196 197 if (!fbuf->fb_err) 198 fbuf->fb_io_fd = ffi.fh; 199 200 return (0); 201} 202 203#define GENERIC_DIRSIZ(NLEN) \ 204((sizeof (struct dirent) - (MAXNAMLEN+1)) + ((NLEN+1 + 7) &~ 7)) 205 206/* 207 * This function adds one directory entry to the buffer. 208 * FUSE file systems can implement readdir in one of two ways. 209 * 210 * 1. Read all directory entries in one operation. The off parameter 211 * will always be 0 and this filler function always returns 0. 212 * 2. The file system keeps track of the directory entry offsets and 213 * this filler function returns 1 when the buffer is full. 214 * 215 * OpenBSD currently supports 1. but will still call the file system's 216 * readdir function multiple times if either the kernel buffer or the 217 * buffer supplied by the calling application is too small to fit all 218 * entries. Each call to the file system's readdir function will fill 219 * the buffer with the next set of entries. 220 */ 221static int 222ifuse_fill_readdir(void *dh, const char *name, const struct stat *stbuf, 223 off_t off) 224{ 225 struct fuse *f; 226 struct fuse_dirhandle *fd = dh; 227 struct fuse_vnode *v; 228 struct fusebuf *fbuf; 229 struct dirent *dir; 230 uint32_t namelen; 231 uint32_t len; 232 233 f = fd->fuse; 234 fbuf = fd->buf; 235 namelen = strnlen(name, MAXNAMLEN); 236 len = GENERIC_DIRSIZ(namelen); 237 238 /* buffer is full so ignore the remaining entries */ 239 if (fd->full || (fbuf->fb_len + len > fd->size)) { 240 fd->full = 1; 241 return (0); 242 } 243 244 /* already returned these entries in a previous call so skip */ 245 if (fd->start != 0 && fd->idx < fd->start) { 246 fd->idx += len; 247 return (0); 248 } 249 250 dir = (struct dirent *) &fbuf->fb_dat[fbuf->fb_len]; 251 252 if (stbuf != NULL && f->conf.use_ino) 253 dir->d_fileno = stbuf->st_ino; 254 else { 255 /* 256 * This always behaves as if readdir_ino option is set so 257 * getcwd(3) works. 258 */ 259 v = get_vn_by_name_and_parent(f, (uint8_t *)name, fbuf->fb_ino); 260 if (v == NULL) { 261 if (strcmp(name, ".") == 0) 262 dir->d_fileno = fbuf->fb_ino; 263 else 264 dir->d_fileno = 0xffffffff; 265 } else 266 dir->d_fileno = v->ino; 267 } 268 269 if (stbuf != NULL) 270 dir->d_type = IFTODT(stbuf->st_mode); 271 else 272 dir->d_type = DT_UNKNOWN; 273 274 dir->d_reclen = len; 275 dir->d_off = off + len; /* XXX */ 276 strlcpy(dir->d_name, name, sizeof(dir->d_name)); 277 dir->d_namlen = strlen(dir->d_name); 278 279 fbuf->fb_len += len; 280 fd->idx += len; 281 282 return (0); 283} 284 285static int 286ifuse_fill_getdir(fuse_dirh_t fd, const char *name, int type, ino_t ino) 287{ 288 struct stat st; 289 290 memset(&st, 0, sizeof(st)); 291 st.st_mode = type << 12; 292 if (ino == 0) 293 st.st_ino = 0xffffffff; 294 else 295 st.st_ino = ino; 296 297 return (fd->filler(fd, name, &st, 0)); 298} 299 300static int 301ifuse_ops_readdir(struct fuse *f, struct fusebuf *fbuf) 302{ 303 struct fuse_file_info ffi; 304 struct fuse_dirhandle fd; 305 struct fuse_vnode *vn; 306 char *realname; 307 uint64_t offset; 308 uint32_t size; 309 310 DPRINTF("Opcode: readdir\t"); 311 DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino); 312 DPRINTF("Offset: %llu\t", fbuf->fb_io_off); 313 DPRINTF("Size: %lu\t", fbuf->fb_io_len); 314 315 memset(&ffi, 0, sizeof(ffi)); 316 ffi.fh = fbuf->fb_io_fd; 317 offset = fbuf->fb_io_off; 318 size = fbuf->fb_io_len; 319 320 fbuf->fb_dat = calloc(1, size); 321 322 if (fbuf->fb_dat == NULL) { 323 fbuf->fb_err = -errno; 324 return (0); 325 } 326 327 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 328 if (vn == NULL) { 329 fbuf->fb_err = -errno; 330 free(fbuf->fb_dat); 331 return (0); 332 } 333 334 memset(&fd, 0, sizeof(fd)); 335 fd.filler = ifuse_fill_readdir; 336 fd.buf = fbuf; 337 fd.full = 0; 338 fd.size = size; 339 fd.off = offset; 340 fd.idx = 0; 341 fd.fuse = f; 342 fd.start = offset; 343 344 realname = build_realname(f, vn->ino); 345 if (realname == NULL) { 346 fbuf->fb_err = -errno; 347 free(fbuf->fb_dat); 348 return (0); 349 } 350 351 if (f->op.readdir) 352 fbuf->fb_err = f->op.readdir(realname, &fd, ifuse_fill_readdir, 353 offset, &ffi); 354 else if (f->op.getdir) 355 fbuf->fb_err = f->op.getdir(realname, &fd, ifuse_fill_getdir); 356 else 357 fbuf->fb_err = -ENOSYS; 358 free(realname); 359 360 if (fbuf->fb_err) 361 fbuf->fb_len = 0; 362 else if (fd.full && fbuf->fb_len == 0) 363 fbuf->fb_err = -ENOBUFS; 364 365 if (fbuf->fb_len == 0) 366 free(fbuf->fb_dat); 367 368 return (0); 369} 370 371static int 372ifuse_ops_releasedir(struct fuse *f, struct fusebuf *fbuf) 373{ 374 struct fuse_file_info ffi; 375 struct fuse_vnode *vn; 376 char *realname; 377 378 DPRINTF("Opcode: releasedir\t"); 379 DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino); 380 381 memset(&ffi, 0, sizeof(ffi)); 382 ffi.fh = fbuf->fb_io_fd; 383 ffi.fh_old = ffi.fh; 384 ffi.flags = fbuf->fb_io_flags; 385 386 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 387 if (vn == NULL) { 388 fbuf->fb_err = -errno; 389 return (0); 390 } 391 392 if (f->op.releasedir) { 393 realname = build_realname(f, vn->ino); 394 if (realname == NULL) { 395 fbuf->fb_err = -errno; 396 return (0); 397 } 398 399 fbuf->fb_err = f->op.releasedir(realname, &ffi); 400 free(realname); 401 } 402 403 return (0); 404} 405 406static int 407ifuse_ops_release(struct fuse *f, struct fusebuf *fbuf) 408{ 409 struct fuse_file_info ffi; 410 struct fuse_vnode *vn; 411 char *realname; 412 413 CHECK_OPT(release); 414 415 memset(&ffi, 0, sizeof(ffi)); 416 ffi.fh = fbuf->fb_io_fd; 417 ffi.fh_old = ffi.fh; 418 ffi.flags = fbuf->fb_io_flags; 419 420 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 421 if (vn == NULL) { 422 fbuf->fb_err = -errno; 423 return (0); 424 } 425 426 realname = build_realname(f, vn->ino); 427 if (realname == NULL) { 428 fbuf->fb_err = -errno; 429 return (0); 430 } 431 fbuf->fb_err = f->op.release(realname, &ffi); 432 free(realname); 433 434 return (0); 435} 436 437static int 438ifuse_ops_fsync(struct fuse *f, struct fusebuf *fbuf) 439{ 440 struct fuse_file_info ffi; 441 struct fuse_vnode *vn; 442 char *realname; 443 int datasync; 444 445 CHECK_OPT(fsync); 446 447 memset(&ffi, 0, sizeof(ffi)); 448 ffi.fh = fbuf->fb_io_fd; 449 450 /* 451 * fdatasync(2) is just a wrapper around fsync(2) so datasync 452 * is always false. 453 */ 454 datasync = 0; 455 456 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 457 if (vn == NULL) { 458 fbuf->fb_err = -errno; 459 return (0); 460 } 461 462 realname = build_realname(f, vn->ino); 463 if (realname == NULL) { 464 fbuf->fb_err = -errno; 465 return (0); 466 } 467 fbuf->fb_err = f->op.fsync(realname, datasync, &ffi); 468 free(realname); 469 470 return (0); 471} 472 473static int 474ifuse_ops_flush(struct fuse *f, struct fusebuf *fbuf) 475{ 476 struct fuse_file_info ffi; 477 struct fuse_vnode *vn; 478 char *realname; 479 480 CHECK_OPT(flush); 481 482 memset(&ffi, 0, sizeof(ffi)); 483 ffi.fh = fbuf->fb_io_fd; 484 ffi.fh_old = ffi.fh; 485 ffi.flush = 1; 486 487 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 488 if (vn == NULL) { 489 fbuf->fb_err = -errno; 490 return (0); 491 } 492 493 realname = build_realname(f, vn->ino); 494 if (realname == NULL) { 495 fbuf->fb_err = -errno; 496 return (0); 497 } 498 fbuf->fb_err = f->op.flush(realname, &ffi); 499 free(realname); 500 501 return (0); 502} 503 504static int 505ifuse_ops_lookup(struct fuse *f, struct fusebuf *fbuf) 506{ 507 struct fuse_vnode *vn; 508 char *realname; 509 510 DPRINTF("Opcode: lookup\t"); 511 DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino); 512 513 if (strcmp((const char *)fbuf->fb_dat, "..") == 0) { 514 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 515 if (vn == NULL || vn->parent == NULL) { 516 fbuf->fb_err = -ENOENT; 517 return (0); 518 } 519 vn = vn->parent; 520 if (vn->ino != FUSE_ROOT_INO) 521 ref_vn(vn); 522 } else { 523 vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino); 524 if (vn == NULL) { 525 vn = alloc_vn(f, (const char *)fbuf->fb_dat, -1, 526 fbuf->fb_ino); 527 if (vn == NULL) { 528 fbuf->fb_err = -errno; 529 free(fbuf->fb_dat); 530 return (0); 531 } 532 set_vn(f, vn); /*XXX*/ 533 } else if (vn->ino != FUSE_ROOT_INO) 534 ref_vn(vn); 535 } 536 537 realname = build_realname(f, vn->ino); 538 if (realname == NULL) { 539 fbuf->fb_err = -errno; 540 free(fbuf->fb_dat); 541 return (0); 542 } 543 544 fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn); 545 fbuf->fb_ino = vn->ino; 546 free(fbuf->fb_dat); 547 free(realname); 548 549 return (0); 550} 551 552static int 553ifuse_ops_read(struct fuse *f, struct fusebuf *fbuf) 554{ 555 struct fuse_file_info ffi; 556 struct fuse_vnode *vn; 557 char *realname; 558 uint64_t offset; 559 uint32_t size; 560 int ret; 561 562 CHECK_OPT(read); 563 564 memset(&ffi, 0, sizeof(ffi)); 565 ffi.fh = fbuf->fb_io_fd; 566 size = fbuf->fb_io_len; 567 offset = fbuf->fb_io_off; 568 569 fbuf->fb_dat = malloc(size); 570 if (fbuf->fb_dat == NULL) { 571 fbuf->fb_err = -errno; 572 return (0); 573 } 574 575 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 576 if (vn == NULL) { 577 fbuf->fb_err = -errno; 578 free(fbuf->fb_dat); 579 return (0); 580 } 581 582 realname = build_realname(f, vn->ino); 583 if (realname == NULL) { 584 fbuf->fb_err = -errno; 585 free(fbuf->fb_dat); 586 return (0); 587 } 588 589 ret = f->op.read(realname, (char *)fbuf->fb_dat, size, offset, &ffi); 590 free(realname); 591 if (ret >= 0) 592 fbuf->fb_len = ret; 593 else 594 fbuf->fb_err = ret; 595 596 if (fbuf->fb_len == 0) 597 free(fbuf->fb_dat); 598 599 return (0); 600} 601 602static int 603ifuse_ops_write(struct fuse *f, struct fusebuf *fbuf) 604{ 605 struct fuse_file_info ffi; 606 struct fuse_vnode *vn; 607 char *realname; 608 uint64_t offset; 609 uint32_t size; 610 int ret; 611 612 CHECK_OPT(write); 613 614 memset(&ffi, 0, sizeof(ffi)); 615 ffi.fh = fbuf->fb_io_fd; 616 ffi.fh_old = ffi.fh; 617 ffi.writepage = fbuf->fb_io_flags & 1; 618 size = fbuf->fb_io_len; 619 offset = fbuf->fb_io_off; 620 621 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 622 if (vn == NULL) { 623 fbuf->fb_err = -errno; 624 free(fbuf->fb_dat); 625 return (0); 626 } 627 628 realname = build_realname(f, vn->ino); 629 if (realname == NULL) { 630 fbuf->fb_err = -errno; 631 free(fbuf->fb_dat); 632 return (0); 633 } 634 635 ret = f->op.write(realname, (char *)fbuf->fb_dat, size, offset, &ffi); 636 free(realname); 637 free(fbuf->fb_dat); 638 639 if (ret >= 0) 640 fbuf->fb_io_len = ret; 641 else 642 fbuf->fb_err = ret; 643 644 return (0); 645} 646 647static int 648ifuse_ops_mkdir(struct fuse *f, struct fusebuf *fbuf) 649{ 650 struct fuse_vnode *vn; 651 char *realname; 652 uint32_t mode; 653 654 CHECK_OPT(mkdir); 655 656 mode = fbuf->fb_io_mode; 657 vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino); 658 if (vn == NULL) { 659 fbuf->fb_err = -errno; 660 free(fbuf->fb_dat); 661 return (0); 662 } 663 664 free(fbuf->fb_dat); 665 realname = build_realname(f, vn->ino); 666 if (realname == NULL) { 667 fbuf->fb_err = -errno; 668 return (0); 669 } 670 671 fbuf->fb_err = f->op.mkdir(realname, mode); 672 673 if (!fbuf->fb_err) { 674 fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn); 675 fbuf->fb_io_mode = fbuf->fb_attr.st_mode; 676 fbuf->fb_ino = vn->ino; 677 } 678 free(realname); 679 680 return (0); 681} 682 683static int 684ifuse_ops_rmdir(struct fuse *f, struct fusebuf *fbuf) 685{ 686 struct fuse_vnode *vn; 687 char *realname; 688 689 CHECK_OPT(rmdir); 690 vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino); 691 if (vn == NULL) { 692 fbuf->fb_err = -errno; 693 free(fbuf->fb_dat); 694 return (0); 695 } 696 697 free(fbuf->fb_dat); 698 realname = build_realname(f, vn->ino); 699 if (realname == NULL) { 700 fbuf->fb_err = -errno; 701 return (0); 702 } 703 704 fbuf->fb_err = f->op.rmdir(realname); 705 free(realname); 706 707 return (0); 708} 709 710static int 711ifuse_ops_readlink(struct fuse *f, struct fusebuf *fbuf) 712{ 713 struct fuse_vnode *vn; 714 char *realname; 715 char name[PATH_MAX + 1]; 716 int len, ret; 717 718 DPRINTF("Opcode: readlink\t"); 719 DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino); 720 721 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 722 if (vn == NULL) { 723 fbuf->fb_err = -errno; 724 return (0); 725 } 726 727 realname = build_realname(f, vn->ino); 728 if (realname == NULL) { 729 fbuf->fb_err = -errno; 730 return (0); 731 } 732 733 if (f->op.readlink) 734 ret = f->op.readlink(realname, name, sizeof(name)); 735 else 736 ret = -ENOSYS; 737 free(realname); 738 739 fbuf->fb_err = ret; 740 if (!ret) { 741 len = strnlen(name, PATH_MAX); 742 fbuf->fb_len = len; 743 fbuf->fb_dat = malloc(fbuf->fb_len); 744 if (fbuf->fb_dat == NULL) { 745 fbuf->fb_err = -errno; 746 return (0); 747 } 748 memcpy(fbuf->fb_dat, name, len); 749 } else 750 fbuf->fb_len = 0; 751 752 return (0); 753} 754 755static int 756ifuse_ops_unlink(struct fuse *f, struct fusebuf *fbuf) 757{ 758 struct fuse_vnode *vn; 759 char *realname; 760 761 CHECK_OPT(unlink); 762 763 vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino); 764 if (vn == NULL) { 765 free(fbuf->fb_dat); 766 fbuf->fb_err = -errno; 767 return (0); 768 } 769 770 free(fbuf->fb_dat); 771 realname = build_realname(f, vn->ino); 772 if (realname == NULL) { 773 fbuf->fb_err = -errno; 774 return (0); 775 } 776 777 fbuf->fb_err = f->op.unlink(realname); 778 free(realname); 779 780 return (0); 781} 782 783static int 784ifuse_ops_statfs(struct fuse *f, struct fusebuf *fbuf) 785{ 786 struct fuse_vnode *vn; 787 char *realname; 788 789 memset(&fbuf->fb_stat, 0, sizeof(fbuf->fb_stat)); 790 791 CHECK_OPT(statfs); 792 793 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 794 if (vn == NULL) { 795 fbuf->fb_err = -errno; 796 return (0); 797 } 798 799 realname = build_realname(f, vn->ino); 800 if (realname == NULL) { 801 fbuf->fb_err = -errno; 802 return (0); 803 } 804 805 fbuf->fb_err = f->op.statfs(realname, &fbuf->fb_stat); 806 free(realname); 807 808 return (0); 809} 810 811static int 812ifuse_ops_link(struct fuse *f, struct fusebuf *fbuf) 813{ 814 struct fuse_vnode *vn; 815 char *realname; 816 char *realname_ln; 817 ino_t oldnodeid; 818 819 CHECK_OPT(link); 820 oldnodeid = fbuf->fb_io_ino; 821 vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino); 822 if (vn == NULL) { 823 fbuf->fb_err = -errno; 824 free(fbuf->fb_dat); 825 return (0); 826 } 827 828 free(fbuf->fb_dat); 829 realname = build_realname(f, oldnodeid); 830 if (realname == NULL) { 831 fbuf->fb_err = -errno; 832 return (0); 833 } 834 835 realname_ln = build_realname(f, vn->ino); 836 if (realname_ln == NULL) { 837 fbuf->fb_err = -errno; 838 free(realname); 839 return (0); 840 } 841 842 fbuf->fb_err = f->op.link(realname, realname_ln); 843 free(realname); 844 free(realname_ln); 845 846 return (0); 847} 848 849static int 850ifuse_ops_setattr(struct fuse *f, struct fusebuf *fbuf) 851{ 852 struct fuse_vnode *vn; 853 struct timespec ts[2]; 854 struct utimbuf tbuf; 855 struct fb_io *io; 856 char *realname; 857 uid_t uid; 858 gid_t gid; 859 860 DPRINTF("Opcode: setattr\t"); 861 DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino); 862 863 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 864 if (vn == NULL) { 865 fbuf->fb_err = -errno; 866 free(fbuf->fb_dat); 867 return (0); 868 } 869 870 realname = build_realname(f, vn->ino); 871 if (realname == NULL) { 872 fbuf->fb_err = -errno; 873 free(fbuf->fb_dat); 874 return (0); 875 } 876 io = fbtod(fbuf, struct fb_io *); 877 878 if (io->fi_flags & FUSE_FATTR_MODE) { 879 if (f->op.chmod) 880 fbuf->fb_err = f->op.chmod(realname, 881 fbuf->fb_attr.st_mode); 882 else 883 fbuf->fb_err = -ENOSYS; 884 } 885 886 if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_UID || 887 io->fi_flags & FUSE_FATTR_GID) ) { 888 uid = (io->fi_flags & FUSE_FATTR_UID) ? 889 fbuf->fb_attr.st_uid : (uid_t)-1; 890 gid = (io->fi_flags & FUSE_FATTR_GID) ? 891 fbuf->fb_attr.st_gid : (gid_t)-1; 892 if (f->op.chown) 893 fbuf->fb_err = f->op.chown(realname, uid, gid); 894 else 895 fbuf->fb_err = -ENOSYS; 896 } 897 898 if (!fbuf->fb_err && ( io->fi_flags & FUSE_FATTR_MTIME || 899 io->fi_flags & FUSE_FATTR_ATIME)) { 900 901 if (f->op.utimens) { 902 ts[0] = fbuf->fb_attr.st_atim; 903 ts[1] = fbuf->fb_attr.st_mtim; 904 fbuf->fb_err = f->op.utimens(realname, ts); 905 } else if (f->op.utime) { 906 tbuf.actime = fbuf->fb_attr.st_atim.tv_sec; 907 tbuf.modtime = fbuf->fb_attr.st_mtim.tv_sec; 908 fbuf->fb_err = f->op.utime(realname, &tbuf); 909 } else 910 fbuf->fb_err = -ENOSYS; 911 } 912 913 if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_SIZE)) { 914 if (f->op.truncate) 915 fbuf->fb_err = f->op.truncate(realname, 916 fbuf->fb_attr.st_size); 917 else 918 fbuf->fb_err = -ENOSYS; 919 } 920 921 memset(&fbuf->fb_attr, 0, sizeof(struct stat)); 922 923 if (!fbuf->fb_err) 924 fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn); 925 free(realname); 926 free(fbuf->fb_dat); 927 928 return (0); 929} 930 931static int 932ifuse_ops_symlink(unused struct fuse *f, struct fusebuf *fbuf) 933{ 934 struct fuse_vnode *vn; 935 char *realname; 936 int len; 937 938 CHECK_OPT(symlink); 939 940 vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino); 941 if (vn == NULL) { 942 fbuf->fb_err = -errno; 943 free(fbuf->fb_dat); 944 return (0); 945 } 946 947 len = strlen((char *)fbuf->fb_dat); 948 949 realname = build_realname(f, vn->ino); 950 if (realname == NULL) { 951 fbuf->fb_err = -errno; 952 free(fbuf->fb_dat); 953 return (0); 954 } 955 956 /* fuse invert the symlink params */ 957 fbuf->fb_err = f->op.symlink((const char *)&fbuf->fb_dat[len + 1], 958 realname); 959 fbuf->fb_ino = vn->ino; 960 free(fbuf->fb_dat); 961 free(realname); 962 963 return (0); 964} 965 966static int 967ifuse_ops_rename(struct fuse *f, struct fusebuf *fbuf) 968{ 969 struct fuse_vnode *vnt; 970 struct fuse_vnode *vnf; 971 char *realnamef; 972 char *realnamet; 973 int len; 974 975 CHECK_OPT(rename); 976 977 len = strlen((char *)fbuf->fb_dat); 978 vnf = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino); 979 if (vnf == NULL) { 980 fbuf->fb_err = -errno; 981 free(fbuf->fb_dat); 982 return (0); 983 } 984 985 vnt = get_vn_by_name_and_parent(f, &fbuf->fb_dat[len + 1], 986 fbuf->fb_io_ino); 987 if (vnt == NULL) { 988 fbuf->fb_err = -errno; 989 free(fbuf->fb_dat); 990 return (0); 991 } 992 993 free(fbuf->fb_dat); 994 995 realnamef = build_realname(f, vnf->ino); 996 if (realnamef == NULL) { 997 fbuf->fb_err = -errno; 998 return (0); 999 } 1000 1001 realnamet = build_realname(f, vnt->ino); 1002 if (realnamet == NULL) { 1003 fbuf->fb_err = -errno; 1004 free(realnamef); 1005 return (0); 1006 } 1007 1008 fbuf->fb_err = f->op.rename(realnamef, realnamet); 1009 free(realnamef); 1010 free(realnamet); 1011 1012 return (0); 1013} 1014 1015static int 1016ifuse_ops_destroy(struct fuse *f) 1017{ 1018 struct fuse_context *ctx; 1019 1020 DPRINTF("Opcode: destroy\n"); 1021 1022 if (f->op.destroy) { 1023 ctx = fuse_get_context(); 1024 1025 f->op.destroy((ctx)?ctx->private_data:NULL); 1026 } 1027 1028 f->fc->dead = 1; 1029 1030 return (0); 1031} 1032 1033static int 1034ifuse_ops_reclaim(struct fuse *f, struct fusebuf *fbuf) 1035{ 1036 struct fuse_vnode *vn; 1037 1038 DPRINTF("Opcode: reclaim\t"); 1039 DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino); 1040 1041 vn = tree_get(&f->vnode_tree, fbuf->fb_ino); 1042 if (vn != NULL) 1043 unref_vn(f, vn); 1044 1045 return (0); 1046} 1047 1048static int 1049ifuse_ops_mknod(struct fuse *f, struct fusebuf *fbuf) 1050{ 1051 struct fuse_vnode *vn; 1052 char *realname; 1053 uint32_t mode; 1054 dev_t dev; 1055 1056 CHECK_OPT(mknod); 1057 1058 mode = fbuf->fb_io_mode; 1059 dev = fbuf->fb_io_rdev; 1060 vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino); 1061 if (vn == NULL) { 1062 fbuf->fb_err = -errno; 1063 free(fbuf->fb_dat); 1064 return (0); 1065 } 1066 1067 free(fbuf->fb_dat); 1068 realname = build_realname(f, vn->ino); 1069 if (realname == NULL) { 1070 fbuf->fb_err = -errno; 1071 return (0); 1072 } 1073 1074 fbuf->fb_err = f->op.mknod(realname, mode, dev); 1075 1076 if (!fbuf->fb_err) { 1077 fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn); 1078 fbuf->fb_io_mode = fbuf->fb_attr.st_mode; 1079 fbuf->fb_ino = vn->ino; 1080 } 1081 free(realname); 1082 1083 return (0); 1084} 1085 1086int 1087ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf) 1088{ 1089 int ret = 0; 1090 1091 fbuf->fb_len = 0; 1092 fbuf->fb_err = 0; 1093 1094 switch (fbuf->fb_type) { 1095 case FBT_LOOKUP: 1096 ret = ifuse_ops_lookup(f, fbuf); 1097 break; 1098 case FBT_GETATTR: 1099 ret = ifuse_ops_getattr(f, fbuf); 1100 break; 1101 case FBT_SETATTR: 1102 ret = ifuse_ops_setattr(f, fbuf); 1103 break; 1104 case FBT_READLINK: 1105 ret = ifuse_ops_readlink(f, fbuf); 1106 break; 1107 case FBT_MKDIR: 1108 ret = ifuse_ops_mkdir(f, fbuf); 1109 break; 1110 case FBT_UNLINK: 1111 ret = ifuse_ops_unlink(f, fbuf); 1112 break; 1113 case FBT_RMDIR: 1114 ret = ifuse_ops_rmdir(f, fbuf); 1115 break; 1116 case FBT_LINK: 1117 ret = ifuse_ops_link(f, fbuf); 1118 break; 1119 case FBT_OPEN: 1120 ret = ifuse_ops_open(f, fbuf); 1121 break; 1122 case FBT_READ: 1123 ret = ifuse_ops_read(f, fbuf); 1124 break; 1125 case FBT_WRITE: 1126 ret = ifuse_ops_write(f, fbuf); 1127 break; 1128 case FBT_STATFS: 1129 ret = ifuse_ops_statfs(f, fbuf); 1130 break; 1131 case FBT_RELEASE: 1132 ret = ifuse_ops_release(f, fbuf); 1133 break; 1134 case FBT_FSYNC: 1135 ret = ifuse_ops_fsync(f, fbuf); 1136 break; 1137 case FBT_FLUSH: 1138 ret = ifuse_ops_flush(f, fbuf); 1139 break; 1140 case FBT_INIT: 1141 ret = ifuse_ops_init(f); 1142 break; 1143 case FBT_OPENDIR: 1144 ret = ifuse_ops_opendir(f, fbuf); 1145 break; 1146 case FBT_READDIR: 1147 ret = ifuse_ops_readdir(f, fbuf); 1148 break; 1149 case FBT_RELEASEDIR: 1150 ret = ifuse_ops_releasedir(f, fbuf); 1151 break; 1152 case FBT_ACCESS: 1153 ret = ifuse_ops_access(f, fbuf); 1154 break; 1155 case FBT_SYMLINK: 1156 ret = ifuse_ops_symlink(f, fbuf); 1157 break; 1158 case FBT_RENAME: 1159 ret = ifuse_ops_rename(f, fbuf); 1160 break; 1161 case FBT_DESTROY: 1162 ret = ifuse_ops_destroy(f); 1163 break; 1164 case FBT_RECLAIM: 1165 ret = ifuse_ops_reclaim(f, fbuf); 1166 break; 1167 case FBT_MKNOD: 1168 ret = ifuse_ops_mknod(f, fbuf); 1169 break; 1170 default: 1171 DPRINTF("Opcode: %i not supported\t", fbuf->fb_type); 1172 DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino); 1173 1174 fbuf->fb_err = -ENOSYS; 1175 fbuf->fb_len = 0; 1176 } 1177 DPRINTF("\n"); 1178 1179 /* fuse api use negative errno */ 1180 fbuf->fb_err = -fbuf->fb_err; 1181 return (ret); 1182} 1183