[BACK]Return to vfs_lookup.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/vfs_lookup.c, Revision 1.56

1.56    ! perry       1: /*     $NetBSD: vfs_lookup.c,v 1.55 2004/09/17 14:11:25 skrll Exp $    */
1.13      cgd         2:
1.10      cgd         3: /*
1.12      mycroft     4:  * Copyright (c) 1982, 1986, 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.10      cgd         6:  * (c) UNIX System Laboratories, Inc.
                      7:  * All or some portions of this file are derived from material licensed
                      8:  * to the University of California by American Telephone and Telegraph
                      9:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
                     10:  * the permission of UNIX System Laboratories, Inc.
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
1.49      agc        20:  * 3. Neither the name of the University nor the names of its contributors
1.10      cgd        21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  *
1.26      fvdl       36:  *     @(#)vfs_lookup.c        8.10 (Berkeley) 5/27/95
1.10      cgd        37:  */
1.38      lukem      38:
                     39: #include <sys/cdefs.h>
1.56    ! perry      40: __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.55 2004/09/17 14:11:25 skrll Exp $");
1.27      thorpej    41:
                     42: #include "opt_ktrace.h"
1.50      cb         43: #include "opt_systrace.h"
1.10      cgd        44:
                     45: #include <sys/param.h>
1.15      cgd        46: #include <sys/systm.h>
1.10      cgd        47: #include <sys/syslimits.h>
                     48: #include <sys/time.h>
                     49: #include <sys/namei.h>
                     50: #include <sys/vnode.h>
                     51: #include <sys/mount.h>
                     52: #include <sys/errno.h>
1.39      lukem      53: #include <sys/filedesc.h>
                     54: #include <sys/hash.h>
1.10      cgd        55: #include <sys/malloc.h>
                     56: #include <sys/proc.h>
1.40      wrstuden   57: #include <sys/syslog.h>
1.12      mycroft    58:
1.10      cgd        59: #ifdef KTRACE
                     60: #include <sys/ktrace.h>
                     61: #endif
1.50      cb         62: #ifdef SYSTRACE
                     63: #include <sys/systrace.h>
                     64: #endif
1.16      christos   65:
1.35      thorpej    66: struct pool pnbuf_pool;                /* pathname buffer pool */
1.37      thorpej    67: struct pool_cache pnbuf_cache; /* pathname buffer cache */
1.44      thorpej    68:
                     69: MALLOC_DEFINE(M_NAMEI, "namei", "namei path buffer");
1.35      thorpej    70:
1.10      cgd        71: /*
                     72:  * Convert a pathname into a pointer to a locked inode.
                     73:  *
                     74:  * The FOLLOW flag is set when symbolic links are to be followed
                     75:  * when they occur at the end of the name translation process.
                     76:  * Symbolic links are always followed for all other pathname
                     77:  * components other than the last.
                     78:  *
                     79:  * The segflg defines whether the name is to be copied from user
                     80:  * space or kernel space.
                     81:  *
                     82:  * Overall outline of namei:
                     83:  *
                     84:  *     copy in name
                     85:  *     get starting directory
                     86:  *     while (!done && !error) {
                     87:  *             call lookup to search path.
                     88:  *             if symbolic link, massage name in buffer and continue
                     89:  *     }
                     90:  */
1.12      mycroft    91: int
                     92: namei(ndp)
1.33      augustss   93:        struct nameidata *ndp;
1.10      cgd        94: {
1.30      thorpej    95:        struct cwdinfo *cwdi;           /* pointer to cwd state */
1.33      augustss   96:        char *cp;                       /* pointer into pathname argument */
                     97:        struct vnode *dp;               /* the directory we are searching */
1.10      cgd        98:        struct iovec aiov;              /* uio for reading symbolic links */
                     99:        struct uio auio;
1.23      mycroft   100:        int error, linklen;
1.12      mycroft   101:        struct componentname *cnp = &ndp->ni_cnd;
1.10      cgd       102:
1.12      mycroft   103: #ifdef DIAGNOSTIC
1.48      fvdl      104:        if (!cnp->cn_cred || !cnp->cn_proc)
1.12      mycroft   105:                panic ("namei: bad cred/proc");
                    106:        if (cnp->cn_nameiop & (~OPMASK))
                    107:                panic ("namei: nameiop contaminated with flags");
                    108:        if (cnp->cn_flags & OPMASK)
                    109:                panic ("namei: flags contaminated with nameiops");
                    110: #endif
1.48      fvdl      111:        cwdi = cnp->cn_proc->p_cwdi;
1.10      cgd       112:
                    113:        /*
                    114:         * Get a buffer for the name to be translated, and copy the
                    115:         * name into the buffer.
                    116:         */
1.12      mycroft   117:        if ((cnp->cn_flags & HASBUF) == 0)
1.35      thorpej   118:                cnp->cn_pnbuf = PNBUF_GET();
1.10      cgd       119:        if (ndp->ni_segflg == UIO_SYSSPACE)
1.12      mycroft   120:                error = copystr(ndp->ni_dirp, cnp->cn_pnbuf,
1.10      cgd       121:                            MAXPATHLEN, &ndp->ni_pathlen);
                    122:        else
1.12      mycroft   123:                error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf,
1.10      cgd       124:                            MAXPATHLEN, &ndp->ni_pathlen);
1.21      kleink    125:
                    126:        /*
                    127:         * POSIX.1 requirement: "" is not a valid file name.
1.56    ! perry     128:         */
1.21      kleink    129:        if (!error && ndp->ni_pathlen == 1)
                    130:                error = ENOENT;
                    131:
