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