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