Cleanup pass. Removed code that is not needed anymore.
[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.12 2004/05/21 15:41:23 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          * POSIX.1 requirement: "" is not a vaild file name.
124          */
125         if (!error && *cnp->cn_pnbuf == '\0')
126                 error = ENOENT;
127
128         if (error) {
129                 zfree(namei_zone, cnp->cn_pnbuf);
130                 ndp->ni_vp = NULL;
131                 return (error);
132         }
133         ndp->ni_loopcnt = 0;
134 #ifdef KTRACE
135         if (KTRPOINT(cnp->cn_td, KTR_NAMEI))
136                 ktrnamei(cnp->cn_td->td_proc->p_tracep, cnp->cn_pnbuf);
137 #endif
138
139         /*
140          * Get starting point for the translation.
141          */
142         ndp->ni_rootdir = fdp->fd_rdir;
143         ndp->ni_topdir = fdp->fd_jdir;
144
145         dp = fdp->fd_cdir;
146         vref(dp);
147         for (;;) {
148                 /*
149                  * Check if root directory should replace current directory.
150                  * Done at start of translation and after symbolic link.
151                  */
152                 cnp->cn_nameptr = cnp->cn_pnbuf;
153                 if (*(cnp->cn_nameptr) == '/') {
154                         vrele(dp);
155                         while (*(cnp->cn_nameptr) == '/') {
156                                 cnp->cn_nameptr++;
157                                 ndp->ni_pathlen--;
158                         }
159                         dp = ndp->ni_rootdir;
160                         vref(dp);
161                 }
162                 ndp->ni_startdir = dp;
163                 error = lookup(ndp);
164                 if (error) {
165                         zfree(namei_zone, cnp->cn_pnbuf);
166                         return (error);
167                 }
168                 /*
169                  * Check for symbolic link
170                  */
171                 if ((cnp->cn_flags & CNP_ISSYMLINK) == 0) {
172                         if ((cnp->cn_flags & (CNP_SAVENAME | CNP_SAVESTART)) == 0)
173                                 zfree(namei_zone, cnp->cn_pnbuf);
174                         else
175                                 cnp->cn_flags |= CNP_HASBUF;
176
177                         if (vn_canvmio(ndp->ni_vp) == TRUE &&
178                                 (cnp->cn_nameiop != NAMEI_DELETE) &&
179                                 ((cnp->cn_flags & (CNP_NOOBJ|CNP_LOCKLEAF)) ==
180                                  CNP_LOCKLEAF))
181                                 vfs_object_create(ndp->ni_vp, ndp->ni_cnd.cn_td);
182
183                         return (0);
184                 }
185                 if ((cnp->cn_flags & CNP_LOCKPARENT) && ndp->ni_pathlen == 1)
186                         VOP_UNLOCK(ndp->ni_dvp, NULL, 0, cnp->cn_td);
187                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
188                         error = ELOOP;
189                         break;
190                 }
191                 if (ndp->ni_pathlen > 1)
192                         cp = zalloc(namei_zone);
193                 else
194                         cp = cnp->cn_pnbuf;
195                 aiov.iov_base = cp;
196                 aiov.iov_len = MAXPATHLEN;
197                 auio.uio_iov = &aiov;
198                 auio.uio_iovcnt = 1;
199                 auio.uio_offset = 0;
200                 auio.uio_rw = UIO_READ;
201                 auio.uio_segflg = UIO_SYSSPACE;
202                 auio.uio_td = NULL;
203                 auio.uio_resid = MAXPATHLEN;
204                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
205                 if (error) {
206                         if (ndp->ni_pathlen > 1)
207                                 zfree(namei_zone, cp);
208                         break;
209                 }
210                 linklen = MAXPATHLEN - auio.uio_resid;
211                 if (linklen == 0) {
212                         if (ndp->ni_pathlen > 1)
213                                 zfree(namei_zone, cp);
214                         error = ENOENT;
215                         break;
216                 }
217                 if (varsym_enable) {
218                         linklen = varsymreplace(cp, linklen, MAXPATHLEN);
219                         if (linklen < 0) {
220                                 if (ndp->ni_pathlen > 1)
221                                         zfree(namei_zone, cp);
222                                 error = ENAMETOOLONG;
223                                 break;
224                         }
225                 }
226                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
227                         if (ndp->ni_pathlen > 1)
228                                 zfree(namei_zone, cp);
229                         error = ENAMETOOLONG;
230                         break;
231                 }
232                 if (ndp->ni_pathlen > 1) {
233                         bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
234                         zfree(namei_zone, cnp->cn_pnbuf);
235                         cnp->cn_pnbuf = cp;
236                 } else {
237                         cnp->cn_pnbuf[linklen] = '\0';
238                 }
239                 ndp->ni_pathlen += linklen;
240                 vput(ndp->ni_vp);
241                 dp = ndp->ni_dvp;
242         }
243         zfree(namei_zone, cnp->cn_pnbuf);
244         vrele(ndp->ni_dvp);
245         vput(ndp->ni_vp);
246         ndp->ni_vp = NULL;
247         return (error);
248 }
249
250 /*
251  * Search a pathname.
252  * This is a very central and rather complicated routine.
253  *
254  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
255  * The starting directory is taken from ni_startdir. The pathname is
256  * descended until done, or a symbolic link is encountered. The variable
257  * ni_more is clear if the path is completed; it is set to one if a
258  * symbolic link needing interpretation is encountered.
259  *
260  * The flag argument is NAMEI_LOOKUP, CREATE, RENAME, or DELETE depending on
261  * whether the name is to be looked up, created, renamed, or deleted.
262  * When CREATE, RENAME, or DELETE is specified, information usable in
263  * creating, renaming, or deleting a directory entry may be calculated.
264  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
265  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
266  * returned unlocked. Otherwise the parent directory is not returned. If
267  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
268  * the target is returned locked, otherwise it is returned unlocked.
269  * When creating or renaming and LOCKPARENT is specified, the target may not
270  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
271  *
272  * Overall outline of lookup:
273  *
274  * dirloop:
275  *      identify next component of name at ndp->ni_ptr
276  *      handle degenerate case where name is null string
277  *      if .. and crossing mount points and on mounted filesys, find parent
278  *      call VOP_LOOKUP routine for next component name
279  *          directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
280  *          component vnode returned in ni_vp (if it exists), locked.
281  *      if result vnode is mounted on and crossing mount points,
282  *          find mounted on vnode
283  *      if more components of name, do next level at dirloop
284  *      return the answer in ni_vp, locked if LOCKLEAF set
285  *          if LOCKPARENT set, return locked parent in ni_dvp
286  *          if WANTPARENT set, return unlocked parent in ni_dvp
287  */
288 int
289 lookup(struct nameidata *ndp)
290 {
291         char *cp;                       /* pointer into pathname argument */
292         struct vnode *dp = NULL;        /* the directory we are searching */
293         struct vnode *tdp;              /* saved dp */
294         struct mount *mp;               /* mount table entry */
295         int docache;                    /* == 0 do not cache last component */
296         int wantparent;                 /* 1 => wantparent or lockparent flag */
297         int rdonly;                     /* lookup read-only flag bit */
298         int trailing_slash;
299         int error = 0;
300         int dpunlocked = 0;             /* dp has already been unlocked */
301         struct componentname *cnp = &ndp->ni_cnd;
302         struct thread *td = cnp->cn_td;
303
304         /*
305          * Setup: break out flag bits into variables.
306          */
307         wantparent = cnp->cn_flags & (CNP_LOCKPARENT | CNP_WANTPARENT);
308         docache = (cnp->cn_flags & CNP_NOCACHE) ^ CNP_NOCACHE;
309         if (cnp->cn_nameiop == NAMEI_DELETE ||
310             (wantparent && cnp->cn_nameiop != NAMEI_CREATE &&
311              cnp->cn_nameiop != NAMEI_LOOKUP))
312                 docache = 0;
313         rdonly = cnp->cn_flags & CNP_RDONLY;
314         ndp->ni_dvp = NULL;
315         cnp->cn_flags &= ~CNP_ISSYMLINK;
316         dp = ndp->ni_startdir;
317         ndp->ni_startdir = NULLVP;
318         vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
319
320 dirloop:
321         /*
322          * Search a new directory.
323          *
324          * The last component of the filename is left accessible via
325          * cnp->cn_nameptr for callers that need the name. Callers needing
326          * the name set the CNP_SAVENAME flag. When done, they assume
327          * responsibility for freeing the pathname buffer.
328          */
329         cnp->cn_consume = 0;
330         for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
331                 continue;
332         cnp->cn_namelen = cp - cnp->cn_nameptr;
333         if (cnp->cn_namelen > NAME_MAX) {
334                 error = ENAMETOOLONG;
335                 goto bad;
336         }
337 #ifdef NAMEI_DIAGNOSTIC
338         { char c = *cp;
339         *cp = '\0';
340         printf("{%s}: ", cnp->cn_nameptr);
341         *cp = c; }
342 #endif
343         ndp->ni_pathlen -= cnp->cn_namelen;
344         ndp->ni_next = cp;
345
346         /*
347          * Replace multiple slashes by a single slash and trailing slashes
348          * by a null.  This must be done before VOP_LOOKUP() because some
349          * fs's don't know about trailing slashes.  Remember if there were
350          * trailing slashes to handle symlinks, existing non-directories
351          * and non-existing files that won't be directories specially later.
352          */
353         trailing_slash = 0;
354         while (*cp == '/' && (cp[1] == '/' || cp[1] == '\0')) {
355                 cp++;
356                 ndp->ni_pathlen--;
357                 if (*cp == '\0') {
358                         trailing_slash = 1;
359                         *ndp->ni_next = '\0';   /* XXX for direnter() ... */
360                 }
361         }
362         ndp->ni_next = cp;
363
364         cnp->cn_flags |= CNP_MAKEENTRY;
365         if (*cp == '\0' && docache == 0)
366                 cnp->cn_flags &= ~CNP_MAKEENTRY;
367         if (cnp->cn_namelen == 2 &&
368             cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
369                 cnp->cn_flags |= CNP_ISDOTDOT;
370         else
371                 cnp->cn_flags &= ~CNP_ISDOTDOT;
372         if (*ndp->ni_next == 0)
373                 cnp->cn_flags |= CNP_ISLASTCN;
374         else
375                 cnp->cn_flags &= ~CNP_ISLASTCN;
376
377
378         /*
379          * Check for degenerate name (e.g. / or "")
380          * which is a way of talking about a directory,
381          * e.g. like "/." or ".".
382          */
383         if (cnp->cn_nameptr[0] == '\0') {
384                 if (dp->v_type != VDIR) {
385                         error = ENOTDIR;
386                         goto bad;
387                 }
388                 if (cnp->cn_nameiop != NAMEI_LOOKUP) {
389                         error = EISDIR;
390                         goto bad;
391                 }
392                 if (wantparent) {
393                         ndp->ni_dvp = dp;
394                         vref(dp);
395                 }
396                 ndp->ni_vp = dp;
397                 if (!(cnp->cn_flags & (CNP_LOCKPARENT | CNP_LOCKLEAF)))
398                         VOP_UNLOCK(dp, NULL, 0, cnp->cn_td);
399                 /* XXX This should probably move to the top of function. */
400                 if (cnp->cn_flags & CNP_SAVESTART)
401                         panic("lookup: CNP_SAVESTART");
402                 return (0);
403         }
404
405         /*
406          * Handle "..": two special cases.
407          * 1. If at root directory (e.g. after chroot)
408          *    or at absolute root directory
409          *    then ignore it so can't get out.
410          * 2. If this vnode is the root of a mounted
411          *    filesystem, then replace it with the
412          *    vnode which was mounted on so we take the
413          *    .. in the other file system.
414          * 3. If the vnode is the top directory of
415          *    the jail or chroot, don't let them out.
416          */
417         if (cnp->cn_flags & CNP_ISDOTDOT) {
418                 for (;;) {
419                         if (dp == ndp->ni_rootdir || 
420                             dp == ndp->ni_topdir || 
421                             dp == rootvnode) {
422                                 ndp->ni_dvp = dp;
423                                 ndp->ni_vp = dp;
424                                 vref(dp);
425                                 goto nextname;
426                         }
427                         if ((dp->v_flag & VROOT) == 0 ||
428                             (cnp->cn_flags & CNP_NOCROSSMOUNT))
429                                 break;
430                         if (dp->v_mount == NULL) {      /* forced unmount */
431                                 error = EBADF;
432                                 goto bad;
433                         }
434                         tdp = dp;
435                         dp = dp->v_mount->mnt_vnodecovered;
436                         vput(tdp);
437                         vref(dp);
438                         vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
439                 }
440         }
441
442         /*
443          * We now have a segment name to search for, and a directory to search.
444          */
445 unionlookup:
446         ndp->ni_dvp = dp;
447         ndp->ni_vp = NULL;
448         cnp->cn_flags &= ~CNP_PDIRUNLOCK;
449         ASSERT_VOP_LOCKED(dp, "lookup");
450         if ((error = VOP_LOOKUP(dp, NCPNULL, &ndp->ni_vp, NCPPNULL, cnp)) != 0) {
451                 KASSERT(ndp->ni_vp == NULL, ("leaf should be empty"));
452 #ifdef NAMEI_DIAGNOSTIC
453                 printf("not found\n");
454 #endif
455                 if ((error == ENOENT) &&
456                     (dp->v_flag & VROOT) && (dp->v_mount != NULL) &&
457                     (dp->v_mount->mnt_flag & MNT_UNION)) {
458                         tdp = dp;
459                         dp = dp->v_mount->mnt_vnodecovered;
460                         if (cnp->cn_flags & CNP_PDIRUNLOCK)
461                                 vrele(tdp);
462                         else
463                                 vput(tdp);
464                         vref(dp);
465                         vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
466                         goto unionlookup;
467                 }
468
469                 if (error != EJUSTRETURN)
470                         goto bad;
471                 /*
472                  * If creating and at end of pathname, then can consider
473                  * allowing file to be created.
474                  */
475                 if (rdonly) {
476                         error = EROFS;
477                         goto bad;
478                 }
479                 if (*cp == '\0' && trailing_slash &&
480                      !(cnp->cn_flags & CNP_WILLBEDIR)) {
481                         error = ENOENT;
482                         goto bad;
483                 }
484                 /*
485                  * We return with ni_vp NULL to indicate that the entry
486                  * doesn't currently exist, leaving a pointer to the
487                  * (possibly locked) directory inode in ndp->ni_dvp.
488                  */
489                 if (cnp->cn_flags & CNP_SAVESTART) {
490                         ndp->ni_startdir = ndp->ni_dvp;
491                         vref(ndp->ni_startdir);
492                 }
493                 return (0);
494         }
495 #ifdef NAMEI_DIAGNOSTIC
496         printf("found\n");
497 #endif
498
499         ASSERT_VOP_LOCKED(ndp->ni_vp, "lookup");
500
501         /*
502          * Take into account any additional components consumed by
503          * the underlying filesystem.
504          */
505         if (cnp->cn_consume > 0) {
506                 cnp->cn_nameptr += cnp->cn_consume;
507                 ndp->ni_next += cnp->cn_consume;
508                 ndp->ni_pathlen -= cnp->cn_consume;
509                 cnp->cn_consume = 0;
510         }
511
512         dp = ndp->ni_vp;
513
514         /*
515          * Check to see if the vnode has been mounted on;
516          * if so find the root of the mounted file system.
517          */
518         while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
519                (cnp->cn_flags & CNP_NOCROSSMOUNT) == 0) {
520                 if (vfs_busy(mp, 0, NULL, td))
521                         continue;
522                 VOP_UNLOCK(dp, NULL, 0, td);
523                 error = VFS_ROOT(mp, &tdp);
524                 vfs_unbusy(mp, td);
525                 if (error) {
526                         dpunlocked = 1;
527                         goto bad2;
528                 }
529                 cache_mount(dp, tdp);
530                 vrele(dp);
531                 ndp->ni_vp = dp = tdp;
532         }
533
534         /*
535          * Check for symbolic link
536          */
537         if ((dp->v_type == VLNK) &&
538             ((cnp->cn_flags & CNP_FOLLOW) || trailing_slash ||
539              *ndp->ni_next == '/')) {
540                 cnp->cn_flags |= CNP_ISSYMLINK;
541                 if (dp->v_mount == NULL) {
542                         /* We can't know whether the directory was mounted with
543                          * NOSYMFOLLOW, so we can't follow safely. */
544                         error = EBADF;
545                         goto bad2;
546                 }
547                 if (dp->v_mount->mnt_flag & MNT_NOSYMFOLLOW) {
548                         error = EACCES;
549                         goto bad2;
550                 }
551                 return (0);
552         }
553
554         /*
555          * Check for bogus trailing slashes.
556          */
557         if (trailing_slash && dp->v_type != VDIR) {
558                 error = ENOTDIR;
559                 goto bad2;
560         }
561
562 nextname:
563         /*
564          * Not a symbolic link.  If more pathname,
565          * continue at next component, else return.
566          */
567         if (*ndp->ni_next == '/') {
568                 cnp->cn_nameptr = ndp->ni_next;
569                 while (*cnp->cn_nameptr == '/') {
570                         cnp->cn_nameptr++;
571                         ndp->ni_pathlen--;
572                 }
573                 if (ndp->ni_dvp != ndp->ni_vp)
574                         ASSERT_VOP_UNLOCKED(ndp->ni_dvp, "lookup");
575                 vrele(ndp->ni_dvp);
576                 goto dirloop;
577         }
578         /*
579          * Disallow directory write attempts on read-only file systems.
580          */
581         if (rdonly &&
582             (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) {
583                 error = EROFS;
584                 goto bad2;
585         }
586         if (cnp->cn_flags & CNP_SAVESTART) {
587                 ndp->ni_startdir = ndp->ni_dvp;
588                 vref(ndp->ni_startdir);
589         }
590         if (!wantparent)
591                 vrele(ndp->ni_dvp);
592
593         if ((cnp->cn_flags & CNP_LOCKLEAF) == 0)
594                 VOP_UNLOCK(dp, NULL, 0, td);
595         return (0);
596
597 bad2:
598         if ((cnp->cn_flags & (CNP_LOCKPARENT | CNP_PDIRUNLOCK)) == CNP_LOCKPARENT &&
599             *ndp->ni_next == '\0')
600                 VOP_UNLOCK(ndp->ni_dvp, NULL, 0, td);
601         vrele(ndp->ni_dvp);
602 bad:
603         if (dpunlocked)
604                 vrele(dp);
605         else
606                 vput(dp);
607         ndp->ni_vp = NULL;
608         return (error);
609 }
610
611 /*
612  * relookup - lookup a path name component
613  *    Used by lookup to re-aquire things.
614  */
615 int
616 relookup(dvp, vpp, cnp)
617         struct vnode *dvp, **vpp;
618         struct componentname *cnp;
619 {
620         struct thread *td = cnp->cn_td;
621         struct vnode *dp = 0;           /* the directory we are searching */
622         int docache;                    /* == 0 do not cache last component */
623         int wantparent;                 /* 1 => wantparent or lockparent flag */
624         int rdonly;                     /* lookup read-only flag bit */
625         int error = 0;
626 #ifdef NAMEI_DIAGNOSTIC
627         int newhash;                    /* DEBUG: check name hash */
628         char *cp;                       /* DEBUG: check name ptr/len */
629 #endif
630
631         /*
632          * Setup: break out flag bits into variables.
633          */
634         wantparent = cnp->cn_flags & (CNP_LOCKPARENT|CNP_WANTPARENT);
635         docache = (cnp->cn_flags & CNP_NOCACHE) ^ CNP_NOCACHE;
636         if (cnp->cn_nameiop == NAMEI_DELETE ||
637             (wantparent && cnp->cn_nameiop != NAMEI_CREATE))
638                 docache = 0;
639         rdonly = cnp->cn_flags & CNP_RDONLY;
640         cnp->cn_flags &= ~CNP_ISSYMLINK;
641         dp = dvp;
642         vn_lock(dp, NULL, LK_EXCLUSIVE | LK_RETRY, td);
643
644 /* dirloop: */
645         /*
646          * Search a new directory.
647          *
648          * The last component of the filename is left accessible via
649          * cnp->cn_nameptr for callers that need the name. Callers needing
650          * the name set the CNP_SAVENAME flag. When done, they assume
651          * responsibility for freeing the pathname buffer.
652          */
653 #ifdef NAMEI_DIAGNOSTIC
654         if (cnp->cn_namelen != cp - cnp->cn_nameptr)
655                 panic ("relookup: bad len");
656         if (*cp != 0)
657                 panic("relookup: not last component");
658         printf("{%s}: ", cnp->cn_nameptr);
659 #endif
660
661         /*
662          * Check for degenerate name (e.g. / or "")
663          * which is a way of talking about a directory,
664          * e.g. like "/." or ".".
665          */
666         if (cnp->cn_nameptr[0] == '\0') {
667                 if (cnp->cn_nameiop != NAMEI_LOOKUP || wantparent) {
668                         error = EISDIR;
669                         goto bad;
670                 }
671                 if (dp->v_type != VDIR) {
672                         error = ENOTDIR;
673                         goto bad;
674                 }
675                 if (!(cnp->cn_flags & CNP_LOCKLEAF))
676                         VOP_UNLOCK(dp, NULL, 0, td);
677                 *vpp = dp;
678                 /* XXX This should probably move to the top of function. */
679                 if (cnp->cn_flags & CNP_SAVESTART)
680                         panic("lookup: CNP_SAVESTART");
681                 return (0);
682         }
683
684         if (cnp->cn_flags & CNP_ISDOTDOT)
685                 panic ("relookup: lookup on dot-dot");
686
687         /*
688          * We now have a segment name to search for, and a directory to search.
689          */
690         if ((error = VOP_LOOKUP(dp, NCPNULL, vpp, NCPPNULL, cnp)) != 0) {
691                 KASSERT(*vpp == NULL, ("leaf should be empty"));
692                 if (error != EJUSTRETURN)
693                         goto bad;
694                 /*
695                  * If creating and at end of pathname, then can consider
696                  * allowing file to be created.
697                  */
698                 if (rdonly) {
699                         error = EROFS;
700                         goto bad;
701                 }
702                 /* ASSERT(dvp == ndp->ni_startdir) */
703                 if (cnp->cn_flags & CNP_SAVESTART)
704                         vref(dvp);
705                 /*
706                  * We return with ni_vp NULL to indicate that the entry
707                  * doesn't currently exist, leaving a pointer to the
708                  * (possibly locked) directory inode in ndp->ni_dvp.
709                  */
710                 return (0);
711         }
712         dp = *vpp;
713
714         /*
715          * Check for symbolic link
716          */
717         KASSERT(dp->v_type != VLNK || !(cnp->cn_flags & CNP_FOLLOW),
718             ("relookup: symlink found.\n"));
719
720         /*
721          * Disallow directory write attempts on read-only file systems.
722          */
723         if (rdonly &&
724             (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME)) {
725                 error = EROFS;
726                 goto bad2;
727         }
728         /* ASSERT(dvp == ndp->ni_startdir) */
729         if (cnp->cn_flags & CNP_SAVESTART)
730                 vref(dvp);
731         
732         if (!wantparent)
733                 vrele(dvp);
734
735         if (vn_canvmio(dp) == TRUE &&
736                 ((cnp->cn_flags & (CNP_NOOBJ|CNP_LOCKLEAF)) == CNP_LOCKLEAF))
737                 vfs_object_create(dp, cnp->cn_td);
738
739         if ((cnp->cn_flags & CNP_LOCKLEAF) == 0)
740                 VOP_UNLOCK(dp, NULL, 0, td);
741         return (0);
742
743 bad2:
744         if ((cnp->cn_flags & CNP_LOCKPARENT) && (cnp->cn_flags & CNP_ISLASTCN))
745                 VOP_UNLOCK(dvp, NULL, 0, td);
746         vrele(dvp);
747 bad:
748         vput(dp);
749         *vpp = NULL;
750         return (error);
751 }