1 /* $OpenBSD: fuse_lookup.c,v 1.15 2016/08/30 16:45:54 natano Exp $ */ 2 /* 3 * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/mount.h> 21 #include <sys/namei.h> 22 #include <sys/stat.h> 23 #include <sys/statvfs.h> 24 #include <sys/vnode.h> 25 #include <sys/lock.h> 26 #include <sys/fusebuf.h> 27 28 #include "fusefs_node.h" 29 #include "fusefs.h" 30 31 int fusefs_lookup(void *); 32 33 int 34 fusefs_lookup(void *v) 35 { 36 struct vop_lookup_args *ap = v; 37 struct vnode *vdp; /* vnode for directory being searched */ 38 struct fusefs_node *dp; /* inode for directory being searched */ 39 struct fusefs_mnt *fmp; /* file system that directory is in */ 40 int lockparent; /* 1 => lockparent flag is set */ 41 struct vnode *tdp; /* returned by VOP_VGET */ 42 struct fusebuf *fbuf = NULL; 43 struct vnode **vpp = ap->a_vpp; 44 struct componentname *cnp = ap->a_cnp; 45 struct proc *p = cnp->cn_proc; 46 struct ucred *cred = cnp->cn_cred; 47 int flags; 48 int nameiop = cnp->cn_nameiop; 49 int wantparent; 50 int error = 0; 51 uint64_t nid; 52 53 flags = cnp->cn_flags; 54 *vpp = NULL; 55 vdp = ap->a_dvp; 56 dp = VTOI(vdp); 57 fmp = (struct fusefs_mnt *)dp->ufs_ino.i_ump; 58 lockparent = flags & LOCKPARENT; 59 wantparent = flags & (LOCKPARENT | WANTPARENT); 60 61 if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0) 62 return (error); 63 64 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 65 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 66 return (EROFS); 67 68 if (flags & ISDOTDOT) { 69 /* got ".." */ 70 nid = dp->parent; 71 if (nid == 0) 72 return (ENOENT); 73 } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') { 74 nid = dp->ufs_ino.i_number; 75 } else { 76 if (!fmp->sess_init) 77 return (ENOENT); 78 79 /* got a real entry */ 80 fbuf = fb_setup(cnp->cn_namelen + 1, dp->ufs_ino.i_number, 81 FBT_LOOKUP, p); 82 83 memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); 84 fbuf->fb_dat[cnp->cn_namelen] = '\0'; 85 86 error = fb_queue(fmp->dev, fbuf); 87 88 /* tsleep return */ 89 if (error == EWOULDBLOCK) 90 goto out; 91 92 if (error) { 93 if ((nameiop == CREATE || nameiop == RENAME) && 94 (flags & ISLASTCN)) { 95 if (vdp->v_mount->mnt_flag & MNT_RDONLY) 96 return (EROFS); 97 98 cnp->cn_flags |= SAVENAME; 99 100 if (!lockparent) { 101 VOP_UNLOCK(vdp, p); 102 cnp->cn_flags |= PDIRUNLOCK; 103 } 104 105 error = EJUSTRETURN; 106 goto out; 107 } 108 109 error = ENOENT; 110 goto out; 111 } 112 113 nid = fbuf->fb_attr.st_ino; 114 } 115 116 if (nameiop == DELETE && (flags & ISLASTCN)) { 117 /* 118 * Write access to directory required to delete files. 119 */ 120 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc); 121 if (error) 122 goto out; 123 124 cnp->cn_flags |= SAVENAME; 125 } 126 127 if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) { 128 /* 129 * Write access to directory required to delete files. 130 */ 131 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0) 132 goto out; 133 134 if (nid == VTOI(vdp)->ufs_ino.i_number) { 135 error = EISDIR; 136 goto out; 137 } 138 139 error = VFS_VGET(fmp->mp, nid, &tdp); 140 if (error) 141 goto out; 142 143 tdp->v_type = IFTOVT(fbuf->fb_attr.st_mode); 144 *vpp = tdp; 145 cnp->cn_flags |= SAVENAME; 146 147 goto out; 148 } 149 150 if (flags & ISDOTDOT) { 151 VOP_UNLOCK(vdp, p); /* race to get the inode */ 152 cnp->cn_flags |= PDIRUNLOCK; 153 154 error = VFS_VGET(fmp->mp, nid, &tdp); 155 156 if (error) { 157 if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) 158 cnp->cn_flags &= ~PDIRUNLOCK; 159 160 return (error); 161 } 162 163 if (lockparent && (flags & ISLASTCN)) { 164 if ((error = vn_lock(vdp, LK_EXCLUSIVE, p))) { 165 vput(tdp); 166 return (error); 167 } 168 cnp->cn_flags &= ~PDIRUNLOCK; 169 } 170 *vpp = tdp; 171 172 } else if (nid == dp->ufs_ino.i_number) { 173 vref(vdp); 174 *vpp = vdp; 175 error = 0; 176 } else { 177 error = VFS_VGET(fmp->mp, nid, &tdp); 178 if (error) 179 goto out; 180 181 tdp->v_type = IFTOVT(fbuf->fb_attr.st_mode); 182 183 if (vdp != NULL && vdp->v_type == VDIR) 184 VTOI(tdp)->parent = dp->ufs_ino.i_number; 185 186 if (!lockparent || !(flags & ISLASTCN)) { 187 VOP_UNLOCK(vdp, p); 188 cnp->cn_flags |= PDIRUNLOCK; 189 } 190 191 *vpp = tdp; 192 } 193 194 out: 195 fb_delete(fbuf); 196 return (error); 197 } 198