/core/10.4/fusefs/fuse_internal.c
C | 1525 lines | 1089 code | 299 blank | 137 comment | 208 complexity | b0aae47d34ad691836998bb76a57abe1 MD5 | raw file
1/* 2 * Copyright (C) 2006-2008 Google. All Rights Reserved. 3 * Amit Singh <singh@> 4 */ 5 6#include <sys/param.h> 7#include <kern/assert.h> 8#include <libkern/libkern.h> 9#include <libkern/OSMalloc.h> 10#include <libkern/locks.h> 11#include <mach/mach_types.h> 12#include <sys/dirent.h> 13#include <sys/disk.h> 14#include <sys/errno.h> 15#include <sys/fcntl.h> 16#include <sys/kernel_types.h> 17#include <sys/mount.h> 18#include <sys/proc.h> 19#include <sys/stat.h> 20#include <sys/ubc.h> 21#include <sys/unistd.h> 22#include <sys/vnode.h> 23#include <sys/vnode_if.h> 24#include <sys/xattr.h> 25#include <sys/buf.h> 26#include <sys/namei.h> 27#include <sys/mman.h> 28 29#include "fuse.h" 30#include "fuse_file.h" 31#include "fuse_internal.h" 32#include "fuse_ipc.h" 33#include "fuse_locking.h" 34#include "fuse_node.h" 35#include "fuse_file.h" 36#include "fuse_nodehash.h" 37#include "fuse_sysctl.h" 38#include "fuse_kludges.h" 39 40/* access */ 41 42__private_extern__ 43int 44fuse_internal_access(vnode_t vp, 45 int action, 46 vfs_context_t context, 47 struct fuse_access_param *facp) 48{ 49 int err = 0; 50 int default_error = 0; 51 uint32_t mask = 0; 52 int dataflags; 53 mount_t mp; 54 struct fuse_dispatcher fdi; 55 struct fuse_access_in *fai; 56 struct fuse_data *data; 57 58 fuse_trace_printf_func(); 59 60 mp = vnode_mount(vp); 61 62 data = fuse_get_mpdata(mp); 63 dataflags = data->dataflags; 64 65 /* Allow for now; let checks be handled inline later. */ 66 if (fuse_isdeferpermissions_mp(mp)) { 67 return 0; 68 } 69 70 if (facp->facc_flags & FACCESS_FROM_VNOP) { 71 default_error = ENOTSUP; 72 } 73 74 /* 75 * (action & KAUTH_VNODE_GENERIC_WRITE_BITS) on a read-only file system 76 * would have been handled by higher layers. 77 */ 78 79 if (!fuse_implemented(data, FSESS_NOIMPLBIT(ACCESS))) { 80 return default_error; 81 } 82 83 /* Unless explicitly permitted, deny everyone except the fs owner. */ 84 if (!vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) { 85 if (!(dataflags & FSESS_ALLOW_OTHER)) { 86 int denied = fuse_match_cred(data->daemoncred, 87 vfs_context_ucred(context)); 88 if (denied) { 89 return EPERM; 90 } 91 } 92 facp->facc_flags |= FACCESS_NOCHECKSPY; 93 } 94 95 if (!(facp->facc_flags & FACCESS_DO_ACCESS)) { 96 return default_error; 97 } 98 99 if (vnode_isdir(vp)) { 100 if (action & (KAUTH_VNODE_LIST_DIRECTORY | 101 KAUTH_VNODE_READ_EXTATTRIBUTES)) { 102 mask |= R_OK; 103 } 104 if (action & (KAUTH_VNODE_ADD_FILE | 105 KAUTH_VNODE_ADD_SUBDIRECTORY | 106 KAUTH_VNODE_DELETE_CHILD)) { 107 mask |= W_OK; 108 } 109 if (action & KAUTH_VNODE_SEARCH) { 110 mask |= X_OK; 111 } 112 } else { 113 if (action & (KAUTH_VNODE_READ_DATA | KAUTH_VNODE_READ_EXTATTRIBUTES)) { 114 mask |= R_OK; 115 } 116 if (action & (KAUTH_VNODE_WRITE_DATA | KAUTH_VNODE_APPEND_DATA)) { 117 mask |= W_OK; 118 } 119 if (action & KAUTH_VNODE_EXECUTE) { 120 mask |= X_OK; 121 } 122 } 123 124 if (action & (KAUTH_VNODE_WRITE_ATTRIBUTES | 125 KAUTH_VNODE_WRITE_EXTATTRIBUTES | 126 KAUTH_VNODE_WRITE_SECURITY)) { 127 mask |= W_OK; 128 } 129 130 bzero(&fdi, sizeof(fdi)); 131 132 fdisp_init(&fdi, sizeof(*fai)); 133 fdisp_make_vp(&fdi, FUSE_ACCESS, vp, context); 134 135 fai = fdi.indata; 136 fai->mask = F_OK; 137 fai->mask |= mask; 138 139 if (!(err = fdisp_wait_answ(&fdi))) { 140 fuse_ticket_drop(fdi.tick); 141 } 142 143 if (err == ENOSYS) { 144 /* 145 * Make sure we don't come in here again. 146 */ 147 vfs_clearauthopaque(mp); 148 fuse_clear_implemented(data, FSESS_NOIMPLBIT(ACCESS)); 149 err = default_error; 150 } 151 152 if (err == ENOENT) { 153 154 const char *vname = NULL; 155 156#if M_MACFUSE_ENABLE_UNSUPPORTED 157 vname = vnode_getname(vp); 158#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ 159 160 IOLog("MacFUSE: disappearing vnode %p (name=%s type=%d action=%x)\n", 161 vp, (vname) ? vname : "?", vnode_vtype(vp), action); 162 163#if M_MACFUSE_ENABLE_UNSUPPORTED 164 if (vname) { 165 vnode_putname(vname); 166 } 167#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ 168 169 /* 170 * On 10.4, I think I can get Finder to lock because of /.Trashes/<uid> 171 * unless I use REVOKE_NONE here. 172 */ 173 174 fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT); 175 } 176 177 return err; 178} 179 180#if M_MACFUSE_ENABLE_EXCHANGE 181 182/* exchange */ 183 184__private_extern__ 185int 186fuse_internal_exchange(vnode_t fvp, 187 const char *fname, 188 size_t flen, 189 vnode_t tvp, 190 const char *tname, 191 size_t tlen, 192 int options, 193 vfs_context_t context) 194{ 195 struct fuse_dispatcher fdi; 196 struct fuse_exchange_in *fei; 197 struct fuse_vnode_data *ffud = VTOFUD(fvp); 198 struct fuse_vnode_data *tfud = VTOFUD(tvp); 199 vnode_t fdvp = ffud->parentvp; 200 vnode_t tdvp = tfud->parentvp; 201 int err = 0; 202 203 fdisp_init(&fdi, sizeof(*fei) + flen + tlen + 2); 204 fdisp_make_vp(&fdi, FUSE_EXCHANGE, fvp, context); 205 206 fei = fdi.indata; 207 fei->olddir = VTOI(fdvp); 208 fei->newdir = VTOI(tdvp); 209 fei->options = (uint64_t)options; 210 211 memcpy((char *)fdi.indata + sizeof(*fei), fname, flen); 212 ((char *)fdi.indata)[sizeof(*fei) + flen] = '\0'; 213 214 memcpy((char *)fdi.indata + sizeof(*fei) + flen + 1, tname, tlen); 215 ((char *)fdi.indata)[sizeof(*fei) + flen + tlen + 1] = '\0'; 216 217 ubc_sync_range(fvp, (off_t)0, (off_t)ffud->filesize, 218 UBC_PUSHALL | UBC_INVALIDATE | UBC_SYNC); 219 ubc_sync_range(tvp, (off_t)0, (off_t)tfud->filesize, 220 UBC_PUSHALL | UBC_INVALIDATE | UBC_SYNC); 221 222 if (!(err = fdisp_wait_answ(&fdi))) { 223 fuse_ticket_drop(fdi.tick); 224 } 225 226 if (err == 0) { 227 if (fdvp) { 228 fuse_invalidate_attr(fdvp); 229 } 230 if (tdvp != fdvp) { 231 if (tdvp) { 232 fuse_invalidate_attr(tdvp); 233 } 234 } 235 236 fuse_invalidate_attr(fvp); 237 fuse_invalidate_attr(tvp); 238 239 cache_purge(fvp); 240 cache_purge(tvp); 241 242 /* Swap sizes */ 243 off_t tmpfilesize = ffud->filesize; 244 ffud->filesize = tfud->filesize; 245 tfud->filesize = tmpfilesize; 246 ubc_setsize(fvp, (off_t)ffud->filesize); 247 ubc_setsize(tvp, (off_t)tfud->filesize); 248 249 fuse_kludge_exchange(fvp, tvp); 250 251 /* 252 * Another approach (will need additional kernel support to work): 253 * 254 vnode_t tmpvp = ffud->vp; 255 ffud->vp = tfud->vp; 256 tfud->vp = tmpvp; 257 258 vnode_t tmpparentvp = ffud->parentvp; 259 ffud->parentvp = tfud->parentvp; 260 tfud->parentvp = tmpparentvp; 261 262 off_t tmpfilesize = ffud->filesize; 263 ffud->filesize = tfud->filesize; 264 tfud->filesize = tmpfilesize; 265 266 struct fuse_vnode_data tmpfud; 267 memcpy(&tmpfud, ffud, sizeof(struct fuse_vnode_data)); 268 memcpy(ffud, tfud, sizeof(struct fuse_vnode_data)); 269 memcpy(tfud, &tmpfud, sizeof(struct fuse_vnode_data)); 270 271 HNodeExchangeFromFSNode(ffud, tfud); 272 * 273 */ 274 } 275 276 return err; 277} 278 279#endif /* M_MACFUSE_ENABLE_EXCHANGE */ 280 281/* fsync */ 282 283__private_extern__ 284int 285fuse_internal_fsync_callback(struct fuse_ticket *ftick, __unused uio_t uio) 286{ 287 fuse_trace_printf_func(); 288 289 if (ftick->tk_aw_ohead.error == ENOSYS) { 290 if (fticket_opcode(ftick) == FUSE_FSYNC) { 291 fuse_clear_implemented(ftick->tk_data, FSESS_NOIMPLBIT(FSYNC)); 292 } else if (fticket_opcode(ftick) == FUSE_FSYNCDIR) { 293 fuse_clear_implemented(ftick->tk_data, FSESS_NOIMPLBIT(FSYNCDIR)); 294 } else { 295 IOLog("MacFUSE: unexpected opcode in sync handling\n"); 296 } 297 } 298 299 fuse_ticket_drop(ftick); 300 301 return 0; 302} 303 304__private_extern__ 305int 306fuse_internal_fsync(vnode_t vp, 307 vfs_context_t context, 308 struct fuse_filehandle *fufh, 309 void *param, 310 fuse_op_waitfor_t waitfor) 311{ 312 int err = 0; 313 int op = FUSE_FSYNC; 314 struct fuse_fsync_in *ffsi; 315 struct fuse_dispatcher *fdip = param; 316 317 fuse_trace_printf_func(); 318 319 fdip->iosize = sizeof(*ffsi); 320 fdip->tick = NULL; 321 if (vnode_isdir(vp)) { 322 op = FUSE_FSYNCDIR; 323 } 324 325 fdisp_make_vp(fdip, op, vp, context); 326 ffsi = fdip->indata; 327 ffsi->fh = fufh->fh_id; 328 329 ffsi->fsync_flags = 1; /* datasync */ 330 331 if (waitfor == FUSE_OP_FOREGROUNDED) { 332 if ((err = fdisp_wait_answ(fdip))) { 333 if (err == ENOSYS) { 334 if (op == FUSE_FSYNC) { 335 fuse_clear_implemented(fdip->tick->tk_data, 336 FSESS_NOIMPLBIT(FSYNC)); 337 } else if (op == FUSE_FSYNCDIR) { 338 fuse_clear_implemented(fdip->tick->tk_data, 339 FSESS_NOIMPLBIT(FSYNCDIR)); 340 } 341 } 342 goto out; 343 } else { 344 fuse_ticket_drop(fdip->tick); 345 } 346 } else { 347 fuse_insert_callback(fdip->tick, fuse_internal_fsync_callback); 348 fuse_insert_message(fdip->tick); 349 } 350 351out: 352 return err; 353} 354 355/* getattr sidekicks */ 356__private_extern__ 357int 358fuse_internal_loadxtimes(vnode_t vp, struct vnode_attr *out_vap, 359 vfs_context_t context) 360{ 361 struct vnode_attr *in_vap = VTOVA(vp); 362 struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp)); 363 struct fuse_dispatcher fdi; 364 struct fuse_getxtimes_out *fgxo = NULL; 365 int isvroot = vnode_isvroot(vp); 366 struct timespec t = { 0, 0 }; 367 const struct timespec kZeroTime = { 0, 0 }; 368 int err = 0; 369 370 if (!(data->dataflags & FSESS_XTIMES)) { 371 /* We don't return anything. */ 372 goto out; 373 } 374 375 if (VTOFUD(vp)->c_flag & C_XTIMES_VALID) { 376 VATTR_RETURN(out_vap, va_backup_time, in_vap->va_backup_time); 377 VATTR_RETURN(out_vap, va_create_time, in_vap->va_create_time); 378 goto out; 379 } 380 381 if (!fuse_implemented(data, FSESS_NOIMPLBIT(GETXTIMES))) { 382 goto fake; 383 } 384 385 if (fuse_isdeadfs(vp) && isvroot) { 386 goto fake; 387 } 388 389 if (!(data->dataflags & FSESS_INITED) && isvroot) { 390 goto fake; 391 } 392 393 err = fdisp_simple_putget_vp(&fdi, FUSE_GETXTIMES, vp, context); 394 if (err) { 395 /* We don't ever treat this as a hard error. */ 396 err = 0; 397 goto fake; 398 } 399 400 fgxo = (struct fuse_getxtimes_out *)fdi.answ; 401 402 t.tv_sec = (time_t)fgxo->bkuptime; /* XXX: truncation */ 403 t.tv_nsec = fgxo->bkuptimensec; 404 VATTR_RETURN(in_vap, va_backup_time, t); 405 VATTR_RETURN(out_vap, va_backup_time, t); 406 407 t.tv_sec = (time_t)fgxo->crtime; /* XXX: truncation */ 408 t.tv_nsec = fgxo->crtimensec; 409 VATTR_RETURN(in_vap, va_create_time, t); 410 VATTR_RETURN(out_vap, va_create_time, t); 411 412 fuse_ticket_drop(fdi.tick); 413 414 VTOFUD(vp)->c_flag |= C_XTIMES_VALID; 415 416 goto out; 417 418fake: 419 VATTR_RETURN(out_vap, va_backup_time, kZeroTime); 420 VATTR_RETURN(out_vap, va_create_time, kZeroTime); 421 422out: 423 return err; 424} 425 426/* ioctl */ 427__private_extern__ 428int 429fuse_internal_ioctl_avfi(vnode_t vp, __unused vfs_context_t context, 430 struct fuse_avfi_ioctl *avfi) 431{ 432 int ret = 0; 433 uint32_t hint = 0; 434 435 if (!avfi) { 436 return EINVAL; 437 } 438 439 if (avfi->cmd & FUSE_AVFI_MARKGONE) { 440 441 /* 442 * TBD 443 */ 444 return EINVAL; 445 } 446 447 /* The result of this /does/ alter our return value. */ 448 if (avfi->cmd & FUSE_AVFI_UBC) { 449 int ubc_flags = avfi->ubc_flags & (UBC_PUSHDIRTY | UBC_PUSHALL | 450 UBC_INVALIDATE | UBC_SYNC); 451 if (ubc_sync_range(vp, (off_t)0, ubc_getsize(vp), ubc_flags) == 0) { 452 /* failed */ 453 ret = EINVAL; /* don't really have a good error to return */ 454 } 455 } 456 457 if (avfi->cmd & FUSE_AVFI_UBC_SETSIZE) { 458 if (VTOFUD(vp)->filesize != avfi->size) { 459 hint |= NOTE_WRITE; 460 if (avfi->size > VTOFUD(vp)->filesize) { 461 hint |= NOTE_EXTEND; 462 } 463 VTOFUD(vp)->filesize = avfi->size; 464 ubc_setsize(vp, avfi->size); 465 } 466 (void)fuse_invalidate_attr(vp); 467 } 468 469 /* The result of this doesn't alter our return value. */ 470 if (avfi->cmd & FUSE_AVFI_PURGEATTRCACHE) { 471 hint |= NOTE_ATTRIB; 472 (void)fuse_invalidate_attr(vp); 473 } 474 475 /* The result of this doesn't alter our return value. */ 476 if (avfi->cmd & FUSE_AVFI_PURGEVNCACHE) { 477 (void)fuse_vncache_purge(vp); 478 } 479 480 if (avfi->cmd & FUSE_AVFI_KNOTE) { 481 hint |= avfi->note; 482 } 483 484 if (hint) { 485 FUSE_KNOTE(vp, hint); 486 } 487 488 return ret; 489} 490 491/* readdir */ 492 493__private_extern__ 494int 495fuse_internal_readdir(vnode_t vp, 496 uio_t uio, 497 vfs_context_t context, 498 struct fuse_filehandle *fufh, 499 struct fuse_iov *cookediov, 500 int *numdirent) 501{ 502 int err = 0; 503 struct fuse_dispatcher fdi; 504 struct fuse_read_in *fri; 505 struct fuse_data *data; 506 507 if (uio_resid(uio) == 0) { 508 return 0; 509 } 510 511 fdisp_init(&fdi, 0); 512 513 /* Note that we DO NOT have a UIO_SYSSPACE here (so no need for p2p I/O). */ 514 515 while (uio_resid(uio) > 0) { 516 517 fdi.iosize = sizeof(*fri); 518 fdisp_make_vp(&fdi, FUSE_READDIR, vp, context); 519 520 fri = fdi.indata; 521 fri->fh = fufh->fh_id; 522 fri->offset = uio_offset(uio); 523 data = fuse_get_mpdata(vnode_mount(vp)); 524 fri->size = (typeof(fri->size))min((size_t)uio_resid(uio), data->iosize); 525 526 if ((err = fdisp_wait_answ(&fdi))) { 527 goto out; 528 } 529 530 if ((err = fuse_internal_readdir_processdata(vp, 531 uio, 532 fri->size, 533 fdi.answ, 534 fdi.iosize, 535 cookediov, 536 numdirent))) { 537 break; 538 } 539 } 540 541/* done: */ 542 543 fuse_ticket_drop(fdi.tick); 544 545out: 546 return ((err == -1) ? 0 : err); 547} 548 549__private_extern__ 550int 551fuse_internal_readdir_processdata(vnode_t vp, 552 uio_t uio, 553 __unused size_t reqsize, 554 void *buf, 555 size_t bufsize, 556 struct fuse_iov *cookediov, 557 int *numdirent) 558{ 559 int err = 0; 560 int cou = 0; 561 int n = 0; 562 size_t bytesavail; 563 size_t freclen; 564 565 struct dirent *de; 566 struct fuse_dirent *fudge; 567 568 if (bufsize < FUSE_NAME_OFFSET) { 569 return -1; 570 } 571 572 for (;;) { 573 574 if (bufsize < FUSE_NAME_OFFSET) { 575 err = -1; 576 break; 577 } 578 579 fudge = (struct fuse_dirent *)buf; 580 freclen = FUSE_DIRENT_SIZE(fudge); 581 582 cou++; 583 584 if (bufsize < freclen) { 585 err = ((cou == 1) ? -1 : 0); 586 break; 587 } 588 589 /* 590 * if (isbzero(buf, FUSE_NAME_OFFSET)) { 591 * // zero-pad incomplete buffer 592 * ... 593 * err = -1; 594 * break; 595 * } 596 */ 597 598 if (!fudge->namelen) { 599 err = EINVAL; 600 break; 601 } 602 603 if (fudge->namelen > MAXNAMLEN) { 604 err = EIO; 605 break; 606 } 607 608#define GENERIC_DIRSIZ(dp) \ 609 ((sizeof(struct dirent) - (MAXNAMLEN + 1)) + (((dp)->d_namlen + 1 + 3) & ~3)) 610 611 bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)&fudge->namelen); 612 613 if (bytesavail > (size_t)uio_resid(uio)) { 614 err = -1; 615 break; 616 } 617 618 fiov_refresh(cookediov); 619 fiov_adjust(cookediov, bytesavail); 620 621 de = (struct dirent *)cookediov->base; 622#if __DARWIN_64_BIT_INO_T 623 de->d_fileno = fudge->ino; 624#else 625 de->d_fileno = (ino_t)fudge->ino; /* XXX: truncation */ 626#endif /* __DARWIN_64_BIT_INO_T */ 627 de->d_reclen = bytesavail; 628 de->d_type = fudge->type; 629 de->d_namlen = fudge->namelen; 630 631 /* Filter out any ._* files if the mount is configured as such. */ 632 if (fuse_skip_apple_double_mp(vnode_mount(vp), 633 fudge->name, fudge->namelen)) { 634 de->d_fileno = 0; 635 de->d_type = DT_WHT; 636 } 637 638 memcpy((char *)cookediov->base + sizeof(struct dirent) - MAXNAMLEN - 1, 639 (char *)buf + FUSE_NAME_OFFSET, fudge->namelen); 640 ((char *)cookediov->base)[bytesavail] = '\0'; 641 642 err = uiomove(cookediov->base, (int)cookediov->len, uio); 643 if (err) { 644 break; 645 } 646 647 n++; 648 649 buf = (char *)buf + freclen; 650 bufsize -= freclen; 651 uio_setoffset(uio, fudge->off); 652 } 653 654 if (!err && numdirent) { 655 *numdirent = n; 656 } 657 658 return err; 659} 660 661/* remove */ 662 663static int 664fuse_internal_remove_callback(vnode_t vp, void *cargs) 665{ 666 struct vnode_attr *vap; 667 uint64_t target_nlink; 668 669 vap = VTOVA(vp); 670 671 target_nlink = *(uint64_t *)cargs; 672 673 /* somewhat lame "heuristics", but you got better ideas? */ 674 if ((vap->va_nlink == target_nlink) && vnode_isreg(vp)) { 675 fuse_invalidate_attr(vp); 676 } 677 678 return VNODE_RETURNED; 679} 680 681__private_extern__ 682int 683fuse_internal_remove(vnode_t dvp, 684 vnode_t vp, 685 struct componentname *cnp, 686 enum fuse_opcode op, 687 vfs_context_t context) 688{ 689 struct fuse_dispatcher fdi; 690 691 struct vnode_attr *vap = VTOVA(vp); 692 int need_invalidate = 0; 693 uint64_t target_nlink = 0; 694 mount_t mp = vnode_mount(vp); 695 696 int err = 0; 697 698 fdisp_init(&fdi, cnp->cn_namelen + 1); 699 fdisp_make_vp(&fdi, op, dvp, context); 700 701 memcpy(fdi.indata, cnp->cn_nameptr, cnp->cn_namelen); 702 ((char *)fdi.indata)[cnp->cn_namelen] = '\0'; 703 704 if ((vap->va_nlink > 1) && vnode_isreg(vp)) { 705 need_invalidate = 1; 706 target_nlink = vap->va_nlink; 707 } 708 709 if (!(err = fdisp_wait_answ(&fdi))) { 710 fuse_ticket_drop(fdi.tick); 711 } 712 713 fuse_invalidate_attr(dvp); 714 fuse_invalidate_attr(vp); 715 716 /* 717 * XXX: M_MACFUSE_INVALIDATE_CACHED_VATTRS_UPON_UNLINK 718 * 719 * Consider the case where vap->va_nlink > 1 for the entity being 720 * removed. In our world, other in-memory vnodes that share a link 721 * count each with this one may not know right way that this one just 722 * got deleted. We should let them know, say, through a vnode_iterate() 723 * here and a callback that does fuse_invalidate_attr(vp) on each 724 * relevant vnode. 725 */ 726 if (need_invalidate && !err) { 727 if (!vfs_busy(mp, LK_NOWAIT)) { 728 vnode_iterate(mp, 0, fuse_internal_remove_callback, 729 (void *)&target_nlink); 730 vfs_unbusy(mp); 731 } else { 732 IOLog("MacFUSE: skipping link count fixup upon remove\n"); 733 } 734 } 735 736 return err; 737} 738 739/* rename */ 740 741__private_extern__ 742int 743fuse_internal_rename(vnode_t fdvp, 744 __unused vnode_t fvp, 745 struct componentname *fcnp, 746 vnode_t tdvp, 747 __unused vnode_t tvp, 748 struct componentname *tcnp, 749 vfs_context_t context) 750{ 751 struct fuse_dispatcher fdi; 752 struct fuse_rename_in *fri; 753 int err = 0; 754 755 fdisp_init(&fdi, sizeof(*fri) + fcnp->cn_namelen + tcnp->cn_namelen + 2); 756 fdisp_make_vp(&fdi, FUSE_RENAME, fdvp, context); 757 758 fri = fdi.indata; 759 fri->newdir = VTOI(tdvp); 760 memcpy((char *)fdi.indata + sizeof(*fri), fcnp->cn_nameptr, 761 fcnp->cn_namelen); 762 ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen] = '\0'; 763 memcpy((char *)fdi.indata + sizeof(*fri) + fcnp->cn_namelen + 1, 764 tcnp->cn_nameptr, tcnp->cn_namelen); 765 ((char *)fdi.indata)[sizeof(*fri) + fcnp->cn_namelen + 766 tcnp->cn_namelen + 1] = '\0'; 767 768 if (!(err = fdisp_wait_answ(&fdi))) { 769 fuse_ticket_drop(fdi.tick); 770 } 771 772 if (err == 0) { 773 fuse_invalidate_attr(fdvp); 774 if (tdvp != fdvp) { 775 fuse_invalidate_attr(tdvp); 776 } 777 } 778 779 return err; 780} 781 782/* revoke */ 783 784__private_extern__ 785int 786fuse_internal_revoke(vnode_t vp, int flags, vfs_context_t context, int how) 787{ 788 int ret = 0; 789 struct fuse_vnode_data *fvdat = VTOFUD(vp); 790 791 fvdat->flag |= FN_REVOKED; 792 793 if (how == REVOKE_HARD) { 794 ret = vn_revoke(vp, flags, context); 795 } 796 797 return ret; 798} 799 800/* strategy */ 801 802__private_extern__ 803int 804fuse_internal_strategy(vnode_t vp, buf_t bp) 805{ 806 size_t biosize; 807 size_t chunksize; 808 size_t respsize; 809 810 int mapped = FALSE; 811 int mode; 812 int op; 813 int vtype = vnode_vtype(vp); 814 815 int err = 0; 816 817 caddr_t bufdat; 818 off_t left; 819 off_t offset; 820 int32_t bflags = buf_flags(bp); 821 822 fufh_type_t fufh_type; 823 struct fuse_dispatcher fdi; 824 struct fuse_data *data; 825 struct fuse_vnode_data *fvdat = VTOFUD(vp); 826 struct fuse_filehandle *fufh = NULL; 827 mount_t mp = vnode_mount(vp); 828 829 data = fuse_get_mpdata(mp); 830 831 biosize = data->blocksize; 832 833 if (!(vtype == VREG || vtype == VDIR)) { 834 return ENOTSUP; 835 } 836 837 if (bflags & B_READ) { 838 mode = FREAD; 839 fufh_type = FUFH_RDONLY; /* FUFH_RDWR will also do */ 840 } else { 841 mode = FWRITE; 842 fufh_type = FUFH_WRONLY; /* FUFH_RDWR will also do */ 843 } 844 845 if (fvdat->flag & FN_CREATING) { 846 fuse_lck_mtx_lock(fvdat->createlock); 847 if (fvdat->flag & FN_CREATING) { 848 (void)fuse_msleep(fvdat->creator, fvdat->createlock, 849 PDROP | PINOD | PCATCH, "fuse_internal_strategy", 850 NULL); 851 } else { 852 fuse_lck_mtx_unlock(fvdat->createlock); 853 } 854 } 855 856 fufh = &(fvdat->fufh[fufh_type]); 857 858 if (!FUFH_IS_VALID(fufh)) { 859 fufh_type = FUFH_RDWR; 860 fufh = &(fvdat->fufh[fufh_type]); 861 if (!FUFH_IS_VALID(fufh)) { 862 fufh = NULL; 863 } else { 864 /* We've successfully fallen back to FUFH_RDWR. */ 865 } 866 } 867 868 if (!fufh) { 869 870 if (mode == FREAD) { 871 fufh_type = FUFH_RDONLY; 872 } else { 873 fufh_type = FUFH_RDWR; 874 } 875 876 /* 877 * Lets NOT do the filehandle preflight check here. 878 */ 879 880 err = fuse_filehandle_get(vp, NULL, fufh_type, 0 /* mode */); 881 882 if (!err) { 883 fufh = &(fvdat->fufh[fufh_type]); 884 FUFH_AUX_INC(fufh); 885 /* We've created a NEW fufh of type fufh_type. open_count is 1. */ 886 } 887 888 } else { /* good fufh */ 889 890 FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_reuse_count); 891 892 /* We're using an existing fufh of type fufh_type. */ 893 } 894 895 if (err) { 896 897 /* A more typical error case. */ 898 if ((err == ENOTCONN) || fuse_isdeadfs(vp)) { 899 buf_seterror(bp, EIO); 900 buf_biodone(bp); 901 return EIO; 902 } 903 904 IOLog("MacFUSE: strategy failed to get fh " 905 "(vtype=%d, fufh_type=%d, err=%d)\n", vtype, fufh_type, err); 906 907 if (!vfs_issynchronous(mp)) { 908 IOLog("MacFUSE: asynchronous write failed!\n"); 909 } 910 911 buf_seterror(bp, EIO); 912 buf_biodone(bp); 913 return EIO; 914 } 915 916 if (!fufh) { 917 panic("MacFUSE: tried everything but still no fufh"); 918 /* NOTREACHED */ 919 } 920 921#define B_INVAL 0x00040000 /* Does not contain valid info. */ 922#define B_ERROR 0x00080000 /* I/O error occurred. */ 923 924 if (bflags & B_INVAL) { 925 IOLog("MacFUSE: buffer does not contain valid information\n"); 926 } 927 928 if (bflags & B_ERROR) { 929 IOLog("MacFUSE: an I/O error has occured\n"); 930 } 931 932 if (buf_count(bp) == 0) { 933 return 0; 934 } 935 936 fdisp_init(&fdi, 0); 937 938 if (mode == FREAD) { 939 940 struct fuse_read_in *fri; 941 942 buf_setresid(bp, buf_count(bp)); 943 offset = (off_t)((off_t)buf_blkno(bp) * biosize); 944 945 if (offset >= fvdat->filesize) { 946 /* Trying to read at/after EOF? */ 947 if (offset != fvdat->filesize) { 948 /* Trying to read after EOF? */ 949 buf_seterror(bp, EINVAL); 950 } 951 buf_biodone(bp); 952 return 0; 953 } 954 955 /* Note that we just made sure that offset < fvdat->filesize. */ 956 if ((offset + buf_count(bp)) > fvdat->filesize) { 957 /* Trimming read */ 958 buf_setcount(bp, (uint32_t)(fvdat->filesize - offset)); 959 } 960 961 if (buf_map(bp, &bufdat)) { 962 IOLog("MacFUSE: failed to map buffer in strategy\n"); 963 return EFAULT; 964 } else { 965 mapped = TRUE; 966 } 967 968 while (buf_resid(bp) > 0) { 969 970 chunksize = min((size_t)buf_resid(bp), data->iosize); 971 972 fdi.iosize = sizeof(*fri); 973 974 op = FUSE_READ; 975 if (vtype == VDIR) { 976 op = FUSE_READDIR; 977 } 978 fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0); 979 980 fri = fdi.indata; 981 fri->fh = fufh->fh_id; 982 983 /* 984 * Historical note: 985 * 986 * fri->offset = ((off_t)(buf_blkno(bp))) * biosize; 987 * 988 * This wasn't being incremented!? 989 */ 990 991 fri->offset = offset; 992 fri->size = (typeof(fri->size))chunksize; 993 fdi.tick->tk_aw_type = FT_A_BUF; 994 fdi.tick->tk_aw_bufdata = bufdat; 995 996 if ((err = fdisp_wait_answ(&fdi))) { 997 /* There was a problem with reading. */ 998 goto out; 999 } 1000 1001 respsize = fdi.tick->tk_aw_bufsize; 1002 1003 if (respsize < 0) { /* Cannot really happen... */ 1004 err = EIO; 1005 goto out; 1006 } 1007 1008 buf_setresid(bp, (uint32_t)(buf_resid(bp) - respsize)); 1009 bufdat += respsize; 1010 offset += respsize; 1011 1012 /* Did we hit EOF before being done? */ 1013 if ((respsize == 0) && (buf_resid(bp) > 0)) { 1014 /* 1015 * Historical note: 1016 * If we don't get enough data, just fill the rest with zeros. 1017 * In NFS context, this would mean a hole in the file. 1018 */ 1019 1020 /* Zero-pad the incomplete buffer. */ 1021 bzero(bufdat, buf_resid(bp)); 1022 buf_setresid(bp, 0); 1023 break; 1024 } 1025 } /* while (buf_resid(bp) > 0) */ 1026 } else { 1027 /* write */ 1028 struct fuse_write_in *fwi; 1029 struct fuse_write_out *fwo; 1030 int merr = 0; 1031 off_t diff; 1032 1033 if (buf_map(bp, &bufdat)) { 1034 IOLog("MacFUSE: failed to map buffer in strategy\n"); 1035 return EFAULT; 1036 } else { 1037 mapped = TRUE; 1038 } 1039 1040 /* Write begin */ 1041 1042 buf_setresid(bp, buf_count(bp)); 1043 offset = (off_t)((off_t)buf_blkno(bp) * biosize); 1044 1045 /* XXX: TBD -- Check here for extension (writing past end) */ 1046 1047 left = buf_count(bp); 1048 1049 while (left) { 1050 1051 fdi.iosize = sizeof(*fwi); 1052 op = FUSE_WRITE; 1053 1054 fdisp_make_vp(&fdi, op, vp, (vfs_context_t)0); 1055 chunksize = min((size_t)left, data->iosize); 1056 1057 fwi = fdi.indata; 1058 fwi->fh = fufh->fh_id; 1059 fwi->offset = offset; 1060 fwi->size = (typeof(fwi->size))chunksize; 1061 1062 fdi.tick->tk_ms_type = FT_M_BUF; 1063 fdi.tick->tk_ms_bufdata = bufdat; 1064 fdi.tick->tk_ms_bufsize = chunksize; 1065 1066 /* About to write <chunksize> at <offset> */ 1067 1068 if ((err = fdisp_wait_answ(&fdi))) { 1069 merr = 1; 1070 break; 1071 } 1072 1073 fwo = fdi.answ; 1074 diff = chunksize - fwo->size; 1075 if (diff < 0) { 1076 err = EINVAL; 1077 break; 1078 } 1079 1080 left -= fwo->size; 1081 bufdat += fwo->size; 1082 offset += fwo->size; 1083 buf_setresid(bp, buf_resid(bp) - fwo->size); 1084 } 1085 1086 if (merr) { 1087 goto out; 1088 } 1089 } 1090 1091 if (fdi.tick) { 1092 fuse_ticket_drop(fdi.tick); 1093 } else { 1094 /* No ticket upon leaving */ 1095 } 1096 1097out: 1098 1099 if (err) { 1100 buf_seterror(bp, err); 1101 } 1102 1103 if (mapped == TRUE) { 1104 buf_unmap(bp); 1105 } 1106 1107 buf_biodone(bp); 1108 1109 return err; 1110} 1111 1112__private_extern__ 1113errno_t 1114fuse_internal_strategy_buf(struct vnop_strategy_args *ap) 1115{ 1116 int32_t bflags; 1117 upl_t bupl; 1118 daddr64_t blkno, lblkno; 1119 int bmap_flags; 1120 buf_t bp = ap->a_bp; 1121 vnode_t vp = buf_vnode(bp); 1122 int vtype = vnode_vtype(vp); 1123 1124 struct fuse_data *data; 1125 1126 if (!vp || vtype == VCHR || vtype == VBLK) { 1127 panic("MacFUSE: buf_strategy: b_vp == NULL || vtype == VCHR | VBLK\n"); 1128 } 1129 1130 bflags = buf_flags(bp); 1131 1132 if (bflags & B_READ) { 1133 bmap_flags = VNODE_READ; 1134 } else { 1135 bmap_flags = VNODE_WRITE; 1136 } 1137 1138 bupl = buf_upl(bp); 1139 blkno = buf_blkno(bp); 1140 lblkno = buf_lblkno(bp); 1141 1142 if (!(bflags & B_CLUSTER)) { 1143 1144 if (bupl) { 1145 return cluster_bp(bp); 1146 } 1147 1148 if (blkno == lblkno) { 1149 off_t f_offset; 1150 size_t contig_bytes; 1151 1152 data = fuse_get_mpdata(vnode_mount(vp)); 1153 1154 // Still think this is a kludge? 1155 f_offset = lblkno * data->blocksize; 1156 blkno = f_offset / data->blocksize; 1157 1158 buf_setblkno(bp, blkno); 1159 1160 contig_bytes = buf_count(bp); 1161 1162 if (blkno == -1) { 1163 buf_clear(bp); 1164 } 1165 1166 /* 1167 * Our "device" is always /all contiguous/. We don't wanna be 1168 * doing things like: 1169 * 1170 * ... 1171 * else if ((long)contig_bytes < buf_count(bp)) { 1172 * ret = buf_strategy_fragmented(devvp, bp, f_offset, 1173 * contig_bytes)); 1174 * return ret; 1175 * } 1176 */ 1177 } 1178 1179 if (blkno == -1) { 1180 buf_biodone(bp); 1181 return 0; 1182 } 1183 } 1184 1185 // Issue the I/O 1186 1187 return fuse_internal_strategy(vp, bp); 1188} 1189 1190/* entity creation */ 1191 1192__private_extern__ 1193void 1194fuse_internal_newentry_makerequest(mount_t mp, 1195 uint64_t dnid, 1196 struct componentname *cnp, 1197 enum fuse_opcode op, 1198 void *buf, 1199 size_t bufsize, 1200 struct fuse_dispatcher *fdip, 1201 vfs_context_t context) 1202{ 1203 fdisp_init(fdip, bufsize + cnp->cn_namelen + 1); 1204 1205 fdisp_make(fdip, op, mp, dnid, context); 1206 memcpy(fdip->indata, buf, bufsize); 1207 memcpy((char *)fdip->indata + bufsize, cnp->cn_nameptr, cnp->cn_namelen); 1208 ((char *)fdip->indata)[bufsize + cnp->cn_namelen] = '\0'; 1209} 1210 1211__private_extern__ 1212int 1213fuse_internal_newentry_core(vnode_t dvp, 1214 vnode_t *vpp, 1215 struct componentname *cnp, 1216 enum vtype vtyp, 1217 struct fuse_dispatcher *fdip, 1218 vfs_context_t context) 1219{ 1220 int err = 0; 1221 struct fuse_entry_out *feo; 1222 mount_t mp = vnode_mount(dvp); 1223 1224 if ((err = fdisp_wait_answ(fdip))) { 1225 return err; 1226 } 1227 1228 feo = fdip->answ; 1229 1230 if ((err = fuse_internal_checkentry(feo, vtyp))) { 1231 goto out; 1232 } 1233 1234 err = fuse_vget_i(vpp, 0 /* flags */, feo, cnp, dvp, mp, context); 1235 if (err) { 1236 fuse_internal_forget_send(mp, context, feo->nodeid, 1, fdip); 1237 return err; 1238 } 1239 1240 cache_attrs(*vpp, feo); 1241 1242out: 1243 fuse_ticket_drop(fdip->tick); 1244 1245 return err; 1246} 1247 1248__private_extern__ 1249int 1250fuse_internal_newentry(vnode_t dvp, 1251 vnode_t *vpp, 1252 struct componentname *cnp, 1253 enum fuse_opcode op, 1254 void *buf, 1255 size_t bufsize, 1256 enum vtype vtype, 1257 vfs_context_t context) 1258{ 1259 int err; 1260 struct fuse_dispatcher fdi; 1261 mount_t mp = vnode_mount(dvp); 1262 1263 if (fuse_skip_apple_double_mp(mp, cnp->cn_nameptr, cnp->cn_namelen)) { 1264 return EACCES; 1265 } 1266 1267 fdisp_init(&fdi, 0); 1268 fuse_internal_newentry_makerequest(mp, VTOI(dvp), cnp, op, buf, 1269 bufsize, &fdi, context); 1270 err = fuse_internal_newentry_core(dvp, vpp, cnp, vtype, &fdi, context); 1271 fuse_invalidate_attr(dvp); 1272 1273 return err; 1274} 1275 1276/* entity destruction */ 1277 1278__private_extern__ 1279int 1280fuse_internal_forget_callback(struct fuse_ticket *ftick, __unused uio_t uio) 1281{ 1282 struct fuse_dispatcher fdi; 1283 1284 fdi.tick = ftick; 1285 1286 fuse_internal_forget_send(ftick->tk_data->mp, (vfs_context_t)0, 1287 ((struct fuse_in_header *)ftick->tk_ms_fiov.base)->nodeid, 1, &fdi); 1288 1289 return 0; 1290} 1291 1292__private_extern__ 1293void 1294fuse_internal_forget_send(mount_t mp, 1295 vfs_context_t context, 1296 uint64_t nodeid, 1297 uint64_t nlookup, 1298 struct fuse_dispatcher *fdip) 1299{ 1300 struct fuse_forget_in *ffi; 1301 1302 /* 1303 * KASSERT(nlookup > 0, ("zero-times forget for vp #%llu", 1304 * (long long unsigned) nodeid)); 1305 */ 1306 1307 fdisp_init(fdip, sizeof(*ffi)); 1308 fdisp_make(fdip, FUSE_FORGET, mp, nodeid, context); 1309 1310 ffi = fdip->indata; 1311 ffi->nlookup = nlookup; 1312 1313 fticket_invalidate(fdip->tick); 1314 fuse_insert_message(fdip->tick); 1315} 1316 1317__private_extern__ 1318void 1319fuse_internal_interrupt_send(struct fuse_ticket *ftick) 1320{ 1321 struct fuse_dispatcher fdi; 1322 struct fuse_interrupt_in *fii; 1323 1324 fdi.tick = ftick; 1325 fdisp_init(&fdi, sizeof(*fii)); 1326 fdisp_make(&fdi, FUSE_INTERRUPT, ftick->tk_data->mp, (uint64_t)0, 1327 (vfs_context_t)0); 1328 fii = fdi.indata; 1329 fii->unique = ftick->tk_unique; 1330 fticket_invalidate(fdi.tick); 1331 fuse_insert_message(fdi.tick); 1332} 1333 1334__private_extern__ 1335void 1336fuse_internal_vnode_disappear(vnode_t vp, vfs_context_t context, int how) 1337{ 1338 int err = 0; 1339 1340 fuse_vncache_purge(vp); 1341 1342 if (how != REVOKE_NONE) { 1343 err = fuse_internal_revoke(vp, REVOKEALL, context, how); 1344 if (err) { 1345 IOLog("MacFUSE: disappearing act: revoke failed (%d)\n", err); 1346 } 1347 1348 err = vnode_recycle(vp); 1349 if (err) { 1350 IOLog("MacFUSE: disappearing act: recycle failed (%d)\n", err); 1351 } 1352 } 1353} 1354 1355/* fuse start/stop */ 1356 1357__private_extern__ 1358int 1359fuse_internal_init_synchronous(struct fuse_ticket *ftick) 1360{ 1361 int err = 0; 1362 struct fuse_init_out *fiio; 1363 struct fuse_data *data = ftick->tk_data; 1364 1365 if ((err = ftick->tk_aw_ohead.error)) { 1366 goto out; 1367 } 1368 1369 fiio = fticket_resp(ftick)->base; 1370 1371 if ((fiio->major < MACFUSE_MIN_USER_VERSION_MAJOR) || 1372 (fiio->minor < MACFUSE_MIN_USER_VERSION_MINOR)){ 1373 IOLog("MacFUSE: user-space library has too low a version\n"); 1374 err = EPROTONOSUPPORT; 1375 goto out; 1376 } 1377 1378 data->fuse_libabi_major = fiio->major; 1379 data->fuse_libabi_minor = fiio->minor; 1380 1381 if (fuse_libabi_geq(data, MACFUSE_MIN_USER_VERSION_MAJOR, 1382 MACFUSE_MIN_USER_VERSION_MINOR)) { 1383 if (fticket_resp(ftick)->len == sizeof(struct fuse_init_out)) { 1384 data->max_write = fiio->max_write; 1385 } else { 1386 err = EINVAL; 1387 } 1388 } else { 1389 /* Old fix values */ 1390 data->max_write = 4096; 1391 } 1392 1393 if (fiio->flags & FUSE_CASE_INSENSITIVE) { 1394 data->dataflags |= FSESS_CASE_INSENSITIVE; 1395 } 1396 1397 if (fiio->flags & FUSE_VOL_RENAME) { 1398 data->dataflags |= FSESS_VOL_RENAME; 1399 } 1400 1401 if (fiio->flags & FUSE_XTIMES) { 1402 data->dataflags |= FSESS_XTIMES; 1403 } 1404 1405out: 1406 fuse_ticket_drop(ftick); 1407 1408 if (err) { 1409 fdata_set_dead(data); 1410 } 1411 1412 fuse_lck_mtx_lock(data->ticket_mtx); 1413 data->dataflags |= FSESS_INITED; 1414 fuse_wakeup(&data->ticketer); 1415 fuse_lck_mtx_unlock(data->ticket_mtx); 1416 1417 return 0; 1418} 1419 1420__private_extern__ 1421int 1422fuse_internal_send_init(struct fuse_data *data, vfs_context_t context) 1423{ 1424 int err = 0; 1425 struct fuse_init_in *fiii; 1426 struct fuse_dispatcher fdi; 1427 1428 fdisp_init(&fdi, sizeof(*fiii)); 1429 fdisp_make(&fdi, FUSE_INIT, data->mp, 0, context); 1430 fiii = fdi.indata; 1431 fiii->major = FUSE_KERNEL_VERSION; 1432 fiii->minor = FUSE_KERNEL_MINOR_VERSION; 1433 fiii->max_readahead = data->iosize * 16; 1434 fiii->flags = 0; 1435 1436 /* blocking FUSE_INIT up to user space */ 1437 1438 err = fdisp_wait_answ(&fdi); 1439 if (err) { 1440 IOLog("MacFUSE: user-space initialization failed (%d)\n", err); 1441 return err; 1442 } 1443 1444 err = fuse_internal_init_synchronous(fdi.tick); 1445 if (err) { 1446 IOLog("MacFUSE: in-kernel initialization failed (%d)\n", err); 1447 return err; 1448 } 1449 1450 return 0; 1451} 1452 1453/* other */ 1454 1455static int 1456fuse_internal_print_vnodes_callback(vnode_t vp, __unused void *cargs) 1457{ 1458 const char *vname = NULL; 1459 struct fuse_vnode_data *fvdat = VTOFUD(vp); 1460 1461#if M_MACFUSE_ENABLE_UNSUPPORTED 1462 vname = vnode_getname(vp); 1463#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ 1464 1465 if (vname) { 1466 IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d %s\n", 1467 vp, fvdat->nodeid, fvdat->parent_nodeid, 1468 vnode_isinuse(vp, 0), vname); 1469 } else { 1470 if (fvdat->nodeid == FUSE_ROOT_ID) { 1471 IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d /\n", 1472 vp, fvdat->nodeid, fvdat->parent_nodeid, 1473 vnode_isinuse(vp, 0)); 1474 } else { 1475 IOLog("MacFUSE: vp=%p ino=%lld parent=%lld inuse=%d\n", 1476 vp, fvdat->nodeid, fvdat->parent_nodeid, 1477 vnode_isinuse(vp, 0)); 1478 } 1479 } 1480 1481#if M_MACFUSE_ENABLE_UNSUPPORTED 1482 if (vname) { 1483 vnode_putname(vname); 1484 } 1485#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ 1486 1487 return VNODE_RETURNED; 1488} 1489 1490__private_extern__ 1491void 1492fuse_internal_print_vnodes(mount_t mp) 1493{ 1494 vnode_iterate(mp, VNODE_ITERATE_ALL, 1495 fuse_internal_print_vnodes_callback, NULL); 1496} 1497 1498__private_extern__ 1499void 1500fuse_preflight_log(vnode_t vp, fufh_type_t fufh_type, int err, char *message) 1501{ 1502 const char *vname = NULL; 1503 1504#if M_MACFUSE_ENABLE_UNSUPPORTED 1505 vname = vnode_getname(vp); 1506#else 1507 (void)vname; 1508 (void)vp; 1509#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ 1510 1511 if (vname) { 1512 IOLog("MacFUSE: file handle preflight " 1513 "(caller=%s, type=%d, err=%d, name=%s)\n", 1514 message, fufh_type, err, vname); 1515 } else { 1516 IOLog("MacFUSE: file handle preflight " 1517 "(caller=%s, type=%d, err=%d)\n", message, fufh_type, err); 1518 } 1519 1520#if M_MACFUSE_ENABLE_UNSUPPORTED 1521 if (vname) { 1522 vnode_putname(vname); 1523 } 1524#endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ 1525}