1/*	$NetBSD: filecore_lookup.c,v 1.22 2022/08/06 18:26:42 andvar Exp $	*/
2
3/*-
4 * Copyright (c) 1989, 1993, 1994 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *	filecore_lookup.c	1.1	1998/6/26
32 */
33
34/*-
35 * Copyright (c) 1998 Andrew McMurry
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 *    must display the following acknowledgement:
47 *	This product includes software developed by the University of
48 *	California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 *    may be used to endorse or promote products derived from this software
51 *    without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 *	filecore_lookup.c	1.1	1998/6/26
66 */
67
68#include <sys/cdefs.h>
69__KERNEL_RCSID(0, "$NetBSD: filecore_lookup.c,v 1.22 2022/08/06 18:26:42 andvar Exp $");
70
71#include <sys/param.h>
72#include <sys/namei.h>
73#include <sys/buf.h>
74#include <sys/file.h>
75#include <sys/vnode.h>
76#include <sys/mount.h>
77#include <sys/systm.h>
78
79#include <fs/filecorefs/filecore.h>
80#include <fs/filecorefs/filecore_extern.h>
81#include <fs/filecorefs/filecore_node.h>
82
83/*
84 * Convert a component of a pathname into a pointer to a locked inode.
85 * This is a very central and rather complicated routine.
86 * If the file system is not maintained in a strict tree hierarchy,
87 * this can result in a deadlock situation (see comments in code below).
88 *
89 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
90 * whether the name is to be looked up, created, renamed, or deleted.
91 * When CREATE, RENAME, or DELETE is specified, information usable in
92 * creating, renaming, or deleting a directory entry may be calculated.
93 * If flag has LOCKPARENT or'ed into it and the target of the pathname
94 * exists, lookup returns both the target and its parent directory locked.
95 * When creating or renaming and LOCKPARENT is specified, the target may
96 * not be ".".  When deleting and LOCKPARENT is specified, the target may
97 * be "."., but the caller must check to ensure it does an vrele and iput
98 * instead of two iputs.
99 *
100 * Overall outline of ufs_lookup:
101 *
102 *	check accessibility of directory
103 *	look for name in cache, if found, then if at end of path
104 *	  and deleting or creating, drop it, else return name
105 *	search for name in directory, to found or notfound
106 * notfound:
107 *	if creating, return locked directory, leaving info on available slots
108 *	else return error
109 * found:
110 *	if at end of path and deleting, return information to allow delete
111 *	if at end of path and rewriting (RENAME and LOCKPARENT), lock target
112 *	  inode and return info to allow rewrite
113 *	if not at end, add name to cache; if at end and neither creating
114 *	  nor deleting, add name to cache
115 *
116 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked.
117 */
118int
119filecore_lookup(void *v)
120{
121	struct vop_lookup_v2_args /* {
122		struct vnode *a_dvp;
123		struct vnode **a_vpp;
124		struct componentname *a_cnp;
125	} */ *ap = v;
126	struct vnode *vdp;		/* vnode for directory being searched */
127	struct filecore_node *dp;	/* inode for directory being searched */
128	struct buf *bp;			/* a buffer of directory entries */
129	struct filecore_direntry *de;
130	int numdirpasses;		/* strategy for directory search */
131	int error;
132	u_short namelen;
133	int res;
134	const char *name;
135	struct vnode **vpp = ap->a_vpp;
136	struct componentname *cnp = ap->a_cnp;
137	kauth_cred_t cred = cnp->cn_cred;
138	int flags;
139	int nameiop = cnp->cn_nameiop;
140	int i, endsearch;
141
142	flags = cnp->cn_flags;
143
144	bp = NULL;
145	*vpp = NULL;
146	vdp = ap->a_dvp;
147	dp = VTOI(vdp);
148
149	/*
150	 * Check accessibility of directory.
151	 */
152	if ((error = VOP_ACCESS(vdp, VEXEC, cred)) != 0)
153		return (error);
154
155	if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
156	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
157		return (EROFS);
158
159	/*
160	 * We now have a segment name to search for, and a directory to search.
161	 *
162	 * Before tediously performing a linear scan of the directory,
163	 * check the name cache to see if the directory/name pair
164	 * we are looking for is known already.
165	 */
166	if (cache_lookup(vdp, cnp->cn_nameptr, cnp->cn_namelen,
167			 cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) {
168		return *vpp == NULLVP ? ENOENT : 0;
169	}
170
171	name = cnp->cn_nameptr;
172	namelen = cnp->cn_namelen;
173
174	/*
175	 * If there is cached information on a previous search of
176	 * this directory, pick up where we last left off.
177	 * We cache only lookups as these are the most common
178	 * and have the greatest payoff. Caching CREATE has little
179	 * benefit as it usually must search the entire directory
180	 * to determine that the entry does not exist. Caching the
181	 * location of the last DELETE or RENAME has not reduced
182	 * profiling time and hence has been removed in the interest
183	 * of simplicity.
184	 */
185	if (nameiop != LOOKUP || dp->i_diroff == 0 ||
186	    dp->i_diroff >= FILECORE_MAXDIRENTS) {
187		i = 0;
188		numdirpasses = 1;
189	} else {
190		i = dp->i_diroff;
191		numdirpasses = 2;
192		namecache_count_2passes();
193	}
194	endsearch = FILECORE_MAXDIRENTS;
195
196	if ((flags & ISDOTDOT) || (name[0] == '.' && namelen == 1))
197		goto found;
198
199	error = filecore_dbread(dp, &bp);
200	if (error) {
201		return error;
202	}
203
204	de = fcdirentry(bp->b_data, i);
205
206searchloop:
207	while (de->name[0] != 0 && i < endsearch) {
208		/*
209		 * Check for a name match.
210		 */
211		res = filecore_fncmp(de->name, name, namelen);
212
213		if (res == 0)
214			goto found;
215		if (res < 0)
216			goto notfound;
217
218		i++;
219		de++;
220	}
221
222notfound:
223	/*
224	 * If we started in the middle of the directory and failed
225	 * to find our target, we must check the beginning as well.
226	 */
227	if (numdirpasses == 2) {
228		numdirpasses--;
229		i = 0;
230		de = fcdirentry(bp->b_data, i);
231		endsearch = dp->i_diroff;
232		goto searchloop;
233	}
234	if (bp != NULL) {
235#ifdef FILECORE_DEBUG_BR
236			printf("brelse(%p) lo1\n", bp);
237#endif
238		brelse(bp, 0);
239	}
240
241	/*
242	 * Insert name into cache (as non-existent) if appropriate.
243	 */
244	cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
245		    cnp->cn_flags);
246	return (nameiop == CREATE || nameiop == RENAME) ? EROFS : ENOENT;
247
248found:
249	if (numdirpasses == 2)
250		namecache_count_pass2();
251
252	/*
253	 * Found component in pathname.
254	 * If the final component of path name, save information
255	 * in the cache as to where the entry was found.
256	 */
257	if ((flags & ISLASTCN) && nameiop == LOOKUP)
258		dp->i_diroff = i;
259
260	if (name[0] == '.' && namelen == 1) {
261		vref(vdp);	/* we want ourself, ie "." */
262		*vpp = vdp;
263	} else {
264		ino_t ino;
265
266		if (flags & ISDOTDOT) {
267			ino = filecore_getparent(dp);
268		} else {
269			ino = dp->i_dirent.addr | (i << FILECORE_INO_INDEX);
270#ifdef FILECORE_DEBUG_BR
271			printf("brelse(%p) lo4\n", bp);
272#endif
273			brelse(bp, 0);
274		}
275		error = vcache_get(vdp->v_mount, &ino, sizeof(ino), vpp);
276		if (error)
277			return error;
278	}
279
280	/*
281	 * Insert name into cache if appropriate.
282	 */
283	cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
284		    cnp->cn_flags);
285	return 0;
286}
287