xref: /openbsd-src/sys/miscfs/fuse/fuse_lookup.c (revision 51d8761d1e63aff7173adb7b282dbb4d6279257d)
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