1.10      cgd       132:        if (error) {
1.35      thorpej   133:                PNBUF_PUT(cnp->cn_pnbuf);
1.10      cgd       134:                ndp->ni_vp = NULL;
                    135:                return (error);
                    136:        }
                    137:        ndp->ni_loopcnt = 0;
1.21      kleink    138:
1.10      cgd       139: #ifdef KTRACE
1.48      fvdl      140:        if (KTRPOINT(cnp->cn_proc, KTR_NAMEI))
                    141:                ktrnamei(cnp->cn_proc, cnp->cn_pnbuf);
1.50      cb        142: #endif
                    143: #ifdef SYSTRACE
                    144:        if (ISSET(cnp->cn_proc->p_flag, P_SYSTRACE))
                    145:                systrace_namei(ndp);
1.10      cgd       146: #endif
                    147:
                    148:        /*
                    149:         * Get starting point for the translation.
                    150:         */
1.30      thorpej   151:        if ((ndp->ni_rootdir = cwdi->cwdi_rdir) == NULL)
1.11      cgd       152:                ndp->ni_rootdir = rootvnode;
1.23      mycroft   153:        /*
                    154:         * Check if starting from root directory or current directory.
                    155:         */
                    156:        if (cnp->cn_pnbuf[0] == '/') {
                    157:                dp = ndp->ni_rootdir;
                    158:                VREF(dp);
                    159:        } else {
1.30      thorpej   160:                dp = cwdi->cwdi_cdir;
1.23      mycroft   161:                VREF(dp);
                    162:        }
1.10      cgd       163:        for (;;) {
1.45      erh       164:                if (!dp->v_mount)
                    165:                {
                    166:                        /* Give up if the directory is no longer mounted */
                    167:                        PNBUF_PUT(cnp->cn_pnbuf);
                    168:                        return (ENOENT);
                    169:                }
1.12      mycroft   170:                cnp->cn_nameptr = cnp->cn_pnbuf;
1.10      cgd       171:                ndp->ni_startdir = dp;
1.16      christos  172:                if ((error = lookup(ndp)) != 0) {
1.35      thorpej   173:                        PNBUF_PUT(cnp->cn_pnbuf);
1.10      cgd       174:                        return (error);
                    175:                }
                    176:                /*
                    177:                 * Check for symbolic link
                    178:                 */
1.12      mycroft   179:                if ((cnp->cn_flags & ISSYMLINK) == 0) {
                    180:                        if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
1.35      thorpej   181:                                PNBUF_PUT(cnp->cn_pnbuf);
1.10      cgd       182:                        else
1.12      mycroft   183:                                cnp->cn_flags |= HASBUF;
1.10      cgd       184:                        return (0);
                    185:                }
1.29      wrstuden  186:                if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
1.26      fvdl      187:                        VOP_UNLOCK(ndp->ni_dvp, 0);
1.10      cgd       188:                if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
                    189:                        error = ELOOP;
                    190:                        break;
                    191:                }
1.25      enami     192:                if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
                    193:                        error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred,
1.48      fvdl      194:                            cnp->cn_proc);
1.25      enami     195:                        if (error != 0)
                    196:                                break;
                    197:                }
1.10      cgd       198:                if (ndp->ni_pathlen > 1)
1.35      thorpej   199:                        cp = PNBUF_GET();
1.10      cgd       200:                else
1.12      mycroft   201:                        cp = cnp->cn_pnbuf;
1.10      cgd       202:                aiov.iov_base = cp;
                    203:                aiov.iov_len = MAXPATHLEN;
                    204:                auio.uio_iov = &aiov;
                    205:                auio.uio_iovcnt = 1;
                    206:                auio.uio_offset = 0;
                    207:                auio.uio_rw = UIO_READ;
                    208:                auio.uio_segflg = UIO_SYSSPACE;
