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