Merge from vendor branch TCPDUMP:
[dragonfly.git] / sys / kern / vfs_lookup.c
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *      @(#)vfs_lookup.c        8.4 (Berkeley) 2/16/94
39  * $FreeBSD: src/sys/kern/vfs_lookup.c,v 1.38.2.3 2001/08/31 19:36:49 dillon Exp $
40  * $DragonFly: src/sys/kern/vfs_lookup.c,v 1.11 2004/04/24 04:32:03 drhodus Exp $
41  */
42
43 #include "opt_ktrace.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/vnode.h>
49 #include <sys/mount.h>
50 #include <sys/filedesc.h>
51 #include <sys/proc.h>
52 #include <sys/namei.h>
53 #include <sys/sysctl.h>
54
55 #ifdef KTRACE
56 #include <sys/ktrace.h>
57 #endif
58
59 #include <vm/vm_zone.h>
60
61 static int varsym_enable = 0;
62 SYSCTL_INT(_vfs, OID_AUTO, varsym_enable, CTLFLAG_RW, &varsym_enable, 0,
63             "Enable Variant Symlinks");
64
65 /*
66  * Convert a pathname into a pointer to a locked inode.
67  *
68  * The CNP_FOLLOW flag is set when symbolic links are to be followed
69  * when they occur at the end of the name translation process.
70  * Symbolic links are always followed for all other pathname
71  * components other than the last.
72  *
73  * The segflg defines whether the name is to be copied from user
74  * space or kernel space.
75  *
76  * Overall outline of namei:
77  *
78  *      copy in name
79  *      get starting directory
80  *      while (!done && !error) {
81  *              call lookup to search path.
82  *              if symbolic link, massage name in buffer and continue
83  *      }
84  */
85 int
86 namei(struct nameidata *ndp)
87 {
88         struct filedesc *fdp;   /* pointer to file descriptor state */
89         char *cp;               /* pointer into pathname argument */
90         struct vnode *dp;       /* the directory we are searching */
91         struct iovec aiov;              /* uio for reading symbolic links */
92         struct uio auio;
93         int error, linklen;
94         struct componentname *cnp = &ndp->ni_cnd;
95         struct proc *p;
96
97         KKASSERT(ndp->ni_cnd.cn_td != NULL);
98         p = cnp->cn_td->td_proc;
99         KKASSERT(p != NULL);
100         KASSERT(cnp->cn_cred, ("namei: bad cred/proc"));
101         KKASSERT(cnp->cn_cred == p->p_ucred); /* YYY */
102         KASSERT((cnp->cn_nameiop & (~NAMEI_OPMASK)) == 0,
103             ("namei: nameiop contaminated with flags"));
104         KASSERT((cnp->cn_flags & NAMEI_OPMASK) == 0,
105             ("namei: flags contaminated with nameiops"));
106         fdp = p->p_fd;
107
108         /*
109          * Get a buffer for the name to be translated, and copy the
110          * name into the buffer.
111          */
112         if ((cnp->cn_flags & CNP_HASBUF) == 0)
113                 cnp->cn_pnbuf = zalloc(namei_zone);
114         if (ndp->ni_segflg == UIO_SYSSPACE)
115                 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
116                             MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
117         else
118                 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
119                             MAXPATHLEN, (size_t *)&ndp->ni_pathlen);
120
121         /*
122          * Don't allow empty pathnames.
123          */
124         if (!error && *cnp->cn_pnbuf == '\0')
125                 error = ENOENT;
126
127         if (error) {
128                 zfree(namei_zone, cnp->cn_pnbuf);
129                 ndp->ni_vp = NULL;
130                 return (error);
131         }
132         ndp->ni_loopcnt = 0;
133 #ifdef KTRACE
134         if (KTRPOINT(cnp->cn_td, KTR_NAMEI))
135                 ktrnamei(cnp->cn_td->td_proc->p_tracep, cnp->cn_pnbuf);
136 #endif
137
138         /*
139          * Get starting point for the translation.
140          */
141         ndp->ni_rootdir = fdp->fd_rdir;
142         ndp->ni_topdir = fdp->fd_jdir;
143
144         dp = fdp->fd_cdir;
145         vref(dp);
146         for (;;) {
147                 /*
148                  * Check if root directory should replace current directory.
149                  * Done at start of translation and after symbolic link.
150                  */
151                 cnp->cn_nameptr = cnp->cn_pnbuf;
152                 if (*(cnp->cn_nameptr) == '/') {
153                         vrele(dp);
154                         while (*(cnp->cn_nameptr) == '/') {
155                                 cnp->cn_nameptr++;
156                                 ndp->ni_pathlen--;
157                         }
158                         dp = ndp->ni_rootdir;
159                         vref(dp);
160                 }
161                 ndp->ni_startdir = dp;
162                 error = lookup(ndp);
163                 if (error) {
164                         zfree(namei_zone, cnp->cn_pnbuf);
165                         return (error);
166                 }
167                 /*
168                  * Check for symbolic link
169                  */
170                 if ((cnp->cn_flags & CNP_ISSYMLINK) == 0) {
171                         if ((cnp->cn_flags & (CNP_SAVENAME | CNP_SAVESTART)) == 0)
172                                 zfree(namei_zone, cnp->cn_pnbuf);
173                         else
174                                 cnp->cn_flags |= CNP_HASBUF;
175
176                         if (vn_canvmio(ndp->ni_vp) == TRUE &&
177                                 (cnp->cn_nameiop != NAMEI_DELETE) &&
178                                 ((cnp->cn_flags & (CNP_NOOBJ|CNP_LOCKLEAF)) ==
179                                  CNP_LOCKLEAF))
180                                 vfs_object_create(ndp->ni_vp, ndp->ni_cnd.cn_td);
181
182                         return (0);
183                 }
184                 if ((cnp->cn_flags & CNP_LOCKPARENT) && ndp->ni_pathlen == 1)
185                         VOP_UNLOCK(ndp->ni_dvp, NULL, 0, cnp->cn_td);
186                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
187                         error = ELOOP;
188                         break;
189                 }
190                 if (ndp->ni_pathlen > 1)
191                         cp = zalloc(namei_zone);
192                 else
193                         cp = cnp->cn_pnbuf;
194                 aiov.iov_base = cp;
195                 aiov.iov_len = MAXPATHLEN;
196                 auio.uio_iov = &aiov;
197                 auio.uio_iovcnt = 1;
198                 auio.uio_offset = 0;
199                 auio.uio_rw = UIO_READ;
200                 auio.uio_segflg = UIO_SYSSPACE;
201                 auio.uio_td = NULL;
202                 auio.uio_resid = MAXPATHLEN;
203                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
204                 if (error) {
205                         if (ndp->ni_pathlen > 1)
206                                 zfree(namei_zone, cp);
207                         break;
208                 }
209                 linklen = MAXPATHLEN - auio.uio_resid;
210                 if (linklen == 0) {
211                         if (ndp->ni_pathlen > 1)
212                                 zfree(namei_zone, cp);
213                         error = ENOENT;
214                         break;
215                 }
216                 if (varsym_enable) {
217                         linklen = varsymreplace(cp, linklen, MAXPATHLEN);
218                         if (linklen < 0) {
219                                 if (ndp->ni_pathlen > 1)
220                                         zfree(namei_zone, cp);
221                                 error = ENAMETOOLONG;
222                                 break;
223                         }
224                 }
225                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
226                         if (ndp->ni_pathlen > 1)
227                                 zfree(namei_zone, cp);
228                         error = ENAMETOOLONG;
229                         break;
230                 }
231                 if (ndp->ni_pathlen > 1) {
232                         bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
233                         zfree(namei_zone, cnp->cn_pnbuf);
234                         cnp->cn_pnbuf = cp;
235                 } else {
236                         cnp->cn_pnbuf[linklen] = '\0';
237                 }
238                 ndp->ni_pathlen += linklen;
239                 vput(ndp->ni_vp);
240                 dp = ndp->ni_dvp;
241         }
242         zfree(namei_zone, cnp->cn_pnbuf);
243         vrele(ndp->ni_dvp);
244         vput(ndp->ni_vp);
245         ndp->ni_vp = NULL;
246         return (error);
247 }
248
249 /*
250  * Search a pathname.
251  * This is a very central and rather complicated routine.
252  *
253  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
254  * The starting directory is taken from ni_startdir. The pathname is
255  * descended until done, or a symbolic link is encountered. The variable
256  * ni_more is clear if the path is completed; it is set to one if a
257  * symbolic link needing interpretation is encountered.
258  *
259  * The flag argument is NAMEI_LOOKUP, CREATE, RENAME, or DELETE depending on
260  * whether the name is to be looked up, created, renamed, or deleted.
261  * When CREATE, RENAME, or DELETE is specified, information usable in
262  * creating, renaming, or deleting a directory entry may be calculated.
263  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
264  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
265  * returned unlocked. Otherwise the parent directory is not returned. If
266  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
267  * the target is returned locked, otherwise it is returned unlocked.
268  * When creating or renaming and LOCKPARENT is specified, the target may not
269  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
270  *
271  * Overall outline of lookup:
272  *
273  * dirloop:
274  *      identify next component of name at ndp->ni_ptr
275  *      handle degenerate case where name is null string
276  *      if .. and crossing mount points and on mounted filesys, find parent
277  *      call VOP_LOOKUP routine for next component name
278  *          directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
279  *          component vnode returned in ni_vp (if it exists), locked.
280  *      if result vnode is mounted on and crossing mount points,
281  *          find mounted on vnode
282  *      if more components of name, do next level at dirloop
283  *      return the answer in ni_vp, locked if LOCKLEAF set
284  *          if LOCKPARENT set, return locked parent in ni_dvp
285  *          if WANTPARENT set, return unlocked parent in ni_dvp
286  */
287 int
288 lookup(struct nameidata *ndp)
289 {
290         char *cp;                       /* pointer into pathname argument */
291         struct vnode *dp = NULL;        /* the directory we are searching */
292         struct vnode *tdp;              /* saved dp */
293         struct mount *mp;               /* mount table entry */
294         int docache;                    /* == 0 do not cache last component */
295         int wantparent;                 /* 1 => wantparent or lockparent flag */
296         int rdonly;                     /* lookup read-only flag bit */
297         int trailing_slash;
298         int error = 0;
299         int dpunlocked = 0;             /* dp has already been unlocked */
300         struct componentname *cnp = &ndp->ni_cnd;
301         struct thread *td = cnp->cn_td;
302
303         /*
304          * Setup: break out flag bits into variables.
305          */
306         wantparent = cnp->cn_flags & (CNP_LOCKPARENT | CNP_WANTPARENT);
307         docache = (cnp->cn_flags & CNP_NOCACHE) ^ CNP_NOCACHE;
308         if (cnp->cn_nameiop == NAMEI_DELETE ||
309             (wantparent && cnp->cn_nameiop != NAMEI_CREATE &&
310              cnp->cn_nameiop != NAMEI_LOOKUP))
311                 docache = 0;
312         rdonly = cnp->cn_flags & CNP_RDONLY;
313         ndp->ni_dvp = NULL;
314         cnp->cn_flags &= ~CNP_ISSYMLINK;
315         dp = ndp->ni_startdir;
316         ndp->ni_startdir = NULLVP;
317         vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
318
319 dirloop:
320         /*
321          * Search a new directory.
322          *
323          * The last component of the filename is left accessible via
324          * cnp->cn_nameptr for callers that need the name. Callers needing
325          * the name set the CNP_SAVENAME flag. When done, they assume
326          * responsibility for freeing the pathname buffer.
327          */
328         cnp->cn_consume = 0;
329         for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
330                 continue;
331         cnp->cn_namelen = cp - cnp->cn_nameptr;
332         if (cnp->cn_namelen > NAME_MAX) {
333                 error = ENAMETOOLONG;
334                 goto bad;
335         }
336 #ifdef NAMEI_DIAGNOSTIC
337         { char c = *cp;
338         *cp = '\0';
339         printf("{%s}: ", cnp->cn_nameptr);
340         *cp = c; }
341 #endif
342         ndp->ni_pathlen -= cnp->cn_namelen;
343         ndp->ni_next = cp;
344
345         /*
346          * Replace multiple slashes by a single slash and trailing slashes
347          * by a null.  This must be done before VOP_LOOKUP() because some
348          * fs's don't know about trailing slashes.  Remember if there were
349          * trailing slashes to handle symlinks, existing non-directories
350          * and non-existing files that won't be directories specially later.
351          */
352         trailing_slash = 0;
353         while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
354                 cp++;
355                 ndp->ni_pathlen--;
356                 if (*cp == '\0') {
357                         trailing_slash = 1;
358                         *ndp->ni_next = '\0';   /* XXX for direnter() ... */
359                 }
360         }
361         ndp->ni_next = cp;
362
363         cnp->cn_flags |= CNP_MAKEENTRY;
364         if (*cp == '\0' && docache == 0)
365                 cnp->cn_flags &= ~CNP_MAKEENTRY;
366         if (cnp->cn_namelen == 2 &&
367             cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
368                 cnp->cn_flags |= CNP_ISDOTDOT;
369         else
370                 cnp->cn_flags &= ~CNP_ISDOTDOT;
371         if (*ndp->ni_next == 0)
372                 cnp->cn_flags |= CNP_ISLASTCN;
373         else
374                 cnp->cn_flags &= ~CNP_ISLASTCN;
375
376
377         /*
378          * Check for degenerate name (e.g. / or "")
379          * which is a way of talking about a directory,
380          * e.g. like "/." or ".".
381          */
382         if (cnp->cn_nameptr[0] == '\0') {
383                 if (dp->v_type != VDIR) {
384                         error = ENOTDIR;
385                         goto bad;
386                 }
387                 if (cnp->cn_nameiop != NAMEI_LOOKUP) {
388                         error = EISDIR;
389                         goto bad;
390                 }
391                 if (wantparent) {
392                         ndp->ni_dvp = dp;
393                         vref(dp);
394                 }
395                 ndp->ni_vp = dp;
396                 if (!(cnp->cn_flags & (CNP_LOCKPARENT | CNP_LOCKLEAF)))
397                         VOP_UNLOCK(dp, NULL, 0, cnp->cn_td);
398                 /* XXX This should probably move to the top of function. */
399                 if (cnp->cn_flags & CNP_SAVESTART)
400                         panic("lookup: CNP_SAVESTART");
401                 return (0);
402         }
403
404         /*
405          * Handle "..": two special cases.
406          * 1. If at root directory (e.g. after chroot)
407          *    or at absolute root directory
408          *    then ignore it so can't get out.
409          * 2. If this vnode is the root of a mounted
410          *    filesystem, then replace it with the
411          *    vnode which was mounted on so we take the
412          *    .. in the other file system.
413          * 3. If the vnode is the top directory of
414          *    the jail or chroot, don't let them out.
415          */
416         if (cnp->cn_flags & CNP_ISDOTDOT) {
417                 for (;;) {
418                         if (dp == ndp->ni_rootdir || 
419                             dp == ndp->ni_topdir || 
420                             dp == rootvnode) {
421                                 ndp->ni_dvp = dp;
422                                 ndp->ni_vp = dp;
423                                 vref(dp);
424                                 goto nextname;
425                         }
426                         if ((dp->v_flag & VROOT) == 0 ||
427                             (cnp->cn_flags & CNP_NOCROSSMOUNT))
428                                 break;
429                         if (dp->v_mount == NULL) {      /* forced unmount */
430                                 error = EBADF;
431                                 goto bad;
432                         }
433                         tdp = dp;
434                         dp = dp->v_mount->mnt_vnodecovered;
435                         vput(tdp);
436                         vref(dp);
437                         vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
438                 }
439         }
440
441         /*
442          * We now have a segment name to search for, and a directory to search.
443          */
444 unionlookup:
445         ndp->ni_dvp = dp;
446         ndp->ni_vp = NULL;
447         cnp->cn_flags &= ~CNP_PDIRUNLOCK;
448         ASSERT_VOP_LOCKED(dp, "lookup");
449         if ((error = VOP_LOOKUP(dp, NCPNULL, &ndp->ni_vp, NCPPNULL, cnp)) != 0) {
450                 KASSERT(ndp->ni_vp == NULL, ("leaf should be empty"));
451 #ifdef NAMEI_DIAGNOSTIC
452                 printf("not found\n");
453 #endif
454                 if ((error == ENOENT) &&
455                     (dp->v_flag & VROOT) && (dp->v_mount != NULL) &&
456                     (dp->v_mount->mnt_flag & MNT_UNION)) {
457                         tdp = dp;
458                         dp = dp->v_mount->mnt_vnodecovered;
459                         if (cnp->cn_flags & CNP_PDIRUNLOCK)
460                                 vrele(tdp);
461                         else
462                                 vput(tdp);
463                         vref(dp);
464                         vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
465                         goto unionlookup;
466                 }
467
468                 if (error != EJUSTRETURN)
469                         goto bad;
470                 /*
471                  * If creating and at end of pathname, then can consider
472                  * allowing file to be created.
473                  */
474                 if (rdonly) {
475                         error = EROFS;
476                         goto bad;
477                 }
478                 if (*cp == '\0' && trailing_slash &&
479                      !(cnp->cn_flags & CNP_WILLBEDIR)) {
480                         error = ENOENT;
481                         goto bad;
482                 }
483                 /*
484                  * We return with ni_vp NULL to indicate that the entry
485                  * doesn't currently exist, leaving a pointer to the
486                  * (possibly locked) directory inode in ndp->ni_dvp.
487                  */
488                 if (cnp->cn_flags & CNP_SAVESTART) {
489                         ndp->ni_startdir = ndp->ni_dvp;
490                         vref(ndp->ni_startdir);
491                 }
492                 return (0);
493         }
494 #ifdef NAMEI_DIAGNOSTIC
495         printf("found\n");
496 #endif
497
498         ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup");
499
500         /*
501          * Take into account any additional components consumed by
502          * the underlying filesystem.
503          */
504         if (cnp->cn_consume > 0) {
505                 cnp->cn_nameptr += cnp->cn_consume;
506                 ndp->ni_next += cnp->cn_consume;
507                 ndp->ni_pathlen -= cnp->cn_consume;
508                 cnp->cn_consume = 0;
509         }
510
511         dp = ndp->ni_vp;
512
513         /*
514          * Check to see if the vnode has been mounted on;
515          * if so find the root of the mounted file system.
516          */
517         while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
518                (cnp->cn_flags & CNP_NOCROSSMOUNT) == 0) {
519                 if (vfs_busy(mp, 0, NULL, td))
520                         continue;
521                 VOP_UNLOCK(dp, NULL, 0, td);
522                 error = VFS_ROOT(mp, &tdp);
523                 vfs_unbusy(mp, td);
524                 if (error) {
525                         dpunlocked = 1;
526                         goto bad2;
527                 }
528                 cache_mount(dp, tdp);
529                 vrele(dp);
530                 ndp->ni_vp = dp = tdp;
531         }
532
533         /*
534          * Check for symbolic link
535          */
536         if ((dp->v_type == VLNK) &&
537             ((cnp->cn_flags & CNP_FOLLOW) || trailing_slash ||
538              *ndp->ni_next == '/')) {
539                 cnp->cn_flags |= CNP_ISSYMLINK;
540                 if (dp->v_mount == NULL) {
541                         /* We can't know whether the directory was mounted with
542                          * NOSYMFOLLOW, so we can't follow safely. */
543                         error = EBADF;
544                         goto bad2;
545                 }
546                 if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) {
547                         error = EACCES;
548                         goto bad2;
549                 }
550                 return (0);
551         }
552
553         /*
554          * Check for bogus trailing slashes.
555          */
556         if (trailing_slash && dp->v_type != VDIR) {
557                 error = ENOTDIR;
558                 goto bad2;
559         }
560
561 nextname:
562         /*
563          * Not a symbolic link.  If more pathname,
564          * continue at next component, else return.
565          */
566         if (*ndp->ni_next == '/') {
567                 cnp->cn_nameptr = ndp->ni_next;
568                 while (*cnp->cn_nameptr == '/') {
569                         cnp->cn_nameptr++;
570                         ndp->ni_pathlen--;
571                 }
572                 if (ndp->ni_dvp != ndp->ni_vp)
573                         ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup");
574                 vrele(ndp->ni_dvp);
575                 goto dirloop;
576         }
577         /*
578          * Disallow directory write attempts on read-only file systems.
579          */
580         if (rdonly &&
581             (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) {
582                 error = EROFS;
583                 goto bad2;
584         }
585         if (cnp->cn_flags & CNP_SAVESTART) {
586                 ndp->ni_startdir = ndp->ni_dvp;
587                 vref(ndp->ni_startdir);
588         }
589         if (!wantparent)
590                 vrele(ndp->ni_dvp);
591
592         if ((cnp->cn_flags & CNP_LOCKLEAF) == 0)
593                 VOP_UNLOCK(dp, NULL, 0, td);
594         return (0);
595
596 bad2:
597         if ((cnp->cn_flags & (CNP_LOCKPARENT | CNP_PDIRUNLOCK)) == CNP_LOCKPARENT &&
598             *ndp->ni_next == '\0')
599                 VOP_UNLOCK(ndp->ni_dvp, NULL, 0, td);
600         vrele(ndp->ni_dvp);
601 bad:
602         if (dpunlocked)
603                 vrele(dp);
604         else
605                 vput(dp);
606         ndp->ni_vp = NULL;
607         return (error);
608 }
609
610 /*
611  * relookup - lookup a path name component
612  *    Used by lookup to re-aquire things.
613  */
614 int
615 relookup(dvp, vpp, cnp)
616         struct vnode *dvp, **vpp;
617         struct componentname *cnp;
618 {
619         struct thread *td = cnp->cn_td;
620         struct vnode *dp = 0;           /* the directory we are searching */
621         int docache;                    /* == 0 do not cache last component */
622         int wantparent;                 /* 1 => wantparent or lockparent flag */
623         int rdonly;                     /* lookup read-only flag bit */
624         int error = 0;
625 #ifdef NAMEI_DIAGNOSTIC
626         int newhash;                    /* DEBUG: check name hash */
627         char *cp;                       /* DEBUG: check name ptr/len */
628 #endif
629
630         /*
631          * Setup: break out flag bits into variables.
632          */
633         wantparent = cnp->cn_flags & (CNP_LOCKPARENT|CNP_WANTPARENT);
634         docache = (cnp->cn_flags & CNP_NOCACHE) ^ CNP_NOCACHE;
635         if (cnp->cn_nameiop == NAMEI_DELETE ||
636             (wantparent && cnp->cn_nameiop != NAMEI_CREATE))
637                 docache = 0;
638         rdonly = cnp->cn_flags & CNP_RDONLY;
639         cnp->cn_flags &= ~CNP_ISSYMLINK;
640         dp = dvp;
641         vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
642
643 /* dirloop: */
644         /*
645          * Search a new directory.
646          *
647          * The last component of the filename is left accessible via
648          * cnp->cn_nameptr for callers that need the name. Callers needing
649          * the name set the CNP_SAVENAME flag. When done, they assume
650          * responsibility for freeing the pathname buffer.
651          */
652 #ifdef NAMEI_DIAGNOSTIC
653         if (cnp->cn_namelen != cp - cnp->cn_nameptr)
654                 panic ("relookup: bad len");
655         if (*cp != 0)
656                 panic("relookup: not last component");
657         printf("{%s}: ", cnp->cn_nameptr);
658 #endif
659
660         /*
661          * Check for degenerate name (e.g. / or "")
662          * which is a way of talking about a directory,
663          * e.g. like "/." or ".".
664          */
665         if (cnp->cn_nameptr[0] == '\0') {
666                 if (cnp->cn_nameiop != NAMEI_LOOKUP || wantparent) {
667                         error = EISDIR;
668                         goto bad;
669                 }
670                 if (dp->v_type != VDIR) {
671                         error = ENOTDIR;
672                         goto bad;
673                 }
674                 if (!(cnp->cn_flags & CNP_LOCKLEAF))
675                         VOP_UNLOCK(dp, NULL, 0, td);
676                 *vpp = dp;
677                 /* XXX This should probably move to the top of function. */
678                 if (cnp->cn_flags & CNP_SAVESTART)
679                         panic("lookup: CNP_SAVESTART");
680                 return (0);
681         }
682
683         if (cnp->cn_flags & CNP_ISDOTDOT)
684                 panic ("relookup: lookup on dot-dot");
685
686         /*
687          * We now have a segment name to search for, and a directory to search.
688          */
689         if ((error = VOP_LOOKUP(dp, NCPNULL, vpp, NCPPNULL, cnp)) != 0) {
690                 KASSERT(*vpp == NULL, ("leaf should be empty"));
691                 if (error != EJUSTRETURN)
692                         goto bad;
693                 /*
694                  * If creating and at end of pathname, then can consider
695                  * allowing file to be created.
696                  */
697                 if (rdonly) {
698                         error = EROFS;
699                         goto bad;
700                 }
701                 /* ASSERT(dvp == ndp->ni_startdir) */
702                 if (cnp->cn_flags & CNP_SAVESTART)
703                         vref(dvp);
704                 /*
705                  * We return with ni_vp NULL to indicate that the entry
706                  * doesn't currently exist, leaving a pointer to the
707                  * (possibly locked) directory inode in ndp->ni_dvp.
708                  */
709                 return (0);
710         }
711         dp = *vpp;
712
713         /*
714          * Check for symbolic link
715          */
716         KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & CNP_FOLLOW),
717             ("relookup: symlink found.\n"));
718
719         /*
720          * Disallow directory write attempts on read-only file systems.
721          */
722         if (rdonly &&
723             (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) {
724                 error = EROFS;
725                 goto bad2;
726         }
727         /* ASSERT(dvp == ndp->ni_startdir) */
728         if (cnp->cn_flags & CNP_SAVESTART)
729                 vref(dvp);
730         
731         if (!wantparent)
732                 vrele(dvp);
733
734         if (vn_canvmio(dp) == TRUE &&
735                 ((cnp->cn_flags & (CNP_NOOBJ|CNP_LOCKLEAF)) == CNP_LOCKLEAF))
736                 vfs_object_create(dp, cnp->cn_td);
737
738         if ((cnp->cn_flags & CNP_LOCKLEAF) == 0)
739                 VOP_UNLOCK(dp, NULL, 0, td);
740         return (0);
741
742 bad2:
743         if ((cnp->cn_flags & CNP_LOCKPARENT) && (cnp->cn_flags & CNP_ISLASTCN))
744                 VOP_UNLOCK(dvp, NULL, 0, td);
745         vrele(dvp);
746 bad:
747         vput(dp);
748         *vpp = NULL;
749         return (error);
750 }