1.55      skrll     209:                auio.uio_procp = NULL;
1.10      cgd       210:                auio.uio_resid = MAXPATHLEN;
1.16      christos  211:                error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
                    212:                if (error) {
1.23      mycroft   213:                badlink:
1.10      cgd       214:                        if (ndp->ni_pathlen > 1)
1.35      thorpej   215:                                PNBUF_PUT(cp);
1.10      cgd       216:                        break;
                    217:                }
                    218:                linklen = MAXPATHLEN - auio.uio_resid;
1.23      mycroft   219:                if (linklen == 0) {
                    220:                        error = ENOENT;
                    221:                        goto badlink;
                    222:                }
1.10      cgd       223:                if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
                    224:                        error = ENAMETOOLONG;
1.23      mycroft   225:                        goto badlink;
1.10      cgd       226:                }
                    227:                if (ndp->ni_pathlen > 1) {
1.28      perry     228:                        memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
1.35      thorpej   229:                        PNBUF_PUT(cnp->cn_pnbuf);
1.12      mycroft   230:                        cnp->cn_pnbuf = cp;
1.10      cgd       231:                } else
1.12      mycroft   232:                        cnp->cn_pnbuf[linklen] = '\0';
1.10      cgd       233:                ndp->ni_pathlen += linklen;
                    234:                vput(ndp->ni_vp);
                    235:                dp = ndp->ni_dvp;
1.23      mycroft   236:                /*
                    237:                 * Check if root directory should replace current directory.
                    238:                 */
                    239:                if (cnp->cn_pnbuf[0] == '/') {
                    240:                        vrele(dp);
                    241:                        dp = ndp->ni_rootdir;
                    242:                        VREF(dp);
                    243:                }
1.10      cgd       244:        }
1.35      thorpej   245:        PNBUF_PUT(cnp->cn_pnbuf);
1.10      cgd       246:        vrele(ndp->ni_dvp);
                    247:        vput(ndp->ni_vp);
                    248:        ndp->ni_vp = NULL;
                    249:        return (error);
                    250: }
                    251:
                    252: /*
1.39      lukem     253:  * Determine the namei hash (for cn_hash) for name.
                    254:  * If *ep != NULL, hash from name to ep-1.
                    255:  * If *ep == NULL, hash from name until the first NUL or '/', and
                    256:  * return the location of this termination character in *ep.
                    257:  *
                    258:  * This function returns an equivalent hash to the MI hash32_strn().
                    259:  * The latter isn't used because in the *ep == NULL case, determining
                    260:  * the length of the string to the first NUL or `/' and then calling
                    261:  * hash32_strn() involves unnecessary double-handling of the data.
                    262:  */
                    263: uint32_t
                    264: namei_hash(const char *name, const char **ep)
                    265: {
                    266:        uint32_t        hash;
                    267:
                    268:        hash = HASH32_STR_INIT;
                    269:        if (*ep != NULL) {
                    270:                for (; name < *ep; name++)
                    271:                        hash = hash * 33 + *(uint8_t *)name;
                    272:        } else {
                    273:                for (; *name != '\0' && *name != '/'; name++)
                    274:                        hash = hash * 33 + *(uint8_t *)name;
                    275:                *ep = name;
                    276:        }
                    277:        return (hash + (hash >> 5));
                    278: }
                    279:
                    280: /*
1.10      cgd       281:  * Search a pathname.
                    282:  * This is a very central and rather complicated routine.
                    283:  *
                    284:  * The pathname is pointed to by ni_ptr and is of length ni_pathlen.
                    285:  * The starting directory is taken from ni_startdir. The pathname is
                    286:  * descended until done, or a symbolic link is encountered. The variable
                    287:  * ni_more is clear if the path is completed; it is set to one if a
                    288:  * symbolic link needing interpretation is encountered.
                    289:  *
                    290:  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
                    291:  * whether the name is to be looked up, created, renamed, or deleted.
                    292:  * When CREATE, RENAME, or DELETE is specified, information usable in
                    293:  * creating, renaming, or deleting a directory entry may be calculated.
                    294:  * If flag has LOCKPARENT or'ed into it, the parent directory is returned
                    295:  * locked. If flag has WANTPARENT or'ed into it, the parent directory is
                    296:  * returned unlocked. Otherwise the parent directory is not returned. If
                    297:  * the target of the pathname exists and LOCKLEAF is or'ed into the flag
                    298:  * the target is returned locked, otherwise it is returned unlocked.
                    299:  * When creating or renaming and LOCKPARENT is specified, the target may not
                    300:  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
1.56    ! perry     301:  *
1.10      cgd       302:  * Overall outline of lookup:
                    303:  *
                    304:  * dirloop:
                    305:  *     identify next component of name at ndp->ni_ptr
                    306:  *     handle degenerate case where name is null string
                    307:  *     if .. and crossing mount points and on mounted filesys, find parent
                    308:  *     call VOP_LOOKUP routine for next component name
                    309:  *         directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
                    310:  *         component vnode returned in ni_vp (if it exists), locked.
                    311:  *     if result vnode is mounted on and crossing mount points,
                    312:  *         find mounted on vnode
                    313:  *     if more components of name, do next level at dirloop
                    314:  *     return the answer in ni_vp, locked if LOCKLEAF set
                    315:  *         if LOCKPARENT set, return locked parent in ni_dvp
                    316:  *         if WANTPARENT set, return unlocked parent in ni_dvp
                    317:  */
