xref: /original-bsd/sys/kern/vfs_lookup.c (revision 9802dd40)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)vfs_lookup.c	7.39 (Berkeley) 05/14/92
8  */
9 
10 #include "param.h"
11 #include "syslimits.h"
12 #include "time.h"
13 #include "namei.h"
14 #include "vnode.h"
15 #include "mount.h"
16 #include "errno.h"
17 #include "malloc.h"
18 #include "filedesc.h"
19 #include "proc.h"
20 
21 #ifdef KTRACE
22 #include "ktrace.h"
23 #endif
24 
25 /*
26  * Convert a pathname into a pointer to a locked inode.
27  *
28  * The FOLLOW flag is set when symbolic links are to be followed
29  * when they occur at the end of the name translation process.
30  * Symbolic links are always followed for all other pathname
31  * components other than the last.
32  *
33  * The segflg defines whether the name is to be copied from user
34  * space or kernel space.
35  *
36  * Overall outline of namei:
37  *
38  *	copy in name
39  *	get starting directory
40  *	while (!done && !error) {
41  *		call lookup to search path.
42  *		if symbolic link, massage name in buffer and continue
43  *	}
44  */
45 int
46 namei(ndp)
47 	register struct nameidata *ndp;
48 {
49 	USES_VOP_READLINK;
50 	USES_VOP_UNLOCK;
51 	register struct filedesc *fdp;	/* pointer to file descriptor state */
52 	register char *cp;		/* pointer into pathname argument */
53 	register struct vnode *dp;	/* the directory we are searching */
54 	struct iovec aiov;		/* uio for reading symbolic links */
55 	struct uio auio;
56 	int error, linklen;
57 	struct componentname *cnp = &ndp->ni_cnd;
58 
59 	ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred;
60 #ifdef DIAGNOSTIC
61 	if (!cnp->cn_cred || !cnp->cn_proc)
62 		panic ("namei: bad cred/proc");
63 	if (cnp->cn_nameiop & (~OPMASK))
64 		panic ("namei: nameiop contaminated with flags");
65 	if (cnp->cn_flags & OPMASK)
66 		panic ("namei: flags contaminated with nameiops");
67 #endif
68 	fdp = cnp->cn_proc->p_fd;
69 
70 	/*
71 	 * Get a buffer for the name to be translated, and copy the
72 	 * name into the buffer.
73 	 */
74 	if ((cnp->cn_flags & HASBUF) == 0)
75 		MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
76 	if (ndp->ni_segflg == UIO_SYSSPACE)
77 		error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
78 			    MAXPATHLEN, &ndp->ni_pathlen);
79 	else
80 		error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
81 			    MAXPATHLEN, &ndp->ni_pathlen);
82 	if (error) {
83 		free(cnp->cn_pnbuf, M_NAMEI);
84 		ndp->ni_vp = NULL;
85 		return (error);
86 	}
87 	ndp->ni_loopcnt = 0;
88 #ifdef KTRACE
89 	if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
90 		ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf);
91 #endif
92 
93 	/*
94 	 * Get starting point for the translation.
95 	 */
96 	if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL)
97 		ndp->ni_rootdir = rootdir;
98 	dp = fdp->fd_cdir;
99 	VREF(dp);
100 	for (;;) {
101 		/*
102 		 * Check if root directory should replace current directory.
103 		 * Done at start of translation and after symbolic link.
104 		 */
105 		cnp->cn_nameptr = cnp->cn_pnbuf;
106 		if (*(cnp->cn_nameptr) == '/') {
107 			vrele(dp);
108 			while (*(cnp->cn_nameptr) == '/') {
109 				cnp->cn_nameptr++;
110 				ndp->ni_pathlen--;
111 			}
112 			dp = ndp->ni_rootdir;
113 			VREF(dp);
114 		}
115 		ndp->ni_startdir = dp;
116 		if (error = lookup(ndp)) {
117 			FREE(cnp->cn_pnbuf, M_NAMEI);
118 			return (error);
119 		}
120 		/*
121 		 * Check for symbolic link
122 		 */
123 		if ((cnp->cn_flags & ISSYMLINK) == 0) {
124 			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
125 				FREE(cnp->cn_pnbuf, M_NAMEI);
126 			else
127 				cnp->cn_flags |= HASBUF;
128 			return (0);
129 		}
130 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
131 			VOP_UNLOCK(ndp->ni_dvp);
132 		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
133 			error = ELOOP;
134 			break;
135 		}
136 		if (ndp->ni_pathlen > 1)
137 			MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
138 		else
139 			cp = cnp->cn_pnbuf;
140 		aiov.iov_base = cp;
141 		aiov.iov_len = MAXPATHLEN;
142 		auio.uio_iov = &aiov;
143 		auio.uio_iovcnt = 1;
144 		auio.uio_offset = 0;
145 		auio.uio_rw = UIO_READ;
146 		auio.uio_segflg = UIO_SYSSPACE;
147 		auio.uio_procp = (struct proc *)0;
148 		auio.uio_resid = MAXPATHLEN;
149 		if (error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred)) {
150 			if (ndp->ni_pathlen > 1)
151 				free(cp, M_NAMEI);
152 			break;
153 		}
154 		linklen = MAXPATHLEN - auio.uio_resid;
155 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
156 			if (ndp->ni_pathlen > 1)
157 				free(cp, M_NAMEI);
158 			error = ENAMETOOLONG;
159 			break;
160 		}
161 		if (ndp->ni_pathlen > 1) {
162 			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
163 			FREE(cnp->cn_pnbuf, M_NAMEI);
164 			cnp->cn_pnbuf = cp;
165 		} else
166 			cnp->cn_pnbuf[linklen] = '\0';
167 		ndp->ni_pathlen += linklen;
168 		vput(ndp->ni_vp);
169 		dp = ndp->ni_dvp;
170 	}
171 	FREE(cnp->cn_pnbuf, M_NAMEI);
172 	vrele(ndp->ni_dvp);
173 	vput(ndp->ni_vp);
174 	ndp->ni_vp = NULL;
175 	return (error);
176 }
177 
178 /*
179  * Search a pathname.
180  * This is a very central and rather complicated routine.
181  *
182  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
183  * The starting directory is taken from ni_startdir. The pathname is
184  * descended until done, or a symbolic link is encountered. The variable
185  * ni_more is clear if the path is completed; it is set to one if a
186  * symbolic link needing interpretation is encountered.
187  *
188  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
189  * whether the name is to be looked up, created, renamed, or deleted.
190  * When CREATE, RENAME, or DELETE is specified, information usable in
191  * creating, renaming, or deleting a directory entry may be calculated.
192  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
193  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
194  * returned unlocked. Otherwise the parent directory is not returned. If
195  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
196  * the target is returned locked, otherwise it is returned unlocked.
197  * When creating or renaming and LOCKPARENT is specified, the target may not
198  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
199  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
200  *
201  * Overall outline of lookup:
202  *
203  * dirloop:
204  *	identify next component of name at ndp->ni_ptr
205  *	handle degenerate case where name is null string
206  *	if .. and crossing mount points and on mounted filesys, find parent
207  *	call VOP_LOOKUP routine for next component name
208  *	    directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
209  *	    component vnode returned in ni_vp (if it exists), locked.
210  *	if result vnode is mounted on and crossing mount points,
211  *	    find mounted on vnode
212  *	if more components of name, do next level at dirloop
213  *	return the answer in ni_vp, locked if LOCKLEAF set
214  *	    if LOCKPARENT set, return locked parent in ni_dvp
215  *	    if WANTPARENT set, return unlocked parent in ni_dvp
216  */
217 int
218 lookup(ndp)
219 	register struct nameidata *ndp;
220 {
221 	USES_VOP_LOCK;
222 	USES_VOP_LOOKUP;
223 	USES_VOP_UNLOCK;
224 	register char *cp;		/* pointer into pathname argument */
225 	register struct vnode *dp = 0;	/* the directory we are searching */
226 	struct vnode *tdp;		/* saved dp */
227 	struct mount *mp;		/* mount table entry */
228 	int docache;			/* == 0 do not cache last component */
229 	int wantparent;			/* 1 => wantparent or lockparent flag */
230 	int rdonly;			/* lookup read-only flag bit */
231 	int error = 0;
232 	struct componentname *cnp = &ndp->ni_cnd;
233 
234 	/*
235 	 * Setup: break out flag bits into variables.
236 	 */
237 	wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT);
238 	docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
239 	if (cnp->cn_nameiop == DELETE ||
240 	    (wantparent && cnp->cn_nameiop != CREATE))
241 		docache = 0;
242 	rdonly = cnp->cn_flags & RDONLY;
243 	ndp->ni_dvp = NULL;
244 	cnp->cn_flags &= ~ISSYMLINK;
245 	dp = ndp->ni_startdir;
246 	ndp->ni_startdir = NULLVP;
247 	VOP_LOCK(dp);
248 
249 dirloop:
250 	/*
251 	 * Search a new directory.
252 	 *
253 	 * The cn_hash value is for use by vfs_cache.
254 	 * The last component of the filename is left accessible via
255 	 * cnp->cn_nameptr for callers that need the name. Callers needing
256 	 * the name set the SAVENAME flag. When done, they assume
257 	 * responsibility for freeing the pathname buffer.
258 	 */
259 	cnp->cn_hash = 0;
260 	for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
261 		cnp->cn_hash += (unsigned char)*cp;
262 	cnp->cn_namelen = cp - cnp->cn_nameptr;
263 	if (cnp->cn_namelen >= NAME_MAX) {
264 		error = ENAMETOOLONG;
265 		goto bad;
266 	}
267 #ifdef NAMEI_DIAGNOSTIC
268 	{ char c = *cp;
269 	*cp = '\0';
270 	printf("{%s}: ", cnp->cn_nameptr);
271 	*cp = c; }
272 #endif
273 	ndp->ni_pathlen -= cnp->cn_namelen;
274 	ndp->ni_next = cp;
275 	cnp->cn_flags |= MAKEENTRY;
276 	if (*cp == '\0' && docache == 0)
277 		cnp->cn_flags &= ~MAKEENTRY;
278 	if (cnp->cn_namelen == 2 &&
279 			cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
280 		cnp->cn_flags |= ISDOTDOT;
281 	else cnp->cn_flags &= ~ISDOTDOT;
282 	if (*ndp->ni_next == 0)
283 		cnp->cn_flags |= ISLASTCN;
284 	else cnp->cn_flags &= ~ISLASTCN;
285 
286 
287 	/*
288 	 * Check for degenerate name (e.g. / or "")
289 	 * which is a way of talking about a directory,
290 	 * e.g. like "/." or ".".
291 	 */
292 	if (cnp->cn_nameptr[0] == '\0') {
293 		if (cnp->cn_nameiop != LOOKUP || wantparent) {
294 			error = EISDIR;
295 			goto bad;
296 		}
297 		if (dp->v_type != VDIR) {
298 			error = ENOTDIR;
299 			goto bad;
300 		}
301 		if (!(cnp->cn_flags & LOCKLEAF))
302 			VOP_UNLOCK(dp);
303 		ndp->ni_vp = dp;
304 		if (cnp->cn_flags & SAVESTART)
305 			panic("lookup: SAVESTART");
306 		return (0);
307 	}
308 
309 	/*
310 	 * Handle "..": two special cases.
311 	 * 1. If at root directory (e.g. after chroot)
312 	 *    then ignore it so can't get out.
313 	 * 2. If this vnode is the root of a mounted
314 	 *    filesystem, then replace it with the
315 	 *    vnode which was mounted on so we take the
316 	 *    .. in the other file system.
317 	 */
318 	if (cnp->cn_flags & ISDOTDOT) {
319 		for (;;) {
320 			if (dp == ndp->ni_rootdir) {
321 				ndp->ni_dvp = dp;
322 				ndp->ni_vp = dp;
323 				VREF(dp);
324 				goto nextname;
325 			}
326 			if ((dp->v_flag & VROOT) == 0 ||
327 			    (cnp->cn_flags & NOCROSSMOUNT))
328 				break;
329 			tdp = dp;
330 			dp = dp->v_mount->mnt_vnodecovered;
331 			vput(tdp);
332 			VREF(dp);
333 			VOP_LOCK(dp);
334 		}
335 	}
336 
337 	/*
338 	 * We now have a segment name to search for, and a directory to search.
339 	 */
340 	ndp->ni_dvp = dp;
341 	if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) {
342 #ifdef DIAGNOSTIC
343 		if (ndp->ni_vp != NULL)
344 			panic("leaf should be empty");
345 #endif
346 #ifdef NAMEI_DIAGNOSTIC
347 		printf("not found\n");
348 #endif
349 		if (error != EJUSTRETURN)
350 			goto bad;
351 		/*
352 		 * If creating and at end of pathname, then can consider
353 		 * allowing file to be created.
354 		 */
355 		if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) {
356 			error = EROFS;
357 			goto bad;
358 		}
359 		/*
360 		 * We return with ni_vp NULL to indicate that the entry
361 		 * doesn't currently exist, leaving a pointer to the
362 		 * (possibly locked) directory inode in ndp->ni_dvp.
363 		 */
364 		if (cnp->cn_flags & SAVESTART) {
365 			ndp->ni_startdir = ndp->ni_dvp;
366 			VREF(ndp->ni_startdir);
367 		}
368 		return (0);
369 	}
370 #ifdef NAMEI_DIAGNOSTIC
371 	printf("found\n");
372 #endif
373 
374 	dp = ndp->ni_vp;
375 	/*
376 	 * Check for symbolic link
377 	 */
378 	if ((dp->v_type == VLNK) &&
379 	    ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) {
380 		cnp->cn_flags |= ISSYMLINK;
381 		return (0);
382 	}
383 
384 	/*
385 	 * Check to see if the vnode has been mounted on;
386 	 * if so find the root of the mounted file system.
387 	 */
388 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
389 	       (cnp->cn_flags & NOCROSSMOUNT) == 0) {
390 		if (mp->mnt_flag & MNT_MLOCK) {
391 			mp->mnt_flag |= MNT_MWAIT;
392 			sleep((caddr_t)mp, PVFS);
393 			continue;
394 		}
395 		if (error = VFS_ROOT(dp->v_mountedhere, &tdp))
396 			goto bad2;
397 		vput(dp);
398 		ndp->ni_vp = dp = tdp;
399 	}
400 
401 nextname:
402 	/*
403 	 * Not a symbolic link.  If more pathname,
404 	 * continue at next component, else return.
405 	 */
406 	if (*ndp->ni_next == '/') {
407 		cnp->cn_nameptr = ndp->ni_next;
408 		while (*cnp->cn_nameptr == '/') {
409 			cnp->cn_nameptr++;
410 			ndp->ni_pathlen--;
411 		}
412 		vrele(ndp->ni_dvp);
413 		goto dirloop;
414 	}
415 	/*
416 	 * Check for read-only file systems.
417 	 */
418 	if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
419 		/*
420 		 * Disallow directory write attempts on read-only
421 		 * file systems.
422 		 */
423 		if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
424 		    (wantparent &&
425 		     (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) {
426 			error = EROFS;
427 			goto bad2;
428 		}
429 	}
430 	if (cnp->cn_flags & SAVESTART) {
431 		ndp->ni_startdir = ndp->ni_dvp;
432 		VREF(ndp->ni_startdir);
433 	}
434 	if (!wantparent)
435 		vrele(ndp->ni_dvp);
436 	if ((cnp->cn_flags & LOCKLEAF) == 0)
437 		VOP_UNLOCK(dp);
438 	return (0);
439 
440 bad2:
441 	if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0')
442 		VOP_UNLOCK(ndp->ni_dvp);
443 	vrele(ndp->ni_dvp);
444 bad:
445 	vput(dp);
446 	ndp->ni_vp = NULL;
447 	return (error);
448 }
449 
450 
451