1*51d8761dSclaudio /* $OpenBSD: fuse_lookup.c,v 1.22 2024/10/31 13:55:21 claudio Exp $ */ 2a2badd06Stedu /* 3a2badd06Stedu * Copyright (c) 2012-2013 Sylvestre Gallon <ccna.syl@gmail.com> 4a2badd06Stedu * 5a2badd06Stedu * Permission to use, copy, modify, and distribute this software for any 6a2badd06Stedu * purpose with or without fee is hereby granted, provided that the above 7a2badd06Stedu * copyright notice and this permission notice appear in all copies. 8a2badd06Stedu * 9a2badd06Stedu * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10a2badd06Stedu * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11a2badd06Stedu * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12a2badd06Stedu * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13a2badd06Stedu * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14a2badd06Stedu * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15a2badd06Stedu * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16a2badd06Stedu */ 17a2badd06Stedu 18a2badd06Stedu #include <sys/param.h> 194bc91defSmpi #include <sys/systm.h> 20a2badd06Stedu #include <sys/mount.h> 21a2badd06Stedu #include <sys/namei.h> 226f9b5942Snatano #include <sys/stat.h> 23a2badd06Stedu #include <sys/statvfs.h> 24a2badd06Stedu #include <sys/vnode.h> 25fde894e5Stedu #include <sys/lock.h> 26a2badd06Stedu #include <sys/fusebuf.h> 27a2badd06Stedu 28a2badd06Stedu #include "fusefs_node.h" 29a2badd06Stedu #include "fusefs.h" 30a2badd06Stedu 31a2badd06Stedu int fusefs_lookup(void *); 32a2badd06Stedu 33a2badd06Stedu int 34a2badd06Stedu fusefs_lookup(void *v) 35a2badd06Stedu { 36a2badd06Stedu struct vop_lookup_args *ap = v; 37a2badd06Stedu struct vnode *vdp; /* vnode for directory being searched */ 38a2badd06Stedu struct fusefs_node *dp; /* inode for directory being searched */ 39a2badd06Stedu struct fusefs_mnt *fmp; /* file system that directory is in */ 40a2badd06Stedu int lockparent; /* 1 => lockparent flag is set */ 41a2badd06Stedu struct vnode *tdp; /* returned by VOP_VGET */ 425e69e0b6Snatano struct fusebuf *fbuf; 43a2badd06Stedu struct vnode **vpp = ap->a_vpp; 44a2badd06Stedu struct componentname *cnp = ap->a_cnp; 45a2badd06Stedu struct proc *p = cnp->cn_proc; 46a2badd06Stedu struct ucred *cred = cnp->cn_cred; 475e69e0b6Snatano uint64_t nid; 485e69e0b6Snatano enum vtype nvtype; 49a2badd06Stedu int flags; 50a2badd06Stedu int nameiop = cnp->cn_nameiop; 51204e8faeStedu int wantparent; 52a2badd06Stedu int error = 0; 53a2badd06Stedu 54a2badd06Stedu flags = cnp->cn_flags; 55a2badd06Stedu *vpp = NULL; 56a2badd06Stedu vdp = ap->a_dvp; 57a2badd06Stedu dp = VTOI(vdp); 58*51d8761dSclaudio fmp = (struct fusefs_mnt *)dp->i_ump; 59a2badd06Stedu lockparent = flags & LOCKPARENT; 60204e8faeStedu wantparent = flags & (LOCKPARENT | WANTPARENT); 61a2badd06Stedu 62a2badd06Stedu if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0) 63a2badd06Stedu return (error); 64a2badd06Stedu 65a2badd06Stedu if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 66a2badd06Stedu (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 67a2badd06Stedu return (EROFS); 68a2badd06Stedu 695e69e0b6Snatano if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') { 70*51d8761dSclaudio nid = dp->i_number; 71a2badd06Stedu } else { 7252b7a2e5Ssyl if (!fmp->sess_init) 7352b7a2e5Ssyl return (ENOENT); 7452b7a2e5Ssyl 75a2badd06Stedu /* got a real entry */ 76*51d8761dSclaudio fbuf = fb_setup(cnp->cn_namelen + 1, dp->i_number, 774c526d15Ssyl FBT_LOOKUP, p); 78a2badd06Stedu 79a2badd06Stedu memcpy(fbuf->fb_dat, cnp->cn_nameptr, cnp->cn_namelen); 80a2badd06Stedu fbuf->fb_dat[cnp->cn_namelen] = '\0'; 81a2badd06Stedu 82a2badd06Stedu error = fb_queue(fmp->dev, fbuf); 83a2badd06Stedu 845e69e0b6Snatano if (error) { 855e69e0b6Snatano fb_delete(fbuf); 865e69e0b6Snatano 8713907cdeShelg /* file system is dead */ 8813907cdeShelg if (error == ENXIO) 895e69e0b6Snatano return (error); 90a2badd06Stedu 91a2badd06Stedu if ((nameiop == CREATE || nameiop == RENAME) && 92a2badd06Stedu (flags & ISLASTCN)) { 93ed6e40b2Shelg /* 94ed6e40b2Shelg * Access for write is interpreted as allowing 95ed6e40b2Shelg * creation of files in the directory. 96ed6e40b2Shelg */ 97ed6e40b2Shelg if ((error = VOP_ACCESS(vdp, VWRITE, cred, 98ed6e40b2Shelg cnp->cn_proc)) != 0) 99ed6e40b2Shelg return (error); 100a2badd06Stedu 101a2badd06Stedu cnp->cn_flags |= SAVENAME; 102a2badd06Stedu 103a2badd06Stedu if (!lockparent) { 10436bb23f1Svisa VOP_UNLOCK(vdp); 105a2badd06Stedu cnp->cn_flags |= PDIRUNLOCK; 106a2badd06Stedu } 107a2badd06Stedu 1085e69e0b6Snatano return (EJUSTRETURN); 109a2badd06Stedu } 110a2badd06Stedu 1115e69e0b6Snatano return (ENOENT); 112a2badd06Stedu } 113a2badd06Stedu 114dae5ffecShelg nid = fbuf->fb_ino; 1155e69e0b6Snatano nvtype = IFTOVT(fbuf->fb_attr.st_mode); 1165e69e0b6Snatano fb_delete(fbuf); 117a2badd06Stedu } 118a2badd06Stedu 119a2badd06Stedu if (nameiop == DELETE && (flags & ISLASTCN)) { 120a2badd06Stedu /* 121a2badd06Stedu * Write access to directory required to delete files. 122a2badd06Stedu */ 123a2badd06Stedu error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc); 124847e9294Snatano if (error) 1255e69e0b6Snatano goto reclaim; 126a2badd06Stedu 127a2badd06Stedu cnp->cn_flags |= SAVENAME; 128a2badd06Stedu } 129a2badd06Stedu 130204e8faeStedu if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) { 131a2badd06Stedu /* 132a2badd06Stedu * Write access to directory required to delete files. 133a2badd06Stedu */ 134847e9294Snatano if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0) 1355e69e0b6Snatano goto reclaim; 136a2badd06Stedu 137*51d8761dSclaudio if (nid == dp->i_number) 1385e69e0b6Snatano return (EISDIR); 139a2badd06Stedu 140204e8faeStedu error = VFS_VGET(fmp->mp, nid, &tdp); 141204e8faeStedu if (error) 1425e69e0b6Snatano goto reclaim; 143204e8faeStedu 1445e69e0b6Snatano tdp->v_type = nvtype; 145204e8faeStedu *vpp = tdp; 146a2badd06Stedu cnp->cn_flags |= SAVENAME; 147a2badd06Stedu 1485e69e0b6Snatano return (0); 149a2badd06Stedu } 150a2badd06Stedu 151a2badd06Stedu if (flags & ISDOTDOT) { 15236bb23f1Svisa VOP_UNLOCK(vdp); /* race to get the inode */ 153a2badd06Stedu cnp->cn_flags |= PDIRUNLOCK; 154a2badd06Stedu 155a2badd06Stedu error = VFS_VGET(fmp->mp, nid, &tdp); 156a2badd06Stedu 157a2badd06Stedu if (error) { 1586e880534Svisa if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY) == 0) 159a2badd06Stedu cnp->cn_flags &= ~PDIRUNLOCK; 160a2badd06Stedu 1615e69e0b6Snatano goto reclaim; 162a2badd06Stedu } 163a2badd06Stedu 1645e69e0b6Snatano tdp->v_type = nvtype; 1655e69e0b6Snatano 166a2badd06Stedu if (lockparent && (flags & ISLASTCN)) { 1676e880534Svisa if ((error = vn_lock(vdp, LK_EXCLUSIVE))) { 168a2badd06Stedu vput(tdp); 169a2badd06Stedu return (error); 170a2badd06Stedu } 171a2badd06Stedu cnp->cn_flags &= ~PDIRUNLOCK; 172a2badd06Stedu } 173a2badd06Stedu *vpp = tdp; 174a2badd06Stedu 175*51d8761dSclaudio } else if (nid == dp->i_number) { 176a2badd06Stedu vref(vdp); 177a2badd06Stedu *vpp = vdp; 178a2badd06Stedu error = 0; 179a2badd06Stedu } else { 180a2badd06Stedu error = VFS_VGET(fmp->mp, nid, &tdp); 181847e9294Snatano if (error) 1825e69e0b6Snatano goto reclaim; 183a2badd06Stedu 1845e69e0b6Snatano tdp->v_type = nvtype; 185a2badd06Stedu 186a2badd06Stedu if (!lockparent || !(flags & ISLASTCN)) { 18736bb23f1Svisa VOP_UNLOCK(vdp); 188a2badd06Stedu cnp->cn_flags |= PDIRUNLOCK; 189a2badd06Stedu } 190a2badd06Stedu 191a2badd06Stedu *vpp = tdp; 192a2badd06Stedu } 193a2badd06Stedu 1945e69e0b6Snatano return (error); 1955e69e0b6Snatano 1965e69e0b6Snatano reclaim: 197*51d8761dSclaudio if (nid != dp->i_number && nid != FUSE_ROOTINO) { 1985e69e0b6Snatano fbuf = fb_setup(0, nid, FBT_RECLAIM, p); 1995e69e0b6Snatano if (fb_queue(fmp->dev, fbuf)) 2005e69e0b6Snatano printf("fusefs: libfuse vnode reclaim failed\n"); 20137318181Ssyl fb_delete(fbuf); 2025e69e0b6Snatano } 203a2badd06Stedu return (error); 204a2badd06Stedu } 205