1.12      mycroft   318: int
                    319: lookup(ndp)
1.33      augustss  320:        struct nameidata *ndp;
1.10      cgd       321: {
1.33      augustss  322:        const char *cp;                 /* pointer into pathname argument */
                    323:        struct vnode *dp = 0;           /* the directory we are searching */
1.10      cgd       324:        struct vnode *tdp;              /* saved dp */
                    325:        struct mount *mp;               /* mount table entry */
                    326:        int docache;                    /* == 0 do not cache last component */
                    327:        int wantparent;                 /* 1 => wantparent or lockparent flag */
1.12      mycroft   328:        int rdonly;                     /* lookup read-only flag bit */
1.10      cgd       329:        int error = 0;
1.23      mycroft   330:        int slashes;
1.32      wrstuden  331:        int dpunlocked = 0;             /* dp has already been unlocked */
1.12      mycroft   332:        struct componentname *cnp = &ndp->ni_cnd;
1.10      cgd       333:
                    334:        /*
                    335:         * Setup: break out flag bits into variables.
                    336:         */
1.12      mycroft   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))
1.10      cgd       341:                docache = 0;
1.12      mycroft   342:        rdonly = cnp->cn_flags & RDONLY;
1.10      cgd       343:        ndp->ni_dvp = NULL;
1.12      mycroft   344:        cnp->cn_flags &= ~ISSYMLINK;
1.10      cgd       345:        dp = ndp->ni_startdir;
                    346:        ndp->ni_startdir = NULLVP;
1.26      fvdl      347:        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.10      cgd       348:
1.23      mycroft   349:        /*
                    350:         * If we have a leading string of slashes, remove them, and just make
                    351:         * sure the current node is a directory.
                    352:         */
                    353:        cp = cnp->cn_nameptr;
                    354:        if (*cp == '/') {
                    355:                do {
                    356:                        cp++;
                    357:                } while (*cp == '/');
                    358:                ndp->ni_pathlen -= cp - cnp->cn_nameptr;
                    359:                cnp->cn_nameptr = cp;
                    360:
                    361:                if (dp->v_type != VDIR) {
                    362:                        error = ENOTDIR;
                    363:                        goto bad;
                    364:                }
                    365:
                    366:                /*
                    367:                 * If we've exhausted the path name, then just return the
                    368:                 * current node.  If the caller requested the parent node (i.e.
                    369:                 * it's a CREATE, DELETE, or RENAME), and we don't have one
                    370:                 * (because this is the root directory), then we must fail.
                    371:                 */
                    372:                if (cnp->cn_nameptr[0] == '\0') {
                    373:                        if (ndp->ni_dvp == NULL && wantparent) {
                    374:                                error = EISDIR;
                    375:                                goto bad;
                    376:                        }
                    377:                        ndp->ni_vp = dp;
                    378:                        cnp->cn_flags |= ISLASTCN;
                    379:                        goto terminal;
                    380:                }
                    381:        }
                    382:
1.10      cgd       383: dirloop:
                    384:        /*
                    385:         * Search a new directory.
                    386:         *
1.12      mycroft   387:         * The cn_hash value is for use by vfs_cache.
1.10      cgd       388:         * The last component of the filename is left accessible via
1.12      mycroft   389:         * cnp->cn_nameptr for callers that need the name. Callers needing
1.10      cgd       390:         * the name set the SAVENAME flag. When done, they assume
                    391:         * responsibility for freeing the pathname buffer.
                    392:         */
1.12      mycroft   393:        cnp->cn_consume = 0;
1.39      lukem     394:        cp = NULL;
                    395:        cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp);
