int fusefs_write(void *v) { struct vop_write_args *ap = v; struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct proc *p = uio->uio_procp; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf = NULL; size_t len, diff; int error=0; DPRINTF("fusefs_write\n"); ip = VTOI(vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; DPRINTF("write inode=%i, offset=%llu, resid=%x\n", ip->ufs_ino.i_number, uio->uio_offset, uio->uio_resid); if (uio->uio_resid == 0) return (error); while (uio->uio_resid > 0) { len = MIN(uio->uio_resid, FUSELEN); fbuf = fb_setup(FUSEFDSIZE + len, ip->ufs_ino.i_number, FBT_WRITE, p); fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_WRONLY); fbuf->fb_io_off = uio->uio_offset; fbuf->fb_io_len = len; if ((error = uiomove(fbuf->fb_dat, len, uio))) { DPRINTF("uio error %i", error); break; } error = fb_queue(fmp->dev, fbuf); if (error) break; diff = len - fbuf->fb_io_len; if (diff < 0) { error = EINVAL; break; } uio->uio_resid += diff; uio->uio_offset -= diff; pool_put(&fusefs_fbuf_pool, fbuf); fbuf = NULL; } if (fbuf) pool_put(&fusefs_fbuf_pool, fbuf); return (error); }
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_readdir(void *v) { struct vop_readdir_args *ap = v; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf; struct vnode *vp; struct proc *p; struct uio *uio; int error = 0; vp = ap->a_vp; uio = ap->a_uio; p = uio->uio_procp; ip = VTOI(vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init) return (0); if (uio->uio_resid < sizeof(struct dirent)) return (EINVAL); while (uio->uio_resid > 0) { fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_READDIR, p); if (ip->fufh[FUFH_RDONLY].fh_type == FUFH_INVALID) { /* TODO open the file */ fb_delete(fbuf); return (error); } fbuf->fb_io_fd = ip->fufh[FUFH_RDONLY].fh_id; fbuf->fb_io_off = uio->uio_offset; fbuf->fb_io_len = MIN(uio->uio_resid, FUSEBUFMAXSIZE); error = fb_queue(fmp->dev, fbuf); if (error) { fb_delete(fbuf); break; } /*ack end of readdir */ if (fbuf->fb_len == 0) { fb_delete(fbuf); break; } if ((error = uiomove(fbuf->fb_dat, fbuf->fb_len, uio))) { fb_delete(fbuf); break; } fb_delete(fbuf); } return (error); }
int fusefs_mkdir(void *v) { struct vop_mkdir_args *ap = v; struct vnode *dvp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; struct vattr *vap = ap->a_vap; struct proc *p = cnp->cn_proc; struct vnode *tdp = NULL; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf; int error = 0; DPRINTF("fusefs_mkdir %s\n", cnp->cn_nameptr); ip = VTOI(dvp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init || (fmp->undef_op & UNDEF_MKDIR)) { error = ENOSYS; goto out; } fbuf = fb_setup(FUSEFDSIZE + cnp->cn_namelen + 1, ip->ufs_ino.i_number, FBT_MKDIR, p); fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode); memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); fbuf->fb_dat[cnp->cn_namelen] = '\0'; error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_MKDIR; pool_put(&fusefs_fbuf_pool, fbuf); goto out; } if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) { pool_put(&fusefs_fbuf_pool, fbuf); goto out; } tdp->v_type = IFTOVT(fbuf->fb_io_mode); VTOI(tdp)->vtype = tdp->v_type; if (dvp != NULL && dvp->v_type == VDIR) VTOI(tdp)->parent = ip->ufs_ino.i_number; *vpp = tdp; VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK); pool_put(&fusefs_fbuf_pool, fbuf); out: vput(dvp); return (error); }
int fusefs_symlink(void *v) { struct vop_symlink_args *ap = v; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; struct vnode *dvp = ap->a_dvp; struct proc *p = cnp->cn_proc; char *target = ap->a_target; struct fusefs_node *dp; struct fusefs_mnt *fmp; struct fusebuf *fbuf; struct vnode *tdp; int error = 0; int len; dp = VTOI(dvp); fmp = (struct fusefs_mnt *)dp->ufs_ino.i_ump; if (!fmp->sess_init || (fmp->undef_op & UNDEF_SYMLINK)) { error = ENOSYS; goto bad; } len = strlen(target) + 1; fbuf = fb_setup(len + cnp->cn_namelen + 1, dp->ufs_ino.i_number, FBT_SYMLINK, p); memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); fbuf->fb_dat[cnp->cn_namelen] = '\0'; memcpy(&fbuf->fb_dat[cnp->cn_namelen + 1], target, len); error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_SYMLINK; fb_delete(fbuf); goto bad; } if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) { fb_delete(fbuf); goto bad; } tdp->v_type = VLNK; VTOI(tdp)->vtype = tdp->v_type; VTOI(tdp)->parent = dp->ufs_ino.i_number; VN_KNOTE(ap->a_dvp, NOTE_WRITE); *vpp = tdp; fb_delete(fbuf); vput(tdp); bad: vput(dvp); return (error); }
int fusefs_read(void *v) { struct vop_read_args *ap = v; struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct proc *p = uio->uio_procp; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf = NULL; size_t size; int error=0; DPRINTF("fusefs_read\n"); ip = VTOI(vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; DPRINTF("read inode=%i, offset=%llu, resid=%x\n", ip->ufs_ino.i_number, uio->uio_offset, uio->uio_resid); if (uio->uio_resid == 0) return (error); if (uio->uio_offset < 0) return (EINVAL); while (uio->uio_resid > 0) { fbuf = fb_setup(FUSEFDSIZE, ip->ufs_ino.i_number, FBT_READ, p); size = MIN(uio->uio_resid, FUSELEN); fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_RDONLY); fbuf->fb_io_off = uio->uio_offset; fbuf->fb_io_len = size; error = fb_queue(fmp->dev, fbuf); if (error) break; error = uiomove(fbuf->fb_dat, MIN(size, fbdatsize(fbuf)), uio); if (error) break; if (fbdatsize(fbuf) < size) break; pool_put(&fusefs_fbuf_pool, fbuf); fbuf = NULL; } if (fbuf) pool_put(&fusefs_fbuf_pool, fbuf); return (error); }
int fusefs_remove(void *v) { struct vop_remove_args *ap = v; struct vnode *vp = ap->a_vp; struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; struct proc *p = cnp->cn_proc; struct fusefs_node *ip; struct fusefs_node *dp; struct fusefs_mnt *fmp; struct fusebuf *fbuf; int error = 0; ip = VTOI(vp); dp = VTOI(dvp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init) { error = ENXIO; goto out; } if (fmp->undef_op & UNDEF_REMOVE) { error = ENOSYS; goto out; } fbuf = fb_setup(cnp->cn_namelen + 1, dp->ufs_ino.i_number, FBT_UNLINK, p); memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); fbuf->fb_dat[cnp->cn_namelen] = '\0'; error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_REMOVE; fb_delete(fbuf); goto out; } VN_KNOTE(vp, NOTE_DELETE); VN_KNOTE(dvp, NOTE_WRITE); fb_delete(fbuf); out: if (dvp == vp) vrele(vp); else vput(vp); vput(dvp); return (error); }
int fusefs_read(void *v) { struct vop_read_args *ap = v; struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct proc *p = uio->uio_procp; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf = NULL; size_t size; int error=0; ip = VTOI(vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init) return (ENXIO); if (uio->uio_resid == 0) return (error); if (uio->uio_offset < 0) return (EINVAL); while (uio->uio_resid > 0) { fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_READ, p); size = MIN(uio->uio_resid, FUSEBUFMAXSIZE); fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_RDONLY); fbuf->fb_io_off = uio->uio_offset; fbuf->fb_io_len = size; error = fb_queue(fmp->dev, fbuf); if (error) break; error = uiomove(fbuf->fb_dat, MIN(size, fbuf->fb_len), uio); if (error) break; if (fbuf->fb_len < size) break; fb_delete(fbuf); fbuf = NULL; } fb_delete(fbuf); return (error); }
int fusefs_reclaim(void *v) { struct vop_reclaim_args *ap = v; struct vnode *vp = ap->a_vp; struct fusefs_node *ip = VTOI(vp); struct fusefs_filehandle *fufh = NULL; struct fusefs_mnt *fmp; struct fusebuf *fbuf; int type; fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; /*close opened files*/ for (type = 0; type < FUFH_MAXTYPE; type++) { fufh = &(ip->fufh[type]); if (fufh->fh_type != FUFH_INVALID) { printf("fusefs: vnode being reclaimed is valid\n"); fusefs_file_close(fmp, ip, fufh->fh_type, type, (ip->vtype == VDIR), curproc); } } /* * Purge old data structures associated with the inode. */ ip->parent = 0; /* * if the fuse connection is opened * ask libfuse to free the vnodes */ if (fmp->sess_init) { fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_RECLAIM, curproc); if (fb_queue(fmp->dev, fbuf)) printf("fusefs: libfuse vnode reclaim failed\n"); fb_delete(fbuf); } /* * Remove the inode from its hash chain. */ ufs_ihashrem(&ip->ufs_ino); cache_purge(vp); free(ip, M_FUSEFS); vp->v_data = NULL; 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_readlink(void *v) { struct vop_readlink_args *ap = v; struct vnode *vp = ap->a_vp; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf; struct uio *uio; struct proc *p; int error = 0; DPRINTF("fusefs_readlink\n"); ip = VTOI(vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; uio = ap->a_uio; p = uio->uio_procp; if (!fmp->sess_init || (fmp->undef_op & UNDEF_READLINK)) { error = ENOSYS; goto out; } fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_READLINK, p); error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_READLINK; pool_put(&fusefs_fbuf_pool, fbuf); goto out; } error = uiomove(fbuf->fb_dat, fbdatsize(fbuf), uio); pool_put(&fusefs_fbuf_pool, fbuf); out: return (error); }
int fusefs_readlink(void *v) { struct vop_readlink_args *ap = v; struct vnode *vp = ap->a_vp; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf; struct uio *uio; struct proc *p; int error = 0; ip = VTOI(vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; uio = ap->a_uio; p = uio->uio_procp; if (!fmp->sess_init) return (ENXIO); if (fmp->undef_op & UNDEF_READLINK) return (ENOSYS); fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_READLINK, p); error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_READLINK; fb_delete(fbuf); return (error); } error = uiomove(fbuf->fb_dat, fbuf->fb_len, uio); fb_delete(fbuf); return (error); }
int fusefs_file_close(struct fusefs_mnt *fmp, struct fusefs_node * ip, enum fufh_type fufh_type, int flags, int isdir, struct proc *p) { struct fusebuf *fbuf; int error = 0; fbuf = fb_setup(FUSEFDSIZE, ip->ufs_ino.i_number, ((isdir) ? FBT_RELEASEDIR : FBT_RELEASE), p); fbuf->fb_io_fd = ip->fufh[fufh_type].fh_id; fbuf->fb_io_flags = flags; error = fb_queue(fmp->dev, fbuf); if (error) printf("fuse file error %d\n", error); ip->fufh[fufh_type].fh_id = (uint64_t)-1; ip->fufh[fufh_type].fh_type = FUFH_INVALID; pool_put(&fusefs_fbuf_pool, fbuf); return (error); }
int fusefs_file_open(struct fusefs_mnt *fmp, struct fusefs_node *ip, enum fufh_type fufh_type, int flags, int isdir, struct proc *p) { struct fusebuf *fbuf; int error = 0; fbuf = fb_setup(FUSEFDSIZE, ip->ufs_ino.i_number, ((isdir) ? FBT_OPENDIR : FBT_OPEN), p); fbuf->fb_io_flags = flags; error = fb_queue(fmp->dev, fbuf); if (error) { pool_put(&fusefs_fbuf_pool, fbuf); return (error); } ip->fufh[fufh_type].fh_id = fbuf->fb_io_fd; ip->fufh[fufh_type].fh_type = fufh_type; pool_put(&fusefs_fbuf_pool, fbuf); return (0); }
int fusefs_rename(void *v) { struct vop_rename_args *ap = v; struct vnode *tvp = ap->a_tvp; struct vnode *tdvp = ap->a_tdvp; struct vnode *fvp = ap->a_fvp; struct vnode *fdvp = ap->a_fdvp; struct componentname *tcnp = ap->a_tcnp; struct componentname *fcnp = ap->a_fcnp; struct proc *p = fcnp->cn_proc; struct fusefs_node *ip, *dp; struct fusefs_mnt *fmp; struct fusebuf *fbuf; int error = 0; #ifdef DIAGNOSTIC if ((tcnp->cn_flags & HASBUF) == 0 || (fcnp->cn_flags & HASBUF) == 0) panic("fusefs_rename: no name"); #endif /* * Check for cross-device rename. */ if ((fvp->v_mount != tdvp->v_mount) || (tvp && (fvp->v_mount != tvp->v_mount))) { error = EXDEV; abortit: VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */ if (tdvp == tvp) vrele(tdvp); else vput(tdvp); if (tvp) vput(tvp); VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */ vrele(fdvp); vrele(fvp); return (error); } /* * If source and dest are the same, do nothing. */ if (tvp == fvp) { error = 0; goto abortit; } if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) != 0) goto abortit; dp = VTOI(fdvp); ip = VTOI(fvp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; /* * Be sure we are not renaming ".", "..", or an alias of ".". This * leads to a crippled directory tree. It's pretty tough to do a * "ls" or "pwd" with the "." directory entry missing, and "cd .." * doesn't work if the ".." entry is missing. */ if (ip->vtype == VDIR) { /* * Avoid ".", "..", and aliases of "." for obvious reasons. */ if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || dp == ip || (fcnp->cn_flags & ISDOTDOT) || (tcnp->cn_flags & ISDOTDOT)) { VOP_UNLOCK(fvp, 0); error = EINVAL; goto abortit; } } VN_KNOTE(fdvp, NOTE_WRITE); /* XXX right place? */ if (!fmp->sess_init || (fmp->undef_op & UNDEF_RENAME)) { error = ENOSYS; VOP_UNLOCK(fvp, 0); goto abortit; } fbuf = fb_setup(fcnp->cn_namelen + tcnp->cn_namelen + 2, dp->ufs_ino.i_number, FBT_RENAME, p); memcpy(fbuf->fb_dat, fcnp->cn_nameptr, fcnp->cn_namelen); fbuf->fb_dat[fcnp->cn_namelen] = '\0'; memcpy(fbuf->fb_dat + fcnp->cn_namelen + 1, tcnp->cn_nameptr, tcnp->cn_namelen); fbuf->fb_dat[fcnp->cn_namelen + tcnp->cn_namelen + 1] = '\0'; fbuf->fb_io_ino = VTOI(tdvp)->ufs_ino.i_number; error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) { fmp->undef_op |= UNDEF_RENAME; } fb_delete(fbuf); VOP_UNLOCK(fvp, 0); goto abortit; } fb_delete(fbuf); VN_KNOTE(fvp, NOTE_RENAME); VOP_UNLOCK(fvp, 0); if (tdvp == tvp) vrele(tdvp); else vput(tdvp); vrele(fdvp); vrele(fvp); return (error); }
int fusefs_mknod(void *v) { struct vop_mknod_args *ap = v; struct componentname *cnp = ap->a_cnp; struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct proc *p = cnp->cn_proc; struct vnode *tdp = NULL; struct fusefs_mnt *fmp; struct fusefs_node *ip; struct fusebuf *fbuf; int error = 0; ip = VTOI(dvp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init || (fmp->undef_op & UNDEF_MKNOD)) { error = ENOSYS; goto out; } fbuf = fb_setup(cnp->cn_namelen + 1, ip->ufs_ino.i_number, FBT_MKNOD, p); fbuf->fb_io_mode = MAKEIMODE(vap->va_type, vap->va_mode); if (vap->va_rdev != VNOVAL) fbuf->fb_io_rdev = vap->va_rdev; memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); fbuf->fb_dat[cnp->cn_namelen] = '\0'; error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_MKNOD; fb_delete(fbuf); goto out; } if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) { fb_delete(fbuf); goto out; } tdp->v_type = IFTOVT(fbuf->fb_io_mode); VTOI(tdp)->vtype = tdp->v_type; if (dvp != NULL && dvp->v_type == VDIR) VTOI(tdp)->parent = ip->ufs_ino.i_number; *vpp = tdp; VN_KNOTE(ap->a_dvp, NOTE_WRITE); fb_delete(fbuf); vput(ap->a_dvp); /* Remove inode so that it will be reloaded by VFS_VGET and * checked to see if it is an alias of an existing entry in * the inode cache. */ vput(*vpp); (*vpp)->v_type = VNON; vgone(*vpp); *vpp = NULL; return (0); out: vput(ap->a_dvp); return (error); }
int fusefs_create(void *v) { struct vop_create_args *ap = v; struct componentname *cnp = ap->a_cnp; struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct proc *p = cnp->cn_proc; struct vnode *tdp = NULL; struct fusefs_mnt *fmp; struct fusefs_node *ip; struct fusebuf *fbuf; int error = 0; mode_t mode; ip = VTOI(dvp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; mode = MAKEIMODE(vap->va_type, vap->va_mode); if (!fmp->sess_init || (fmp->undef_op & UNDEF_CREATE)) { error = ENOSYS; goto out; } fbuf = fb_setup(cnp->cn_namelen + 1, ip->ufs_ino.i_number, FBT_CREATE, p); fbuf->fb_io_mode = mode; fbuf->fb_io_flags = O_CREAT | O_RDWR; memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); fbuf->fb_dat[cnp->cn_namelen] = '\0'; error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_CREATE; fb_delete(fbuf); goto out; } if ((error = VFS_VGET(fmp->mp, fbuf->fb_ino, &tdp))) { fb_delete(fbuf); goto out; } tdp->v_type = IFTOVT(fbuf->fb_io_mode); VTOI(tdp)->vtype = tdp->v_type; if (dvp != NULL && dvp->v_type == VDIR) VTOI(tdp)->parent = ip->ufs_ino.i_number; *vpp = tdp; VN_KNOTE(ap->a_dvp, NOTE_WRITE); fb_delete(fbuf); out: vput(ap->a_dvp); return (error); }
int fusefs_link(void *v) { struct vop_link_args *ap = v; struct vnode *dvp = ap->a_dvp; struct vnode *vp = ap->a_vp; struct componentname *cnp = ap->a_cnp; struct proc *p = cnp->cn_proc; struct fusefs_mnt *fmp; struct fusefs_node *ip; struct fusefs_node *dip; struct fusebuf *fbuf; int error = 0; if (vp->v_type == VDIR) { VOP_ABORTOP(dvp, cnp); error = EISDIR; goto out2; } if (dvp->v_mount != vp->v_mount) { VOP_ABORTOP(dvp, cnp); error = EXDEV; goto out2; } if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) { VOP_ABORTOP(dvp, cnp); goto out2; } ip = VTOI(vp); dip = VTOI(dvp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init || (fmp->undef_op & UNDEF_LINK)) goto out1; fbuf = fb_setup(cnp->cn_namelen + 1, dip->ufs_ino.i_number, FBT_LINK, p); fbuf->fb_io_ino = ip->ufs_ino.i_number; memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); fbuf->fb_dat[cnp->cn_namelen] = '\0'; error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_LINK; fb_delete(fbuf); goto out1; } fb_delete(fbuf); VN_KNOTE(vp, NOTE_LINK); VN_KNOTE(dvp, NOTE_WRITE); out1: if (dvp != vp) VOP_UNLOCK(vp, 0); out2: vput(dvp); return (error); }
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_access(void *v) { struct vop_access_args *ap; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf; struct ucred *cred; struct vattr vattr; struct proc *p; uint32_t mask = 0; int error = 0; ap = v; p = curproc; cred = p->p_ucred; ip = VTOI(ap->a_vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init || (fmp->undef_op & UNDEF_ACCESS)) goto system_check; if (ap->a_vp->v_type == VLNK) goto system_check; if (ap->a_vp->v_type == VREG && (ap->a_mode & VWRITE & VEXEC)) goto system_check; if ((ap->a_mode & VWRITE) && (fmp->mp->mnt_flag & MNT_RDONLY)) return (EACCES); if ((ap->a_mode & VWRITE) != 0) mask |= 0x2; if ((ap->a_mode & VREAD) != 0) mask |= 0x4; if ((ap->a_mode & VEXEC) != 0) mask |= 0x1; fbuf = fb_setup(0, ip->ufs_ino.i_number, FBT_ACCESS, p); fbuf->fb_io_mode = mask; error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) { fmp->undef_op |= UNDEF_ACCESS; fb_delete(fbuf); goto system_check; } printf("fusefs: access error %i\n", error); fb_delete(fbuf); return (error); } fb_delete(fbuf); return (error); system_check: if ((error = VOP_GETATTR(ap->a_vp, &vattr, cred)) != 0) return (error); return (vaccess(ap->a_vp->v_type, vattr.va_mode & ALLPERMS, vattr.va_uid, vattr.va_gid, ap->a_mode, ap->a_cred)); }
int fusefs_rmdir(void *v) { struct vop_rmdir_args *ap = v; struct vnode *vp = ap->a_vp; struct vnode *dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; struct proc *p = cnp->cn_proc; struct fusefs_node *ip, *dp; struct fusefs_mnt *fmp; struct fusebuf *fbuf; int error; ip = VTOI(vp); dp = VTOI(dvp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; /* * No rmdir "." please. */ if (dp == ip) { vrele(dvp); vput(vp); return (EINVAL); } if (!fmp->sess_init || (fmp->undef_op & UNDEF_RMDIR)) { error = ENOSYS; goto out; } VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); fbuf = fb_setup(cnp->cn_namelen + 1, dp->ufs_ino.i_number, FBT_RMDIR, p); memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); fbuf->fb_dat[cnp->cn_namelen] = '\0'; error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) fmp->undef_op |= UNDEF_RMDIR; if (error != ENOTEMPTY) VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); fb_delete(fbuf); goto out; } cache_purge(dvp); vput(dvp); dvp = NULL; cache_purge(ITOV(ip)); fb_delete(fbuf); out: if (dvp) vput(dvp); VN_KNOTE(vp, NOTE_DELETE); vput(vp); return (error); }
int fusefs_access(void *v) { struct vop_access_args *ap; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf; struct proc *p; uint32_t mask = 0; int error = 0; DPRINTF("fusefs_access\n"); ap = v; p = ap->a_p; ip = VTOI(ap->a_vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init || (fmp->undef_op & UNDEF_ACCESS)) goto system_check; if (ap->a_vp->v_type == VLNK) goto system_check; if (ap->a_vp->v_type == VREG && (ap->a_mode & VWRITE & VEXEC)) goto system_check; if ((ap->a_mode & VWRITE) && (fmp->mp->mnt_flag & MNT_RDONLY)) return (EACCES); if ((ap->a_mode & VWRITE) != 0) mask |= 0x2; if ((ap->a_mode & VREAD) != 0) mask |= 0x4; if ((ap->a_mode & VEXEC) != 0) mask |= 0x1; fbuf = fb_setup(FUSEFDSIZE, ip->ufs_ino.i_number, FBT_ACCESS, p); fbuf->fb_io_mode = mask; error = fb_queue(fmp->dev, fbuf); if (error) { if (error == ENOSYS) { fmp->undef_op |= UNDEF_ACCESS; pool_put(&fusefs_fbuf_pool, fbuf); goto system_check; } DPRINTF("access error %i\n", error); pool_put(&fusefs_fbuf_pool, fbuf); return (error); } pool_put(&fusefs_fbuf_pool, fbuf); return (error); system_check: return (vaccess(ap->a_vp->v_type, ip->cached_attrs.va_mode & ALLPERMS, ip->cached_attrs.va_uid, ip->cached_attrs.va_gid, ap->a_mode, ap->a_cred)); }
int fusefs_write(void *v) { struct vop_write_args *ap = v; struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct proc *p = uio->uio_procp; struct ucred *cred = p->p_ucred; struct vattr vattr; int ioflag = ap->a_ioflag; struct fusefs_node *ip; struct fusefs_mnt *fmp; struct fusebuf *fbuf = NULL; size_t len, diff; int error=0; ip = VTOI(vp); fmp = (struct fusefs_mnt *)ip->ufs_ino.i_ump; if (!fmp->sess_init) return (ENXIO); if (uio->uio_resid == 0) return (error); if (ioflag & IO_APPEND) { if ((error = VOP_GETATTR(vp, &vattr, cred)) != 0) return (error); uio->uio_offset = vattr.va_size; } while (uio->uio_resid > 0) { len = MIN(uio->uio_resid, FUSEBUFMAXSIZE); fbuf = fb_setup(len, ip->ufs_ino.i_number, FBT_WRITE, p); fbuf->fb_io_fd = fusefs_fd_get(ip, FUFH_WRONLY); fbuf->fb_io_off = uio->uio_offset; fbuf->fb_io_len = len; if ((error = uiomove(fbuf->fb_dat, len, uio))) { printf("fusefs: uio error %i\n", error); break; } error = fb_queue(fmp->dev, fbuf); if (error) break; if (fbuf->fb_io_len > len) { error = EINVAL; break; } diff = len - fbuf->fb_io_len; uio->uio_resid += diff; uio->uio_offset -= diff; fb_delete(fbuf); fbuf = NULL; } 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); }