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