1.12      mycroft   396:        cnp->cn_namelen = cp - cnp->cn_nameptr;
                    397:        if (cnp->cn_namelen > NAME_MAX) {
1.10      cgd       398:                error = ENAMETOOLONG;
                    399:                goto bad;
                    400:        }
                    401: #ifdef NAMEI_DIAGNOSTIC
                    402:        { char c = *cp;
1.41      soren     403:        *(char *)cp = '\0';
1.19      christos  404:        printf("{%s}: ", cnp->cn_nameptr);
1.41      soren     405:        *(char *)cp = c; }
1.52      yamt      406: #endif /* NAMEI_DIAGNOSTIC */
1.12      mycroft   407:        ndp->ni_pathlen -= cnp->cn_namelen;
1.10      cgd       408:        ndp->ni_next = cp;
1.23      mycroft   409:        /*
                    410:         * If this component is followed by a slash, then move the pointer to
                    411:         * the next component forward, and remember that this component must be
                    412:         * a directory.
                    413:         */
                    414:        if (*cp == '/') {
                    415:                do {
                    416:                        cp++;
                    417:                } while (*cp == '/');
                    418:                slashes = cp - ndp->ni_next;
                    419:                ndp->ni_pathlen -= slashes;
                    420:                ndp->ni_next = cp;
                    421:                cnp->cn_flags |= REQUIREDIR;
                    422:        } else {
                    423:                slashes = 0;
                    424:                cnp->cn_flags &= ~REQUIREDIR;
                    425:        }
                    426:        /*
                    427:         * We do special processing on the last component, whether or not it's
                    428:         * a directory.  Cache all intervening lookups, but not the final one.
                    429:         */
                    430:        if (*cp == '\0') {
                    431:                if (docache)
                    432:                        cnp->cn_flags |= MAKEENTRY;
                    433:                else
                    434:                        cnp->cn_flags &= ~MAKEENTRY;
                    435:                cnp->cn_flags |= ISLASTCN;
                    436:        } else {
                    437:                cnp->cn_flags |= MAKEENTRY;
                    438:                cnp->cn_flags &= ~ISLASTCN;
                    439:        }
