int fusefs_getattr(void *v) { struct vop_getattr_args *ap = v; struct vnode *vp = ap->a_vp; struct fusefs_mnt *fmp; struct vattr *vap = ap->a_vap; struct proc *p = curproc; struct fusefs_node *ip; struct fusebuf *fbuf; int error = 0; ip = VTOI(vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init) goto fake; fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_GETATTR, p); error = fb_queue(fmp->dev, fbuf); if (error) { fb_delete(fbuf); return (error); } update_vattr(fmp->mp, &fbuf->fb_vattr); memcpy(vap, &fbuf->fb_vattr, sizeof(*vap)); fb_delete(fbuf); return (error); fake: bzero(vap, sizeof(*vap)); vap->va_type = vp->v_type; return (0); }
int fusefs_getattr(void *v) { struct vop_getattr_args *ap = v; struct vnode *vp = ap->a_vp; struct fusefs_mnt *fmp; struct vattr *vap = ap->a_vap; struct proc *p = ap->a_p; struct fusefs_node *ip; struct fusebuf *fbuf; int error = 0; DPRINTF("fusefs_getattr\n"); ip = VTOI(vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init) goto fake; fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_GETATTR, p); error = fb_queue(fmp->dev, fbuf); if (error) { DPRINTF("getattr error\n"); pool_put(&fusefs_fbuf_pool, fbuf); return (error); } /* check if we got a response */ if (fbuf->fb_len == 0) { pool_put(&fusefs_fbuf_pool, fbuf); goto fake; } update_vattr(fmp->mp, &fbuf->fb_vattr); memcpy(vap, &fbuf->fb_vattr, sizeof(*vap)); memcpy(&ip->cached_attrs, vap, sizeof(*vap)); pool_put(&fusefs_fbuf_pool, fbuf); return (error); fake: bzero(vap, sizeof(*vap)); vap->va_type = vp->v_type; return (0); }
int fusefs_setattr(void *v) { struct vop_setattr_args *ap = v; struct vattr *vap = ap->a_vap; struct vnode *vp = ap->a_vp; struct fusefs_node *ip = VTOI(vp); struct proc *p = curproc; struct fusefs_mnt *fmp; struct fusebuf *fbuf; struct fb_io *io; int error = 0; fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; /* * Check for unsettable attributes. */ if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) return (EINVAL); if (!fmp->sess_init || (fmp->undef_op & UNDEF_SETATTR)) return (ENXIO); fbuf = fb_setup(sizeof(*io), ip->ufs_ino.i_number, FBT_SETATTR, p); io = fbtod(fbuf, struct fb_io *); io->fi_flags = 0; if (vap->va_uid != (uid_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) { error = EROFS; goto out; } fbuf->fb_vattr.va_uid = vap->va_uid; io->fi_flags |= FUSE_FATTR_UID; } if (vap->va_gid != (gid_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) { error = EROFS; goto out; } fbuf->fb_vattr.va_gid = vap->va_gid; io->fi_flags |= FUSE_FATTR_GID; } if (vap->va_size != VNOVAL) { switch (vp->v_type) { case VDIR: error = EISDIR; goto out; case VLNK: case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) { error = EROFS; goto out; } break; default: break; } fbuf->fb_vattr.va_size = vap->va_size; io->fi_flags |= FUSE_FATTR_SIZE; } if (vap->va_atime.tv_sec != VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) { error = EROFS; goto out; } fbuf->fb_vattr.va_atime.tv_sec = vap->va_atime.tv_sec; fbuf->fb_vattr.va_atime.tv_nsec = vap->va_atime.tv_nsec; io->fi_flags |= FUSE_FATTR_ATIME; } if (vap->va_mtime.tv_sec != VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) { error = EROFS; goto out; } fbuf->fb_vattr.va_mtime.tv_sec = vap->va_mtime.tv_sec; fbuf->fb_vattr.va_mtime.tv_nsec = vap->va_mtime.tv_nsec; io->fi_flags |= FUSE_FATTR_MTIME; } if (vap->va_mode != (mode_t)VNOVAL) { if (vp->v_mount->mnt_flag & MNT_RDONLY) { error = EROFS; goto out; } fbuf->fb_vattr.va_mode = vap->va_mode & ALLPERMS; io->fi_flags |= FUSE_FATTR_MODE; } if (!io->fi_flags) { goto out; } if (io->fi_flags & FUSE_FATTR_SIZE && vp->v_type == VDIR) { error = EISDIR; goto out; } error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_SETATTR; goto out; } update_vattr(fmp->mp, &fbuf->fb_vattr); memcpy(vap, &fbuf->fb_vattr, sizeof(*vap)); VN_KNOTE(ap->a_vp, NOTE_ATTRIB); out: fb_delete(fbuf); return (error); }
int fusefs_lookup(void *v) { struct vop_lookup_args *ap = v; struct vnode *vdp; /* vnode for directory being searched */ struct fusefs_node *dp; /* inode for directory being searched */ struct fusefs_mnt *fmp; /* file system that directory is in */ int lockparent; /* 1 => lockparent flag is set */ struct vnode *tdp; /* returned by VOP_VGET */ struct fusebuf *fbuf = NULL; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; struct proc *p = cnp->cn_proc; struct ucred *cred = cnp->cn_cred; int flags; int nameiop = cnp->cn_nameiop; int wantparent; int error = 0; uint64_t nid; flags = cnp->cn_flags; *vpp = NULL; vdp = ap->a_dvp; dp = VTOI(vdp); fmp = (struct fusefs_mnt *)dp->ufs_ino.i_ump; lockparent = flags & LOCKPARENT; wantparent = flags & (LOCKPARENT | WANTPARENT); DPRINTF("lookup path %s\n", cnp->cn_pnbuf); DPRINTF("lookup file %s\n", cnp->cn_nameptr); if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0) return (error); if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) return (EROFS); if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) return (error); if (flags & ISDOTDOT) { /* got ".." */ nid = dp->parent; if (nid == 0) return (ENOENT); } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') { nid = dp->ufs_ino.i_number; } else { /* got a real entry */ fbuf = fb_setup(FUSEFDSIZE + cnp->cn_namelen + 1, dp->ufs_ino.i_number, FBT_LOOKUP, p); memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); fbuf->fb_dat[cnp->cn_namelen] = '\0'; error = fb_queue(fmp->dev, fbuf); /* tsleep return */ if (error == EWOULDBLOCK) goto out; if (error) { if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) { if (vdp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); cnp->cn_flags |= SAVENAME; if (!lockparent) { VOP_UNLOCK(vdp, 0, p); cnp->cn_flags |= PDIRUNLOCK; } error = EJUSTRETURN; goto out; } error = ENOENT; goto out; } nid = fbuf->fb_vattr.va_fileid; } if (nameiop == DELETE && (flags & ISLASTCN)) { /* * Write access to directory required to delete files. */ error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc); if (error != 0) { if (fbuf) pool_put(&fusefs_fbuf_pool, fbuf); return (error); } cnp->cn_flags |= SAVENAME; } if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) { /* * Write access to directory required to delete files. */ if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0) return (error); if (nid == VTOI(vdp)->ufs_ino.i_number) { error = EISDIR; goto out; } error = VFS_VGET(fmp->mp, nid, &tdp); if (error) goto out; tdp->v_type = IFTOVT(fbuf->fb_vattr.va_mode); VTOI(tdp)->vtype = tdp->v_type; *vpp = tdp; cnp->cn_flags |= SAVENAME; goto out; } if (flags & ISDOTDOT) { VOP_UNLOCK(vdp, 0, p); /* race to get the inode */ cnp->cn_flags |= PDIRUNLOCK; error = VFS_VGET(fmp->mp, nid, &tdp); if (error) { if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) cnp->cn_flags &= ~PDIRUNLOCK; return (error); } if (lockparent && (flags & ISLASTCN)) { if ((error = vn_lock(vdp, LK_EXCLUSIVE, p))) { vput(tdp); return (error); } cnp->cn_flags &= ~PDIRUNLOCK; } *vpp = tdp; } else if (nid == dp->ufs_ino.i_number) { vref(vdp); *vpp = vdp; error = 0; } else { error = VFS_VGET(fmp->mp, nid, &tdp); if (!error) { tdp->v_type = IFTOVT(fbuf->fb_vattr.va_mode); VTOI(tdp)->vtype = tdp->v_type; } update_vattr(fmp->mp, &fbuf->fb_vattr); memcpy(&(VTOI(tdp)->cached_attrs), &fbuf->fb_vattr, sizeof(struct vattr)); if (error) { if (fbuf) pool_put(&fusefs_fbuf_pool, fbuf); return (error); } if (vdp != NULL && vdp->v_type == VDIR) VTOI(tdp)->parent = dp->ufs_ino.i_number; if (!lockparent || !(flags & ISLASTCN)) { VOP_UNLOCK(vdp, 0, p); cnp->cn_flags |= PDIRUNLOCK; } *vpp = tdp; } out: if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE && nameiop != DELETE) cache_enter(vdp, *vpp, cnp); if (fbuf) pool_put(&fusefs_fbuf_pool, fbuf); return (error); }