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