/* struct vnop_remove_args { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; }; */ static int fuse_vnop_remove(struct vop_remove_args *ap) { struct vnode *dvp = ap->a_dvp; struct vnode *vp = ap->a_vp; struct componentname *cnp = ap->a_cnp; int err; FS_DEBUG2G("inode=%ju name=%*s\n", (uintmax_t)VTOI(vp), (int)cnp->cn_namelen, cnp->cn_nameptr); if (fuse_isdeadfs(vp)) { return ENXIO; } if (vnode_isdir(vp)) { return EPERM; } cache_purge(vp); err = fuse_internal_remove(dvp, vp, cnp, FUSE_UNLINK); if (err == 0) fuse_internal_vnode_disappear(vp); return err; }
int fuse_filehandle_open(struct vnode *vp, fufh_type_t fufh_type, struct fuse_filehandle **fufhp, struct thread *td, struct ucred *cred) { struct fuse_dispatcher fdi; struct fuse_open_in *foi; struct fuse_open_out *foo; int err = 0; int isdir = 0; int oflags = 0; int op = FUSE_OPEN; fuse_trace_printf("fuse_filehandle_open(vp=%p, fufh_type=%d)\n", vp, fufh_type); if (fuse_filehandle_valid(vp, fufh_type)) { panic("FUSE: filehandle_open called despite valid fufh (type=%d)", fufh_type); /* NOTREACHED */ } /* * Note that this means we are effectively FILTERING OUT open() flags. */ oflags = fuse_filehandle_xlate_to_oflags(fufh_type); if (vnode_isdir(vp)) { isdir = 1; op = FUSE_OPENDIR; if (fufh_type != FUFH_RDONLY) { printf("FUSE:non-rdonly fh requested for a directory?\n"); fufh_type = FUFH_RDONLY; } } fdisp_init(&fdi, sizeof(*foi)); fdisp_make_vp(&fdi, op, vp, td, cred); foi = fdi.indata; foi->flags = oflags; if ((err = fdisp_wait_answ(&fdi))) { debug_printf("OUCH ... daemon didn't give fh (err = %d)\n", err); if (err == ENOENT) { fuse_internal_vnode_disappear(vp); } goto out; } foo = fdi.answ; fuse_filehandle_init(vp, fufh_type, fufhp, foo->fh); fuse_vnode_open(vp, foo->open_flags, td); out: fdisp_destroy(&fdi); return err; }
/* struct vnop_rmdir_args { struct vnode *a_dvp; struct vnode *a_vp; struct componentname *a_cnp; } *ap; */ static int fuse_vnop_rmdir(struct vop_rmdir_args *ap) { struct vnode *dvp = ap->a_dvp; struct vnode *vp = ap->a_vp; int err; FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); if (fuse_isdeadfs(vp)) { return ENXIO; } if (VTOFUD(vp) == VTOFUD(dvp)) { return EINVAL; } err = fuse_internal_remove(dvp, vp, ap->a_cnp, FUSE_RMDIR); if (err == 0) fuse_internal_vnode_disappear(vp); return err; }
errno_t FSNodeGetOrCreateFileVNodeByID(vnode_t *vnPtr, uint32_t flags, struct fuse_abi_data *feo, mount_t mp, vnode_t dvp, vfs_context_t context, uint32_t *oflags) { int err; vnode_t vn = NULLVP; HNodeRef hn = NULL; struct fuse_vnode_data *fvdat = NULL; struct fuse_data *mntdata = NULL; fuse_device_t dummy_device; struct fuse_abi_data fa; enum vtype vtyp; fuse_abi_data_init(&fa, feo->fad_version, fuse_entry_out_get_attr(feo)); vtyp = IFTOVT(fuse_attr_get_mode(&fa)); if ((vtyp >= VBAD) || (vtyp == VNON)) { return EINVAL; } int markroot = (flags & FN_IS_ROOT) ? 1 : 0; uint64_t size = (flags & FN_IS_ROOT) ? 0 : fuse_attr_get_size(&fa); uint32_t rdev = (flags & FN_IS_ROOT) ? 0 : fuse_attr_get_rdev(&fa); uint64_t generation = fuse_entry_out_get_generation(feo); mntdata = fuse_get_mpdata(mp); dummy_device = mntdata->fdev; err = HNodeLookupCreatingIfNecessary(dummy_device, fuse_entry_out_get_nodeid(feo), 0 /* fork index */, &hn, &vn); if ((err == 0) && (vn == NULL)) { struct vnode_fsparam params; fvdat = (struct fuse_vnode_data *)FSNodeGenericFromHNode(hn); if (!fvdat->fInitialised) { fvdat->fInitialised = true; /* self */ fvdat->vp = NULLVP; /* hold on */ fvdat->nodeid = fuse_entry_out_get_nodeid(feo); fvdat->generation = generation; /* parent */ fvdat->parentvp = dvp; if (dvp) { fvdat->parent_nodeid = VTOI(dvp); } else { fvdat->parent_nodeid = 0; } /* I/O */ { int k; for (k = 0; k < FUFH_MAXTYPE; k++) { FUFH_USE_RESET(&(fvdat->fufh[k])); } } /* flags */ fvdat->flag = flags; fvdat->c_flag = 0; /* meta */ /* XXX: truncation */ fvdat->entry_valid.tv_sec = (time_t)fuse_entry_out_get_entry_valid(feo); fvdat->entry_valid.tv_nsec = fuse_entry_out_get_entry_valid_nsec(feo); /* XXX: truncation */ fvdat->attr_valid.tv_sec = 0; fvdat->attr_valid.tv_nsec = 0; /* XXX: truncation */ fvdat->modify_time.tv_sec = (time_t)fuse_attr_get_mtime(&fa); fvdat->modify_time.tv_nsec = fuse_attr_get_mtimensec(&fa); fvdat->filesize = size; fvdat->nlookup = 0; fvdat->vtype = vtyp; /* locking */ fvdat->createlock = lck_mtx_alloc_init(fuse_lock_group, fuse_lock_attr); fvdat->creator = current_thread(); #if M_OSXFUSE_ENABLE_TSLOCKING fvdat->nodelock = lck_rw_alloc_init(fuse_lock_group, fuse_lock_attr); fvdat->nodelockowner = NULL; fvdat->truncatelock = lck_rw_alloc_init(fuse_lock_group, fuse_lock_attr); #endif } if (err == 0) { params.vnfs_mp = mp; params.vnfs_vtype = vtyp; params.vnfs_str = NULL; params.vnfs_dvp = dvp; /* NULLVP for the root vnode */ params.vnfs_fsnode = hn; #if M_OSXFUSE_ENABLE_SPECFS if ((vtyp == VBLK) || (vtyp == VCHR)) { params.vnfs_vops = fuse_spec_operations; params.vnfs_rdev = (dev_t)rdev; #else if (0) { #endif #if M_OSXFUSE_ENABLE_FIFOFS } else if (vtyp == VFIFO) { params.vnfs_vops = fuse_fifo_operations; params.vnfs_rdev = 0; (void)rdev; #else } else if (0) { #endif } else { params.vnfs_vops = fuse_vnode_operations; params.vnfs_rdev = 0; (void)rdev; } params.vnfs_marksystem = 0; params.vnfs_cnp = NULL; params.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE; params.vnfs_filesize = size; params.vnfs_markroot = markroot; #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_unlock(mntdata->biglock); #endif err = vnode_create(VNCREATE_FLAVOR, (uint32_t)sizeof(params), ¶ms, &vn); #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_lock(mntdata->biglock); #endif } if (err == 0) { if (markroot) { fvdat->parentvp = vn; } else { fvdat->parentvp = dvp; } if (oflags) { *oflags |= MAKEENTRY; } /* Need VT_OSXFUSE from xnu */ vnode_settag(vn, VT_OTHER); cache_attrs(vn, fuse_entry_out, feo); HNodeAttachVNodeSucceeded(hn, 0 /* forkIndex */, vn); FUSE_OSAddAtomic(1, (SInt32 *)&fuse_vnodes_current); } else { if (HNodeAttachVNodeFailed(hn, 0 /* forkIndex */)) { FSNodeScrub(fvdat); HNodeScrubDone(hn); } } } if (err == 0) { if (vnode_vtype(vn) != vtyp) { IOLog("osxfuse: vnode changed type behind us (old=%d, new=%d)\n", vnode_vtype(vn), vtyp); #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_unlock(mntdata->biglock); #endif fuse_internal_vnode_disappear(vn, context, REVOKE_SOFT); vnode_put(vn); #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_lock(mntdata->biglock); #endif err = EIO; } else if (VTOFUD(vn)->generation != generation) { IOLog("osxfuse: vnode changed generation\n"); #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_unlock(mntdata->biglock); #endif fuse_internal_vnode_disappear(vn, context, REVOKE_SOFT); vnode_put(vn); #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_lock(mntdata->biglock); #endif err = ESTALE; } } if (err == 0) { *vnPtr = vn; } /* assert((err == 0) == (*vnPtr != NULL); */ return err; } int fuse_vget_i(vnode_t *vpp, uint32_t flags, struct fuse_abi_data *feo, struct componentname *cnp, vnode_t dvp, mount_t mp, vfs_context_t context) { int err = 0; if (!feo) { return EINVAL; } err = FSNodeGetOrCreateFileVNodeByID(vpp, flags, feo, mp, dvp, context, NULL); if (err) { return err; } if (!fuse_isnovncache_mp(mp) && (cnp->cn_flags & MAKEENTRY)) { fuse_vncache_enter(dvp, *vpp, cnp); } /* found: */ VTOFUD(*vpp)->nlookup++; return 0; }
/* * Because of the vagaries of how a filehandle can be used, we try not to * be too smart in here (we try to be smart elsewhere). It is required that * you come in here only if you really do not have the said filehandle--else * we panic. */ int fuse_filehandle_get(vnode_t vp, vfs_context_t context, fufh_type_t fufh_type, int mode) { struct fuse_dispatcher fdi; struct fuse_abi_data foi; struct fuse_abi_data foo; struct fuse_filehandle *fufh; struct fuse_vnode_data *fvdat = VTOFUD(vp); struct fuse_data *data = fuse_get_mpdata(vnode_mount(vp)); int err = 0; int oflags = 0; int op = FUSE_OPEN; fuse_trace_printf("fuse_filehandle_get(vp=%p, fufh_type=%d, mode=%x)\n", vp, fufh_type, mode); fufh = &(fvdat->fufh[fufh_type]); if (FUFH_IS_VALID(fufh)) { panic("osxfuse: filehandle_get called despite valid fufh (type=%d)", fufh_type); /* NOTREACHED */ } /* * Note that this means we are effectively FILTERING OUT open() flags. */ (void)mode; oflags = fuse_filehandle_xlate_to_oflags(fufh_type); if (vnode_isdir(vp)) { op = FUSE_OPENDIR; if (fufh_type != FUFH_RDONLY) { IOLog("osxfuse: non-rdonly fufh requested for directory\n"); fufh_type = FUFH_RDONLY; } } if (vnode_islnk(vp) && (mode & O_SYMLINK)) { oflags |= O_SYMLINK; } if ((mode & O_TRUNC) && (data->dataflags & FSESS_ATOMIC_O_TRUNC)) { oflags |= O_TRUNC; } fdisp_init_abi(&fdi, fuse_open_in, data); fdisp_make_vp(&fdi, op, vp, context); fuse_abi_data_init(&foi, DATOI(data), fdi.indata); fuse_open_in_set_flags(&foi, oflags); FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_upcall_count); err = fdisp_wait_answ(&fdi); if (err) { #if M_OSXFUSE_ENABLE_UNSUPPORTED const char *vname = vnode_getname(vp); #endif /* M_OSXFUSE_ENABLE_UNSUPPORTED */ if (err == ENOENT) { /* * See comment in fuse_vnop_reclaim(). */ cache_purge(vp); } #if M_OSXFUSE_ENABLE_UNSUPPORTED IOLog("osxfuse: filehandle_get: failed for %s " "(type=%d, err=%d, caller=%p)\n", (vname) ? vname : "?", fufh_type, err, __builtin_return_address(0)); if (vname) { vnode_putname(vname); } #endif /* M_OSXFUSE_ENABLE_UNSUPPORTED */ if (err == ENOENT) { #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_unlock(data->biglock); #endif fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT); #if M_OSXFUSE_ENABLE_BIG_LOCK fuse_biglock_lock(data->biglock); #endif } return err; } FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_current); fuse_abi_data_init(&foo, DATOI(data), fdi.answ); fufh->fh_id = fuse_open_out_get_fh(&foo); fufh->open_count = 1; fufh->open_flags = oflags; fufh->fuse_open_flags = fuse_open_out_get_open_flags(&foo); fufh->aux_count = 0; fuse_ticket_release(fdi.tick); return 0; }
/* struct vnop_getattr_args { struct vnode *a_vp; struct vattr *a_vap; struct ucred *a_cred; struct thread *a_td; }; */ static int fuse_vnop_getattr(struct vop_getattr_args *ap) { struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; struct ucred *cred = ap->a_cred; struct thread *td = curthread; struct fuse_vnode_data *fvdat = VTOFUD(vp); int err = 0; int dataflags; struct fuse_dispatcher fdi; FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); dataflags = fuse_get_mpdata(vnode_mount(vp))->dataflags; /* Note that we are not bailing out on a dead file system just yet. */ if (!(dataflags & FSESS_INITED)) { if (!vnode_isvroot(vp)) { fdata_set_dead(fuse_get_mpdata(vnode_mount(vp))); err = ENOTCONN; debug_printf("fuse_getattr b: returning ENOTCONN\n"); return err; } else { goto fake; } } fdisp_init(&fdi, 0); if ((err = fdisp_simple_putget_vp(&fdi, FUSE_GETATTR, vp, td, cred))) { if ((err == ENOTCONN) && vnode_isvroot(vp)) { /* see comment at similar place in fuse_statfs() */ fdisp_destroy(&fdi); goto fake; } if (err == ENOENT) { fuse_internal_vnode_disappear(vp); } goto out; } cache_attrs(vp, (struct fuse_attr_out *)fdi.answ); if (vap != VTOVA(vp)) { memcpy(vap, VTOVA(vp), sizeof(*vap)); } if (vap->va_type != vnode_vtype(vp)) { fuse_internal_vnode_disappear(vp); err = ENOENT; goto out; } if ((fvdat->flag & FN_SIZECHANGE) != 0) vap->va_size = fvdat->filesize; if (vnode_isreg(vp) && (fvdat->flag & FN_SIZECHANGE) == 0) { /* * This is for those cases when the file size changed without us * knowing, and we want to catch up. */ off_t new_filesize = ((struct fuse_attr_out *) fdi.answ)->attr.size; if (fvdat->filesize != new_filesize) { fuse_vnode_setsize(vp, cred, new_filesize); } } debug_printf("fuse_getattr e: returning 0\n"); out: fdisp_destroy(&fdi); return err; fake: bzero(vap, sizeof(*vap)); vap->va_type = vnode_vtype(vp); return 0; }
/* struct vnop_setattr_args { struct vnode *a_vp; struct vattr *a_vap; struct ucred *a_cred; struct thread *a_td; }; */ static int fuse_vnop_setattr(struct vop_setattr_args *ap) { struct vnode *vp = ap->a_vp; struct vattr *vap = ap->a_vap; struct ucred *cred = ap->a_cred; struct thread *td = curthread; struct fuse_dispatcher fdi; struct fuse_setattr_in *fsai; struct fuse_access_param facp; int err = 0; enum vtype vtyp; int sizechanged = 0; uint64_t newsize = 0; FS_DEBUG2G("inode=%ju\n", (uintmax_t)VTOI(vp)); if (fuse_isdeadfs(vp)) { return ENXIO; } fdisp_init(&fdi, sizeof(*fsai)); fdisp_make_vp(&fdi, FUSE_SETATTR, vp, td, cred); fsai = fdi.indata; fsai->valid = 0; bzero(&facp, sizeof(facp)); facp.xuid = vap->va_uid; facp.xgid = vap->va_gid; if (vap->va_uid != (uid_t)VNOVAL) { facp.facc_flags |= FACCESS_CHOWN; fsai->uid = vap->va_uid; fsai->valid |= FATTR_UID; } if (vap->va_gid != (gid_t)VNOVAL) { facp.facc_flags |= FACCESS_CHOWN; fsai->gid = vap->va_gid; fsai->valid |= FATTR_GID; } if (vap->va_size != VNOVAL) { struct fuse_filehandle *fufh = NULL; /*Truncate to a new value. */ fsai->size = vap->va_size; sizechanged = 1; newsize = vap->va_size; fsai->valid |= FATTR_SIZE; fuse_filehandle_getrw(vp, FUFH_WRONLY, &fufh); if (fufh) { fsai->fh = fufh->fh_id; fsai->valid |= FATTR_FH; } } if (vap->va_atime.tv_sec != VNOVAL) { fsai->atime = vap->va_atime.tv_sec; fsai->atimensec = vap->va_atime.tv_nsec; fsai->valid |= FATTR_ATIME; } if (vap->va_mtime.tv_sec != VNOVAL) { fsai->mtime = vap->va_mtime.tv_sec; fsai->mtimensec = vap->va_mtime.tv_nsec; fsai->valid |= FATTR_MTIME; } if (vap->va_mode != (mode_t)VNOVAL) { fsai->mode = vap->va_mode & ALLPERMS; fsai->valid |= FATTR_MODE; } if (!fsai->valid) { goto out; } vtyp = vnode_vtype(vp); if (fsai->valid & FATTR_SIZE && vtyp == VDIR) { err = EISDIR; goto out; } if (vfs_isrdonly(vnode_mount(vp)) && (fsai->valid & ~FATTR_SIZE || vtyp == VREG)) { err = EROFS; goto out; } if (fsai->valid & ~FATTR_SIZE) { /*err = fuse_internal_access(vp, VADMIN, context, &facp); */ /*XXX */ err = 0; } facp.facc_flags &= ~FACCESS_XQUERIES; if (err && !(fsai->valid & ~(FATTR_ATIME | FATTR_MTIME)) && vap->va_vaflags & VA_UTIMES_NULL) { err = fuse_internal_access(vp, VWRITE, &facp, td, cred); } if (err) goto out; if ((err = fdisp_wait_answ(&fdi))) goto out; vtyp = IFTOVT(((struct fuse_attr_out *)fdi.answ)->attr.mode); if (vnode_vtype(vp) != vtyp) { if (vnode_vtype(vp) == VNON && vtyp != VNON) { debug_printf("FUSE: Dang! vnode_vtype is VNON and vtype isn't.\n"); } else { /* * STALE vnode, ditch * * The vnode has changed its type "behind our back". There's * nothing really we can do, so let us just force an internal * revocation and tell the caller to try again, if interested. */ fuse_internal_vnode_disappear(vp); err = EAGAIN; } } if (!err && !sizechanged) { cache_attrs(vp, (struct fuse_attr_out *)fdi.answ); } out: fdisp_destroy(&fdi); if (!err && sizechanged) { fuse_vnode_setsize(vp, cred, newsize); VTOFUD(vp)->flag &= ~FN_SIZECHANGE; } return err; }
__private_extern__ int fuse_internal_access(vnode_t vp, int action, vfs_context_t context, struct fuse_access_param *facp) { int err = 0; int default_error = 0; uint32_t mask = 0; int dataflags; mount_t mp; struct fuse_dispatcher fdi; struct fuse_access_in *fai; struct fuse_data *data; fuse_trace_printf_func(); mp = vnode_mount(vp); data = fuse_get_mpdata(mp); dataflags = data->dataflags; /* Allow for now; let checks be handled inline later. */ if (fuse_isdeferpermissions_mp(mp)) { return 0; } if (facp->facc_flags & FACCESS_FROM_VNOP) { default_error = ENOTSUP; } /* * (action & KAUTH_VNODE_GENERIC_WRITE_BITS) on a read-only file system * would have been handled by higher layers. */ if (!fuse_implemented(data, FSESS_NOIMPLBIT(ACCESS))) { return default_error; } /* Unless explicitly permitted, deny everyone except the fs owner. */ if (!vnode_isvroot(vp) && !(facp->facc_flags & FACCESS_NOCHECKSPY)) { if (!(dataflags & FSESS_ALLOW_OTHER)) { int denied = fuse_match_cred(data->daemoncred, vfs_context_ucred(context)); if (denied) { return EPERM; } } facp->facc_flags |= FACCESS_NOCHECKSPY; } if (!(facp->facc_flags & FACCESS_DO_ACCESS)) { return default_error; } if (vnode_isdir(vp)) { if (action & (KAUTH_VNODE_LIST_DIRECTORY | KAUTH_VNODE_READ_EXTATTRIBUTES)) { mask |= R_OK; } if (action & (KAUTH_VNODE_ADD_FILE | KAUTH_VNODE_ADD_SUBDIRECTORY | KAUTH_VNODE_DELETE_CHILD)) { mask |= W_OK; } if (action & KAUTH_VNODE_SEARCH) { mask |= X_OK; } } else { if (action & (KAUTH_VNODE_READ_DATA | KAUTH_VNODE_READ_EXTATTRIBUTES)) { mask |= R_OK; } if (action & (KAUTH_VNODE_WRITE_DATA | KAUTH_VNODE_APPEND_DATA)) { mask |= W_OK; } if (action & KAUTH_VNODE_EXECUTE) { mask |= X_OK; } } if (action & (KAUTH_VNODE_WRITE_ATTRIBUTES | KAUTH_VNODE_WRITE_EXTATTRIBUTES | KAUTH_VNODE_WRITE_SECURITY)) { mask |= W_OK; } bzero(&fdi, sizeof(fdi)); fdisp_init(&fdi, sizeof(*fai)); fdisp_make_vp(&fdi, FUSE_ACCESS, vp, context); fai = fdi.indata; fai->mask = F_OK; fai->mask |= mask; if (!(err = fdisp_wait_answ(&fdi))) { fuse_ticket_drop(fdi.tick); } if (err == ENOSYS) { /* * Make sure we don't come in here again. */ vfs_clearauthopaque(mp); fuse_clear_implemented(data, FSESS_NOIMPLBIT(ACCESS)); err = default_error; } if (err == ENOENT) { const char *vname = NULL; #if M_MACFUSE_ENABLE_UNSUPPORTED vname = vnode_getname(vp); #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ IOLog("MacFUSE: disappearing vnode %p (name=%s type=%d action=%x)\n", vp, (vname) ? vname : "?", vnode_vtype(vp), action); #if M_MACFUSE_ENABLE_UNSUPPORTED if (vname) { vnode_putname(vname); } #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ /* * On 10.4, I think I can get Finder to lock because of /.Trashes/<uid> * unless I use REVOKE_NONE here. */ #if M_MACFUSE_ENABLE_INTERIM_FSNODE_LOCK && !M_MACFUSE_ENABLE_HUGE_LOCK fuse_biglock_unlock(data->biglock); #endif fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT); #if M_MACFUSE_ENABLE_INTERIM_FSNODE_LOCK && !M_MACFUSE_ENABLE_HUGE_LOCK fuse_biglock_lock(data->biglock); #endif } return err; }
/* * Because of the vagaries of how a filehandle can be used, we try not to * be too smart in here (we try to be smart elsewhere). It is required that * you come in here only if you really do not have the said filehandle--else * we panic. */ int fuse_filehandle_get(vnode_t vp, vfs_context_t context, fufh_type_t fufh_type, int mode) { struct fuse_dispatcher fdi; struct fuse_open_in *foi; struct fuse_open_out *foo; struct fuse_filehandle *fufh; struct fuse_vnode_data *fvdat = VTOFUD(vp); int err = 0; int isdir = 0; int oflags = 0; int op = FUSE_OPEN; fuse_trace_printf("fuse_filehandle_get(vp=%p, fufh_type=%d, mode=%x)\n", vp, fufh_type, mode); fufh = &(fvdat->fufh[fufh_type]); if (FUFH_IS_VALID(fufh)) { panic("MacFUSE: filehandle_get called despite valid fufh (type=%d)", fufh_type); /* NOTREACHED */ } /* * Note that this means we are effectively FILTERING OUT open() flags. */ (void)mode; oflags = fuse_filehandle_xlate_to_oflags(fufh_type); if (vnode_isdir(vp)) { isdir = 1; op = FUSE_OPENDIR; if (fufh_type != FUFH_RDONLY) { IOLog("MacFUSE: non-rdonly fufh requested for directory\n"); fufh_type = FUFH_RDONLY; } } fdisp_init(&fdi, sizeof(*foi)); fdisp_make_vp(&fdi, op, vp, context); if (vnode_islnk(vp) && (mode & O_SYMLINK)) { oflags |= O_SYMLINK; } foi = fdi.indata; foi->flags = oflags; FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_upcall_count); if ((err = fdisp_wait_answ(&fdi))) { #if M_MACFUSE_ENABLE_UNSUPPORTED const char *vname = vnode_getname(vp); #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ if (err == ENOENT) { /* * See comment in fuse_vnop_reclaim(). */ cache_purge(vp); } #if M_MACFUSE_ENABLE_UNSUPPORTED IOLog("MacFUSE: filehandle_get: failed for %s " "(type=%d, err=%d, caller=%p)\n", (vname) ? vname : "?", fufh_type, err, __builtin_return_address(0)); if (vname) { vnode_putname(vname); } #endif /* M_MACFUSE_ENABLE_UNSUPPORTED */ if (err == ENOENT) { fuse_internal_vnode_disappear(vp, context, REVOKE_SOFT); } return err; } FUSE_OSAddAtomic(1, (SInt32 *)&fuse_fh_current); foo = fdi.answ; fufh->fh_id = foo->fh; fufh->open_count = 1; fufh->open_flags = oflags; fufh->fuse_open_flags = foo->open_flags; fufh->aux_count = 0; fuse_ticket_drop(fdi.tick); return 0; }