1.12      mycroft   440:        if (cnp->cn_namelen == 2 &&
                    441:            cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.')
                    442:                cnp->cn_flags |= ISDOTDOT;
                    443:        else
                    444:                cnp->cn_flags &= ~ISDOTDOT;
1.10      cgd       445:
                    446:        /*
                    447:         * Handle "..": two special cases.
                    448:         * 1. If at root directory (e.g. after chroot)
1.12      mycroft   449:         *    or at absolute root directory
1.10      cgd       450:         *    then ignore it so can't get out.
1.40      wrstuden  451:         * 1a. If we have somehow gotten out of a jail, warn
                    452:         *    and also ignore it so we can't get farther out.
1.10      cgd       453:         * 2. If this vnode is the root of a mounted
                    454:         *    filesystem, then replace it with the
                    455:         *    vnode which was mounted on so we take the
                    456:         *    .. in the other file system.
                    457:         */
1.12      mycroft   458:        if (cnp->cn_flags & ISDOTDOT) {
1.10      cgd       459:                for (;;) {
1.12      mycroft   460:                        if (dp == ndp->ni_rootdir || dp == rootvnode) {
1.10      cgd       461:                                ndp->ni_dvp = dp;
                    462:                                ndp->ni_vp = dp;
                    463:                                VREF(dp);
                    464:                                goto nextname;
1.40      wrstuden  465:                        }
                    466:                        if (ndp->ni_rootdir != rootvnode) {
                    467:                                int retval;
                    468:                                VOP_UNLOCK(dp, 0);
1.48      fvdl      469:                                retval = vn_isunder(dp, ndp->ni_rootdir,
                    470:                                    cnp->cn_proc);
1.40      wrstuden  471:                                vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
                    472:                                if (!retval) {
                    473:                                    /* Oops! We got out of jail! */
                    474:                                    log(LOG_WARNING,
                    475:                                        "chrooted pid %d uid %d (%s) "
                    476:                                        "detected outside of its chroot\n",
1.48      fvdl      477:                                        cnp->cn_proc->p_pid,
                    478:                                        cnp->cn_proc->p_ucred->cr_uid,
                    479:                                        cnp->cn_proc->p_comm);
1.40      wrstuden  480:                                    /* Put us at the jail root. */
                    481:                                    vput(dp);
                    482:                                    dp = ndp->ni_rootdir;
                    483:                                    ndp->ni_dvp = dp;
                    484:                                    ndp->ni_vp = dp;
                    485:                                    VREF(dp);
                    486:                                    VREF(dp);
                    487:                                    vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
                    488:                                    goto nextname;
                    489:                                }
1.10      cgd       490:                        }
                    491:                        if ((dp->v_flag & VROOT) == 0 ||
1.12      mycroft   492:                            (cnp->cn_flags & NOCROSSMOUNT))
1.10      cgd       493:                                break;
                    494:                        tdp = dp;
                    495:                        dp = dp->v_mount->mnt_vnodecovered;
                    496:                        vput(tdp);
                    497:                        VREF(dp);
1.26      fvdl      498:                        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.10      cgd       499:                }
                    500:        }
                    501:
                    502:        /*
                    503:         * We now have a segment name to search for, and a directory to search.
                    504:         */
1.12      mycroft   505: unionlookup:
                    506:        ndp->ni_dvp = dp;
1.26      fvdl      507:        ndp->ni_vp = NULL;
1.31      wrstuden  508:        cnp->cn_flags &= ~PDIRUNLOCK;
1.16      christos  509:        if ((error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) != 0) {
1.10      cgd       510: #ifdef DIAGNOSTIC
                    511:                if (ndp->ni_vp != NULL)
1.43      christos  512:                        panic("leaf `%s' should be empty", cnp->cn_nameptr);
1.52      yamt      513: #endif /* DIAGNOSTIC */
1.10      cgd       514: #ifdef NAMEI_DIAGNOSTIC
1.19      christos  515:                printf("not found\n");
1.52      yamt      516: #endif /* NAMEI_DIAGNOSTIC */
1.12      mycroft   517:                if ((error == ENOENT) &&
1.10      cgd       518:                    (dp->v_flag & VROOT) &&
                    519:                    (dp->v_mount->mnt_flag & MNT_UNION)) {
                    520:                        tdp = dp;
                    521:                        dp = dp->v_mount->mnt_vnodecovered;
1.31      wrstuden  522:                        if (cnp->cn_flags & PDIRUNLOCK)
                    523:                                vrele(tdp);
                    524:                        else
                    525:                                vput(tdp);
1.10      cgd       526:                        VREF(dp);
1.26      fvdl      527:                        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.12      mycroft   528:                        goto unionlookup;
1.10      cgd       529:                }
1.12      mycroft   530:
1.10      cgd       531:                if (error != EJUSTRETURN)
                    532:                        goto bad;
                    533:                /*
1.23      mycroft   534:                 * If this was not the last component, or there were trailing
1.51      christos  535:                 * slashes, and we are not going to create a directory,
                    536:                 * then the name must exist.
1.23      mycroft   537:                 */
1.51      christos  538:                if ((cnp->cn_flags & (REQUIREDIR | CREATEDIR)) == REQUIREDIR) {
1.23      mycroft   539:                        error = ENOENT;
                    540:                        goto bad;
                    541:                }
                    542:                /*
1.10      cgd       543:                 * If creating and at end of pathname, then can consider
                    544:                 * allowing file to be created.
                    545:                 */
1.26      fvdl      546:                if (rdonly) {
1.10      cgd       547:                        error = EROFS;
                    548:                        goto bad;
                    549:                }
                    550:                /*
                    551:                 * We return with ni_vp NULL to indicate that the entry
                    552:                 * doesn't currently exist, leaving a pointer to the
                    553:                 * (possibly locked) directory inode in ndp->ni_dvp.
                    554:                 */
1.12      mycroft   555:                if (cnp->cn_flags & SAVESTART) {
1.10      cgd       556:                        ndp->ni_startdir = ndp->ni_dvp;
                    557:                        VREF(ndp->ni_startdir);
                    558:                }
                    559:                return (0);
                    560:        }
                    561: #ifdef NAMEI_DIAGNOSTIC
1.19      christos  562:        printf("found\n");
1.52      yamt      563: #endif /* NAMEI_DIAGNOSTIC */
1.10      cgd       564:
1.12      mycroft   565:        /*
1.23      mycroft   566:         * Take into account any additional components consumed by the
                    567:         * underlying filesystem.  This will include any trailing slashes after
                    568:         * the last component consumed.
1.12      mycroft   569:         */
                    570:        if (cnp->cn_consume > 0) {
1.23      mycroft   571:                ndp->ni_pathlen -= cnp->cn_consume - slashes;
                    572:                ndp->ni_next += cnp->cn_consume - slashes;
1.12      mycroft   573:                cnp->cn_consume = 0;
1.23      mycroft   574:                if (ndp->ni_next[0] == '\0')
                    575:                        cnp->cn_flags |= ISLASTCN;
1.12      mycroft   576:        }
                    577:
1.10      cgd       578:        dp = ndp->ni_vp;
                    579:        /*
                    580:         * Check to see if the vnode has been mounted on;
                    581:         * if so find the root of the mounted file system.
                    582:         */
                    583:        while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
1.12      mycroft   584:               (cnp->cn_flags & NOCROSSMOUNT) == 0) {
1.26      fvdl      585:                if (vfs_busy(mp, 0, 0))
1.12      mycroft   586:                        continue;
1.32      wrstuden  587:                VOP_UNLOCK(dp, 0);
1.47      thorpej   588:                error = VFS_ROOT(mp, &tdp);
1.26      fvdl      589:                vfs_unbusy(mp);
1.32      wrstuden  590:                if (error) {
                    591:                        dpunlocked = 1;
1.10      cgd       592:                        goto bad2;
1.32      wrstuden  593:                }
                    594:                vrele(dp);
1.10      cgd       595:                ndp->ni_vp = dp = tdp;
1.14      mycroft   596:        }
                    597:
                    598:        /*
1.23      mycroft   599:         * Check for symbolic link.  Back up over any slashes that we skipped,
                    600:         * as we will need them again.
1.14      mycroft   601:         */
1.23      mycroft   602:        if ((dp->v_type == VLNK) && (cnp->cn_flags & (FOLLOW|REQUIREDIR))) {
                    603:                ndp->ni_pathlen += slashes;
                    604:                ndp->ni_next -= slashes;
1.14      mycroft   605:                cnp->cn_flags |= ISSYMLINK;
                    606:                return (0);
1.10      cgd       607:        }
                    608:
