xref: /csrg-svn/sys/kern/vfs_lookup.c (revision 47540)
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.27 (Berkeley) 03/17/91
8  */
9 
10 #include "param.h"
11 #include "time.h"
12 #include "namei.h"
13 #include "vnode.h"
14 #include "mount.h"
15 #include "errno.h"
16 #include "malloc.h"
17 #include "filedesc.h"
18 #include "user.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  * This is a very central and rather complicated routine.
28  *
29  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
30  * whether the name is to be looked up, created, renamed, or deleted.
31  * When CREATE, RENAME, or DELETE is specified, information usable in
32  * creating, renaming, or deleting a directory entry may be calculated.
33  * If flag has LOCKPARENT or'ed into it and the target of the pathname
34  * exists, namei returns both the target and its parent directory locked.
35  * When creating or renaming and LOCKPARENT is specified, the target may not
36  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
37  *
38  * The FOLLOW flag is set when symbolic links are to be followed
39  * when they occur at the end of the name translation process.
40  * Symbolic links are always followed for all other pathname
41  * components other than the last.
42  *
43  * The segflg defines whether the name is to be copied from user
44  * space or kernel space.
45  *
46  * Overall outline of namei:
47  *
48  *	copy in name
49  *	get starting directory
50  * dirloop:
51  *	copy next component of name to ndp->ni_dent
52  *	handle degenerate case where name is null string
53  *	if .. and on mounted filesys, find parent
54  *	call lookup routine for next component name
55  *	  directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
56  *	  component vnode returned in ni_vp (if it exists), locked.
57  *	if symbolic link, massage name in buffer and continue at dirloop
58  *	if result inode is mounted on, find mounted on vnode
59  *	if more components of name, do next level at dirloop
60  *	return the answer in ni_vp as locked vnode;
61  *	  if LOCKPARENT set, return locked parent in ni_dvp
62  *
63  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
64  */
65 namei(ndp, p)
66 	register struct nameidata *ndp;
67 	struct proc *p;
68 {
69 	register struct filedesc *fdp;	/* pointer to file descriptor state */
70 	register char *cp;		/* pointer into pathname argument */
71 	register struct vnode *dp = 0;	/* the directory we are searching */
72 	register int i;		   	/* Temp counter */
73 	struct vnode *tdp;		/* saved dp */
74 	struct mount *mp;		/* mount table entry */
75 	int docache;			/* == 0 do not cache last component */
76 	int flag;			/* LOOKUP, CREATE, RENAME or DELETE */
77 	int wantparent;			/* 1 => wantparent or lockparent flag */
78 	int lockparent;			/* 1 => lockparent flag */
79 	int getbuf;			/* 1 => Malloc a pathname buffer */
80 	int rdonly;			/* mounted read-only flag bit(s) */
81 	int error = 0;
82 
83 	/*
84 	 * Setup: break out flag bits into variables.
85 	 */
86 	ndp->ni_cred = p->p_ucred;
87 	fdp = p->p_fd;
88 	ndp->ni_dvp = NULL;
89 	flag = ndp->ni_nameiop & OPMASK;
90 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
91 	lockparent = ndp->ni_nameiop & LOCKPARENT;
92 	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
93 	getbuf = (ndp->ni_nameiop & HASBUF) ^ HASBUF;
94 	if (flag == DELETE || (wantparent && flag != CREATE))
95 		docache = 0;
96 	rdonly = MNT_RDONLY;
97 	if (ndp->ni_nameiop & REMOTE)
98 		rdonly |= MNT_EXRDONLY;
99 	/*
100 	 * Get a buffer for the name to be translated, and copy the
101 	 * name into the buffer.
102 	 */
103 	if (getbuf) {
104 		MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
105 		if (ndp->ni_segflg == UIO_SYSSPACE)
106 			error = copystr(ndp->ni_dirp, ndp->ni_pnbuf,
107 				    MAXPATHLEN, &ndp->ni_pathlen);
108 		else
109 			error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf,
110 				    MAXPATHLEN, &ndp->ni_pathlen);
111 		if (error) {
112 			free(ndp->ni_pnbuf, M_NAMEI);
113 			ndp->ni_vp = NULL;
114 			return (error);
115 		}
116 	}
117 	ndp->ni_ptr = ndp->ni_pnbuf;
118 	ndp->ni_loopcnt = 0;
119 #ifdef KTRACE
120 	if (KTRPOINT(p, KTR_NAMEI))
121 		ktrnamei(p->p_tracep, ndp->ni_pnbuf);
122 #endif
123 
124 	/*
125 	 * Get starting point for the translation.
126 	 */
127 	if (ndp->ni_nameiop & STARTDIR)
128 		dp = ndp->ni_startdir;
129 	else
130 		dp = fdp->fd_cdir;
131 	VREF(dp);
132 start:
133 	/*
134 	 * Get starting directory.
135 	 * Done at start of translation and after symbolic link.
136 	 */
137 	if (*ndp->ni_ptr == '/') {
138 		if (ndp->ni_nameiop & STARTDIR)
139 			panic("namei: illegal path");
140 		vrele(dp);
141 		while (*ndp->ni_ptr == '/') {
142 			ndp->ni_ptr++;
143 			ndp->ni_pathlen--;
144 		}
145 		if ((dp = fdp->fd_rdir) == NULL)
146 			dp = rootdir;
147 		VREF(dp);
148 	}
149 	VOP_LOCK(dp);
150 	ndp->ni_endoff = 0;
151 
152 	/*
153 	 * We come to dirloop to search a new directory.
154 	 */
155 dirloop:
156 	/*
157 	 * Copy next component of name to ndp->ni_dent.
158 	 * XXX kern_exec looks at d_name
159 	 * ??? The ni_hash value may be useful for vfs_cache
160 	 * XXX There must be the last component of the filename left
161 	 * somewhere accessible via. ndp for NFS (and any other stateless file
162 	 * systems) in case they are doing a CREATE. The "Towards a..." noted
163 	 * that ni_ptr would be left pointing to the last component, but since
164 	 * the ni_pnbuf gets free'd, that is not a good idea.
165 	 */
166 	if (getbuf) {
167 		ndp->ni_hash = 0;
168 		for (cp = ndp->ni_ptr, i = 0; *cp != 0 && *cp != '/'; cp++) {
169 			if (i >= MAXNAMLEN) {
170 				error = ENAMETOOLONG;
171 				goto bad;
172 			}
173 			if (*cp & 0200)
174 				if ((*cp&0377) == ('/'|0200) ||
175 				    flag != DELETE) {
176 					error = EINVAL;
177 					goto bad;
178 				}
179 			ndp->ni_dent.d_name[i++] = *cp;
180 			ndp->ni_hash += (unsigned char)*cp * i;
181 		}
182 		ndp->ni_namelen = i;
183 		ndp->ni_dent.d_namlen = i;
184 		ndp->ni_dent.d_name[i] = '\0';
185 		ndp->ni_pathlen -= i;
186 		ndp->ni_next = cp;
187 #ifdef NAMEI_DIAGNOSTIC
188 		printf("{%s}: ", ndp->ni_dent.d_name);
189 #endif
190 	}
191 	cp = ndp->ni_next;
192 	ndp->ni_makeentry = 1;
193 	if (*cp == '\0' && docache == 0)
194 		ndp->ni_makeentry = 0;
195 	ndp->ni_isdotdot = (ndp->ni_namelen == 2 &&
196 		ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.');
197 
198 	/*
199 	 * Check for degenerate name (e.g. / or "")
200 	 * which is a way of talking about a directory,
201 	 * e.g. like "/." or ".".
202 	 */
203 	if (ndp->ni_ptr[0] == '\0') {
204 		if (flag != LOOKUP || wantparent) {
205 			error = EISDIR;
206 			goto bad;
207 		}
208 		if (getbuf)
209 			free(ndp->ni_pnbuf, M_NAMEI);
210 		if (!(ndp->ni_nameiop & LOCKLEAF))
211 			VOP_UNLOCK(dp);
212 		ndp->ni_vp = dp;
213 		return (0);
214 	}
215 
216 	/*
217 	 * Handle "..": two special cases.
218 	 * 1. If at root directory (e.g. after chroot)
219 	 *    then ignore it so can't get out.
220 	 * 2. If this vnode is the root of a mounted
221 	 *    file system, then replace it with the
222 	 *    vnode which was mounted on so we take the
223 	 *    .. in the other file system.
224 	 */
225 	if (ndp->ni_isdotdot) {
226 		for (;;) {
227 			if (dp == fdp->fd_rdir || dp == rootdir) {
228 				ndp->ni_dvp = dp;
229 				ndp->ni_vp = dp;
230 				VREF(dp);
231 				goto nextname;
232 			}
233 			if ((dp->v_flag & VROOT) == 0 ||
234 				(ndp->ni_nameiop & NOCROSSMOUNT))
235 				break;
236 			tdp = dp;
237 			dp = dp->v_mount->mnt_vnodecovered;
238 			vput(tdp);
239 			VREF(dp);
240 			VOP_LOCK(dp);
241 		}
242 	}
243 
244 	/*
245 	 * We now have a segment name to search for, and a directory to search.
246 	 */
247 	if (error = VOP_LOOKUP(dp, ndp)) {
248 		if (ndp->ni_vp != NULL)
249 			panic("leaf should be empty");
250 #ifdef NAMEI_DIAGNOSTIC
251 		printf("not found\n");
252 #endif
253 		if (flag == LOOKUP || flag == DELETE ||
254 		    error != ENOENT || *cp != 0)
255 			goto bad;
256 		/*
257 		 * If creating and at end of pathname, then can consider
258 		 * allowing file to be created.
259 		 */
260 		if (ndp->ni_dvp->v_mount->mnt_flag & rdonly) {
261 			error = EROFS;
262 			goto bad;
263 		}
264 		/*
265 		 * We return with ni_vp NULL to indicate that the entry
266 		 * doesn't currently exist, leaving a pointer to the
267 		 * (possibly locked) directory inode in ndp->ni_dvp.
268 		 */
269 		if (getbuf)
270 			FREE(ndp->ni_pnbuf, M_NAMEI);
271 		return (0);	/* should this be ENOENT? */
272 	}
273 #ifdef NAMEI_DIAGNOSTIC
274 	printf("found\n");
275 #endif
276 
277 	/*
278 	 * Check for symbolic link
279 	 */
280 	dp = ndp->ni_vp;
281 	if ((dp->v_type == VLNK) &&
282 	    ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) {
283 		struct iovec aiov;
284 		struct uio auio;
285 		int linklen;
286 
287 		if (!getbuf)
288 			panic("namei: unexpected symlink");
289 		if (++ndp->ni_loopcnt > MAXSYMLINKS) {
290 			error = ELOOP;
291 			goto bad2;
292 		}
293 		if (ndp->ni_pathlen > 1)
294 			MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
295 		else
296 			cp = ndp->ni_pnbuf;
297 		aiov.iov_base = cp;
298 		aiov.iov_len = MAXPATHLEN;
299 		auio.uio_iov = &aiov;
300 		auio.uio_iovcnt = 1;
301 		auio.uio_offset = 0;
302 		auio.uio_rw = UIO_READ;
303 		auio.uio_segflg = UIO_SYSSPACE;
304 		auio.uio_resid = MAXPATHLEN;
305 		if (error = VOP_READLINK(dp, &auio, p->p_ucred)) {
306 			if (ndp->ni_pathlen > 1)
307 				free(cp, M_NAMEI);
308 			goto bad2;
309 		}
310 		linklen = MAXPATHLEN - auio.uio_resid;
311 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
312 			if (ndp->ni_pathlen > 1)
313 				free(cp, M_NAMEI);
314 			error = ENAMETOOLONG;
315 			goto bad2;
316 		}
317 		if (ndp->ni_pathlen > 1) {
318 			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
319 			FREE(ndp->ni_pnbuf, M_NAMEI);
320 			ndp->ni_pnbuf = cp;
321 		} else
322 			ndp->ni_pnbuf[linklen] = '\0';
323 		ndp->ni_ptr = cp;
324 		vput(dp);
325 		dp = ndp->ni_dvp;
326 		if (lockparent && ndp->ni_pathlen == 1)
327 			VOP_UNLOCK(dp);
328 		ndp->ni_pathlen += linklen;
329 		goto start;
330 	}
331 
332 	/*
333 	 * Check to see if the vnode has been mounted on;
334 	 * if so find the root of the mounted file system.
335 	 */
336 mntloop:
337 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
338 	       (ndp->ni_nameiop & NOCROSSMOUNT) == 0) {
339 		while(mp->mnt_flag & MNT_MLOCK) {
340 			mp->mnt_flag |= MNT_MWAIT;
341 			sleep((caddr_t)mp, PVFS);
342 			goto mntloop;
343 		}
344 		error = VFS_ROOT(dp->v_mountedhere, &tdp);
345 		if (error)
346 			goto bad2;
347 		vput(dp);
348 		ndp->ni_vp = dp = tdp;
349 	}
350 
351 nextname:
352 	/*
353 	 * Not a symbolic link.  If more pathname,
354 	 * continue at next component, else return.
355 	 */
356 	ndp->ni_ptr = ndp->ni_next;
357 	if (*ndp->ni_ptr == '/') {
358 		while (*ndp->ni_ptr == '/') {
359 			ndp->ni_ptr++;
360 			ndp->ni_pathlen--;
361 		}
362 		vrele(ndp->ni_dvp);
363 		goto dirloop;
364 	}
365 	/*
366 	 * Check for read-only file systems.
367 	 */
368 	if (flag == DELETE || flag == RENAME) {
369 		/*
370 		 * Disallow directory write attempts on read-only
371 		 * file systems.
372 		 */
373 		if ((dp->v_mount->mnt_flag & rdonly) ||
374 		    (wantparent && (ndp->ni_dvp->v_mount->mnt_flag & rdonly))) {
375 			error = EROFS;
376 			goto bad2;
377 		}
378 	}
379 	if (!wantparent)
380 		vrele(ndp->ni_dvp);
381 	if ((ndp->ni_nameiop & LOCKLEAF) == 0)
382 		VOP_UNLOCK(dp);
383 	if (getbuf)
384 		FREE(ndp->ni_pnbuf, M_NAMEI);
385 	return (0);
386 
387 bad2:
388 	if (lockparent && *ndp->ni_next == '\0')
389 		VOP_UNLOCK(ndp->ni_dvp);
390 	vrele(ndp->ni_dvp);
391 bad:
392 	vput(dp);
393 	ndp->ni_vp = NULL;
394 	if (getbuf)
395 		FREE(ndp->ni_pnbuf, M_NAMEI);
396 	return (error);
397 }
398