1.23      mycroft   609:        /*
                    610:         * Check for directory, if the component was followed by a series of
                    611:         * slashes.
                    612:         */
                    613:        if ((dp->v_type != VDIR) && (cnp->cn_flags & REQUIREDIR)) {
                    614:                error = ENOTDIR;
                    615:                goto bad2;
                    616:        }
                    617:
1.10      cgd       618: nextname:
                    619:        /*
1.23      mycroft   620:         * Not a symbolic link.  If this was not the last component, then
                    621:         * continue at the next component, else return.
1.10      cgd       622:         */
1.23      mycroft   623:        if (!(cnp->cn_flags & ISLASTCN)) {
1.12      mycroft   624:                cnp->cn_nameptr = ndp->ni_next;
1.10      cgd       625:                vrele(ndp->ni_dvp);
                    626:                goto dirloop;
                    627:        }
1.23      mycroft   628:
                    629: terminal:
1.10      cgd       630:        /*
1.26      fvdl      631:         * Disallow directory write attempts on read-only file systems.
1.10      cgd       632:         */
1.26      fvdl      633:        if (rdonly &&
                    634:            (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
1.10      cgd       635:                /*
                    636:                 * Disallow directory write attempts on read-only
                    637:                 * file systems.
                    638:                 */
1.26      fvdl      639:                error = EROFS;
                    640:                goto bad2;
1.10      cgd       641:        }
1.23      mycroft   642:        if (ndp->ni_dvp != NULL) {
                    643:                if (cnp->cn_flags & SAVESTART) {
                    644:                        ndp->ni_startdir = ndp->ni_dvp;
                    645:                        VREF(ndp->ni_startdir);
                    646:                }
                    647:                if (!wantparent)
                    648:                        vrele(ndp->ni_dvp);
1.10      cgd       649:        }
1.12      mycroft   650:        if ((cnp->cn_flags & LOCKLEAF) == 0)
1.26      fvdl      651:                VOP_UNLOCK(dp, 0);
1.10      cgd       652:        return (0);
                    653:
                    654: bad2:
1.31      wrstuden  655:        if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN) &&
                    656:                        ((cnp->cn_flags & PDIRUNLOCK) == 0))
1.26      fvdl      657:                VOP_UNLOCK(ndp->ni_dvp, 0);
1.10      cgd       658:        vrele(ndp->ni_dvp);
                    659: bad:
1.32      wrstuden  660:        if (dpunlocked)
                    661:                vrele(dp);
                    662:        else
                    663:                vput(dp);
1.10      cgd       664:        ndp->ni_vp = NULL;
1.12      mycroft   665:        return (error);
                    666: }
                    667:
                    668: /*
                    669:  * Reacquire a path name component.
                    670:  */
                    671: int
                    672: relookup(dvp, vpp, cnp)
                    673:        struct vnode *dvp, **vpp;
                    674:        struct componentname *cnp;
                    675: {
1.26      fvdl      676:        struct vnode *dp = 0;           /* the directory we are searching */
1.12      mycroft   677:        int wantparent;                 /* 1 => wantparent or lockparent flag */
                    678:        int rdonly;                     /* lookup read-only flag bit */
                    679:        int error = 0;
1.52      yamt      680: #ifdef DEBUG
1.54      hannken   681:        u_long newhash;                 /* DEBUG: check name hash */
1.41      soren     682:        const char *cp;                 /* DEBUG: check name ptr/len */
1.52      yamt      683: #endif /* DEBUG */
1.12      mycroft   684:
                    685:        /*
                    686:         * Setup: break out flag bits into variables.
                    687:         */
                    688:        wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
                    689:        rdonly = cnp->cn_flags & RDONLY;
                    690:        cnp->cn_flags &= ~ISSYMLINK;
                    691:        dp = dvp;
1.26      fvdl      692:        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.12      mycroft   693:
                    694: /* dirloop: */
                    695:        /*
                    696:         * Search a new directory.
                    697:         *
                    698:         * The cn_hash value is for use by vfs_cache.
                    699:         * The last component of the filename is left accessible via
                    700:         * cnp->cn_nameptr for callers that need the name. Callers needing
                    701:         * the name set the SAVENAME flag. When done, they assume
                    702:         * responsibility for freeing the pathname buffer.
                    703:         */
1.52      yamt      704: #ifdef DEBUG
1.39      lukem     705:        cp = NULL;
                    706:        newhash = namei_hash(cnp->cn_nameptr, &cp);
1.12      mycroft   707:        if (newhash != cnp->cn_hash)
                    708:                panic("relookup: bad hash");
                    709:        if (cnp->cn_namelen != cp - cnp->cn_nameptr)
                    710:                panic ("relookup: bad len");
1.53      yamt      711:        while (*cp == '/')
                    712:                cp++;
1.12      mycroft   713:        if (*cp != 0)
                    714:                panic("relookup: not last component");
1.52      yamt      715: #endif /* DEBUG */
                    716: #ifdef NAMEI_DIAGNOSTIC
1.19      christos  717:        printf("{%s}: ", cnp->cn_nameptr);
1.52      yamt      718: #endif /* NAMEI_DIAGNOSTIC */
1.12      mycroft   719:
                    720:        /*
                    721:         * Check for degenerate name (e.g. / or "")
                    722:         * which is a way of talking about a directory,
                    723:         * e.g. like "/." or ".".
                    724:         */
1.23      mycroft   725:        if (cnp->cn_nameptr[0] == '\0')
                    726:                panic("relookup: null name");
1.12      mycroft   727:
                    728:        if (cnp->cn_flags & ISDOTDOT)
                    729:                panic ("relookup: lookup on dot-dot");
                    730:
                    731:        /*
                    732:         * We now have a segment name to search for, and a directory to search.
                    733:         */
1.16      christos  734:        if ((error = VOP_LOOKUP(dp, vpp, cnp)) != 0) {
1.12      mycroft   735: #ifdef DIAGNOSTIC
                    736:                if (*vpp != NULL)
1.43      christos  737:                        panic("leaf `%s' should be empty", cnp->cn_nameptr);
1.12      mycroft   738: #endif
                    739:                if (error != EJUSTRETURN)
                    740:                        goto bad;
                    741:                /*
                    742:                 * If creating and at end of pathname, then can consider
                    743:                 * allowing file to be created.
                    744:                 */
1.26      fvdl      745:                if (rdonly) {
1.12      mycroft   746:                        error = EROFS;
                    747:                        goto bad;
                    748:                }
                    749:                /* ASSERT(dvp == ndp->ni_startdir) */
                    750:                if (cnp->cn_flags & SAVESTART)
                    751:                        VREF(dvp);
                    752:                /*
                    753:                 * We return with ni_vp NULL to indicate that the entry
                    754:                 * doesn't currently exist, leaving a pointer to the
                    755:                 * (possibly locked) directory inode in ndp->ni_dvp.
                    756:                 */
                    757:                return (0);
                    758:        }
                    759:        dp = *vpp;
                    760:
                    761: #ifdef DIAGNOSTIC
                    762:        /*
                    763:         * Check for symbolic link
                    764:         */
                    765:        if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
                    766:                panic ("relookup: symlink found.\n");
                    767: #endif
                    768:
                    769:        /*
                    770:         * Check for read-only file systems.
                    771:         */
1.26      fvdl      772:        if (rdonly &&
                    773:            (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
                    774:                error = EROFS;
                    775:                goto bad2;
1.12      mycroft   776:        }
                    777:        /* ASSERT(dvp == ndp->ni_startdir) */
                    778:        if (cnp->cn_flags & SAVESTART)
                    779:                VREF(dvp);
                    780:        if (!wantparent)
                    781:                vrele(dvp);
                    782:        if ((cnp->cn_flags & LOCKLEAF) == 0)
1.26      fvdl      783:                VOP_UNLOCK(dp, 0);
1.12      mycroft   784:        return (0);
                    785:
                    786: bad2:
                    787:        if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
1.26      fvdl      788:                VOP_UNLOCK(dvp, 0);
1.12      mycroft   789:        vrele(dvp);
                    790: bad:
                    791:        vput(dp);
                    792:        *vpp = NULL;
1.10      cgd       793:        return (error);
                    794: }

CVSweb <webmaster@jp.NetBSD.org>