Annotation of 43BSDReno/sys/kern/vfs_lookup.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution is only permitted until one year after the first shipment
        !             6:  * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
        !             7:  * binary forms are permitted provided that: (1) source distributions retain
        !             8:  * this entire copyright notice and comment, and (2) distributions including
        !             9:  * binaries display the following acknowledgement:  This product includes
        !            10:  * software developed by the University of California, Berkeley and its
        !            11:  * contributors'' in the documentation or other materials provided with the
        !            12:  * distribution and in all advertising materials mentioning features or use
        !            13:  * of this software.  Neither the name of the University nor the names of
        !            14:  * its contributors may be used to endorse or promote products derived from
        !            15:  * this software without specific prior written permission.
        !            16:  * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            17:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            18:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            19:  *
        !            20:  *     @(#)vfs_lookup.c        7.22 (Berkeley) 6/28/90
        !            21:  */
        !            22: 
        !            23: #include "param.h"
        !            24: #include "time.h"
        !            25: #include "namei.h"
        !            26: #include "vnode.h"
        !            27: #include "mount.h"
        !            28: #include "errno.h"
        !            29: #include "malloc.h"
        !            30: 
        !            31: #ifdef KTRACE
        !            32: #include "user.h"
        !            33: #include "proc.h"
        !            34: #include "ktrace.h"
        !            35: #endif
        !            36: 
        !            37: /*
        !            38:  * Convert a pathname into a pointer to a locked inode.
        !            39:  * This is a very central and rather complicated routine.
        !            40:  *
        !            41:  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
        !            42:  * whether the name is to be looked up, created, renamed, or deleted.
        !            43:  * When CREATE, RENAME, or DELETE is specified, information usable in
        !            44:  * creating, renaming, or deleting a directory entry may be calculated.
        !            45:  * If flag has LOCKPARENT or'ed into it and the target of the pathname
        !            46:  * exists, namei returns both the target and its parent directory locked.
        !            47:  * When creating or renaming and LOCKPARENT is specified, the target may not
        !            48:  * be ".".  When deleting and LOCKPARENT is specified, the target may be ".".
        !            49:  *
        !            50:  * The FOLLOW flag is set when symbolic links are to be followed
        !            51:  * when they occur at the end of the name translation process.
        !            52:  * Symbolic links are always followed for all other pathname
        !            53:  * components other than the last.
        !            54:  *
        !            55:  * The segflg defines whether the name is to be copied from user
        !            56:  * space or kernel space.
        !            57:  *
        !            58:  * Overall outline of namei:
        !            59:  *
        !            60:  *     copy in name
        !            61:  *     get starting directory
        !            62:  * dirloop:
        !            63:  *     copy next component of name to ndp->ni_dent
        !            64:  *     handle degenerate case where name is null string
        !            65:  *     if .. and on mounted filesys, find parent
        !            66:  *     call lookup routine for next component name
        !            67:  *       directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set
        !            68:  *       component vnode returned in ni_vp (if it exists), locked.
        !            69:  *     if symbolic link, massage name in buffer and continue at dirloop
        !            70:  *     if result inode is mounted on, find mounted on vnode
        !            71:  *     if more components of name, do next level at dirloop
        !            72:  *     return the answer in ni_vp as locked vnode;
        !            73:  *       if LOCKPARENT set, return locked parent in ni_dvp
        !            74:  *
        !            75:  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked.
        !            76:  */
        !            77: namei(ndp)
        !            78:        register struct nameidata *ndp;
        !            79: {
        !            80:        register char *cp;              /* pointer into pathname argument */
        !            81:        register struct vnode *dp = 0;  /* the directory we are searching */
        !            82:        register int i;                 /* Temp counter */
        !            83:        struct vnode *tdp;              /* saved dp */
        !            84:        struct mount *mp;               /* mount table entry */
        !            85:        int docache;                    /* == 0 do not cache last component */
        !            86:        int flag;                       /* LOOKUP, CREATE, RENAME or DELETE */
        !            87:        int wantparent;                 /* 1 => wantparent or lockparent flag */
        !            88:        int lockparent;                 /* 1 => lockparent flag */
        !            89:        int getbuf;                     /* 1 => Malloc a pathname buffer */
        !            90:        int rdonly;                     /* mounted read-only flag bit(s) */
        !            91:        int error = 0;
        !            92: 
        !            93:        /*
        !            94:         * Setup: break out flag bits into variables.
        !            95:         */
        !            96:        ndp->ni_dvp = NULL;
        !            97:        flag = ndp->ni_nameiop & OPFLAG;
        !            98:        wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
        !            99:        lockparent = ndp->ni_nameiop & LOCKPARENT;
        !           100:        docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
        !           101:        getbuf = (ndp->ni_nameiop & HASBUF) ^ HASBUF;
        !           102:        if (flag == DELETE || wantparent)
        !           103:                docache = 0;
        !           104:        rdonly = MNT_RDONLY;
        !           105:        if (ndp->ni_nameiop & REMOTE)
        !           106:                rdonly |= MNT_EXRDONLY;
        !           107:        /*
        !           108:         * Get a buffer for the name to be translated, and copy the
        !           109:         * name into the buffer.
        !           110:         */
        !           111:        if (getbuf) {
        !           112:                MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
        !           113:                if (ndp->ni_segflg == UIO_SYSSPACE)
        !           114:                        error = copystr(ndp->ni_dirp, ndp->ni_pnbuf,
        !           115:                                    MAXPATHLEN, &ndp->ni_pathlen);
        !           116:                else
        !           117:                        error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf,
        !           118:                                    MAXPATHLEN, &ndp->ni_pathlen);
        !           119:                if (error) {
        !           120:                        free(ndp->ni_pnbuf, M_NAMEI);
        !           121:                        ndp->ni_vp = NULL;
        !           122:                        return (error);
        !           123:                }
        !           124:                ndp->ni_ptr = ndp->ni_pnbuf;
        !           125:        }
        !           126:        ndp->ni_loopcnt = 0;
        !           127:        dp = ndp->ni_cdir;
        !           128:        VREF(dp);
        !           129: #ifdef KTRACE
        !           130:        if (KTRPOINT(u.u_procp, KTR_NAMEI))
        !           131:                ktrnamei(u.u_procp->p_tracep, ndp->ni_pnbuf);
        !           132: #endif
        !           133: 
        !           134: start:
        !           135:        /*
        !           136:         * Get starting directory.
        !           137:         * Done at start of translation and after symbolic link.
        !           138:         */
        !           139:        if (*ndp->ni_ptr == '/') {
        !           140:                vrele(dp);
        !           141:                while (*ndp->ni_ptr == '/') {
        !           142:                        ndp->ni_ptr++;
        !           143:                        ndp->ni_pathlen--;
        !           144:                }
        !           145:                if ((dp = ndp->ni_rdir) == NULL)
        !           146:                        dp = rootdir;
        !           147:                VREF(dp);
        !           148:        }
        !           149:        VOP_LOCK(dp);
        !           150:        ndp->ni_endoff = 0;
        !           151: 
        !           152:        /*
        !           153:         * We come to dirloop to search a new directory.
        !           154:         */
        !           155: dirloop:
        !           156:        /*
        !           157:         * Copy next component of name to ndp->ni_dent.
        !           158:         * XXX kern_exec looks at d_name
        !           159:         * ??? The ni_hash value may be useful for vfs_cache
        !           160:         * XXX There must be the last component of the filename left
        !           161:         * somewhere accessible via. ndp for NFS (and any other stateless file
        !           162:         * systems) in case they are doing a CREATE. The "Towards a..." noted
        !           163:         * that ni_ptr would be left pointing to the last component, but since
        !           164:         * the ni_pnbuf gets free'd, that is not a good idea.
        !           165:         */
        !           166:        if (getbuf) {
        !           167:                ndp->ni_hash = 0;
        !           168:                for (cp = ndp->ni_ptr, i = 0; *cp != 0 && *cp != '/'; cp++) {
        !           169:                        if (i >= MAXNAMLEN) {
        !           170:                                error = ENAMETOOLONG;
        !           171:                                goto bad;
        !           172:                        }
        !           173:                        if (*cp & 0200)
        !           174:                                if ((*cp&0377) == ('/'|0200) ||
        !           175:                                    flag != DELETE) {
        !           176:                                        error = EINVAL;
        !           177:                                        goto bad;
        !           178:                                }
        !           179:                        ndp->ni_dent.d_name[i++] = *cp;
        !           180:                        ndp->ni_hash += (unsigned char)*cp * i;
        !           181:                }
        !           182:                ndp->ni_namelen = i;
        !           183:                ndp->ni_dent.d_namlen = i;
        !           184:                ndp->ni_dent.d_name[i] = '\0';
        !           185:                ndp->ni_pathlen -= i;
        !           186:                ndp->ni_next = cp;
        !           187: #ifdef NAMEI_DIAGNOSTIC
        !           188:                printf("{%s}: ", ndp->ni_dent.d_name);
        !           189: #endif
        !           190:        }
        !           191:        cp = ndp->ni_next;
        !           192:        ndp->ni_makeentry = 1;
        !           193:        if (*cp == '\0' && docache == 0)
        !           194:                ndp->ni_makeentry = 0;
        !           195:        ndp->ni_isdotdot = (ndp->ni_namelen == 2 &&
        !           196:                ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.');
        !           197: 
        !           198:        /*
        !           199:         * Check for degenerate name (e.g. / or "")
        !           200:         * which is a way of talking about a directory,
        !           201:         * e.g. like "/." or ".".
        !           202:         */
        !           203:        if (ndp->ni_ptr[0] == '\0') {
        !           204:                if (flag != LOOKUP || wantparent) {
        !           205:                        error = EISDIR;
        !           206:                        goto bad;
        !           207:                }
        !           208:                if (getbuf)
        !           209:                        free(ndp->ni_pnbuf, M_NAMEI);
        !           210:                if (!(ndp->ni_nameiop & LOCKLEAF))
        !           211:                        VOP_UNLOCK(dp);
        !           212:                ndp->ni_vp = dp;
        !           213:                return (0);
        !           214:        }
        !           215: 
        !           216:        /*
        !           217:         * Handle "..": two special cases.
        !           218:         * 1. If at root directory (e.g. after chroot)
        !           219:         *    then ignore it so can't get out.
        !           220:         * 2. If this vnode is the root of a mounted
        !           221:         *    file system, then replace it with the
        !           222:         *    vnode which was mounted on so we take the
        !           223:         *    .. in the other file system.
        !           224:         */
        !           225:        if (ndp->ni_isdotdot) {
        !           226:                for (;;) {
        !           227:                        if (dp == ndp->ni_rdir || dp == rootdir) {
        !           228:                                ndp->ni_dvp = dp;
        !           229:                                ndp->ni_vp = dp;
        !           230:                                VREF(dp);
        !           231:                                goto nextname;
        !           232:                        }
        !           233:                        if ((dp->v_flag & VROOT) == 0 ||
        !           234:                                (ndp->ni_nameiop & NOCROSSMOUNT))
        !           235:                                break;
        !           236:                        tdp = dp;
        !           237:                        dp = dp->v_mount->mnt_vnodecovered;
        !           238:                        vput(tdp);
        !           239:                        VREF(dp);
        !           240:                        VOP_LOCK(dp);
        !           241:                }
        !           242:        }
        !           243: 
        !           244:        /*
        !           245:         * We now have a segment name to search for, and a directory to search.
        !           246:         */
        !           247:        if (error = VOP_LOOKUP(dp, ndp)) {
        !           248:                if (ndp->ni_vp != NULL)
        !           249:                        panic("leaf should be empty");
        !           250: #ifdef NAMEI_DIAGNOSTIC
        !           251:                printf("not found\n");
        !           252: #endif
        !           253:                if (flag == LOOKUP || flag == DELETE ||
        !           254:                    error != ENOENT || *cp != 0)
        !           255:                        goto bad;
        !           256:                /*
        !           257:                 * If creating and at end of pathname, then can consider
        !           258:                 * allowing file to be created.
        !           259:                 */
        !           260:                if (ndp->ni_dvp->v_mount->mnt_flag & rdonly) {
        !           261:                        error = EROFS;
        !           262:                        goto bad;
        !           263:                }
        !           264:                /*
        !           265:                 * We return with ni_vp NULL to indicate that the entry
        !           266:                 * doesn't currently exist, leaving a pointer to the
        !           267:                 * (possibly locked) directory inode in ndp->ni_dvp.
        !           268:                 */
        !           269:                if (getbuf)
        !           270:                        FREE(ndp->ni_pnbuf, M_NAMEI);
        !           271:                return (0);     /* should this be ENOENT? */
        !           272:        }
        !           273: #ifdef NAMEI_DIAGNOSTIC
        !           274:        printf("found\n");
        !           275: #endif
        !           276: 
        !           277:        /*
        !           278:         * Check for symbolic link
        !           279:         */
        !           280:        dp = ndp->ni_vp;
        !           281:        if ((dp->v_type == VLNK) &&
        !           282:            ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) {
        !           283:                struct iovec aiov;
        !           284:                struct uio auio;
        !           285:                int linklen;
        !           286: 
        !           287:                if (!getbuf)
        !           288:                        panic("namei: unexpected symlink");
        !           289:                if (++ndp->ni_loopcnt > MAXSYMLINKS) {
        !           290:                        error = ELOOP;
        !           291:                        goto bad2;
        !           292:                }
        !           293:                if (ndp->ni_pathlen > 1)
        !           294:                        MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
        !           295:                else
        !           296:                        cp = ndp->ni_pnbuf;
        !           297:                aiov.iov_base = cp;
        !           298:                aiov.iov_len = MAXPATHLEN;
        !           299:                auio.uio_iov = &aiov;
        !           300:                auio.uio_iovcnt = 1;
        !           301:                auio.uio_offset = 0;
        !           302:                auio.uio_rw = UIO_READ;
        !           303:                auio.uio_segflg = UIO_SYSSPACE;
        !           304:                auio.uio_resid = MAXPATHLEN;
        !           305:                if (error = VOP_READLINK(dp, &auio, ndp->ni_cred)) {
        !           306:                        if (ndp->ni_pathlen > 1)
        !           307:                                free(cp, M_NAMEI);
        !           308:                        goto bad2;
        !           309:                }
        !           310:                linklen = MAXPATHLEN - auio.uio_resid;
        !           311:                if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
        !           312:                        if (ndp->ni_pathlen > 1)
        !           313:                                free(cp, M_NAMEI);
        !           314:                        error = ENAMETOOLONG;
        !           315:                        goto bad2;
        !           316:                }
        !           317:                if (ndp->ni_pathlen > 1) {
        !           318:                        bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
        !           319:                        FREE(ndp->ni_pnbuf, M_NAMEI);
        !           320:                        ndp->ni_pnbuf = cp;
        !           321:                } else
        !           322:                        ndp->ni_pnbuf[linklen] = '\0';
        !           323:                ndp->ni_ptr = cp;
        !           324:                vput(dp);
        !           325:                dp = ndp->ni_dvp;
        !           326:                if (lockparent && ndp->ni_pathlen == 1)
        !           327:                        VOP_UNLOCK(dp);
        !           328:                ndp->ni_pathlen += linklen;
        !           329:                goto start;
        !           330:        }
        !           331: 
        !           332:        /*
        !           333:         * Check to see if the vnode has been mounted on;
        !           334:         * if so find the root of the mounted file system.
        !           335:         */
        !           336: mntloop:
        !           337:        while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
        !           338:               (ndp->ni_nameiop & NOCROSSMOUNT) == 0) {
        !           339:                while(mp->mnt_flag & MNT_MLOCK) {
        !           340:                        mp->mnt_flag |= MNT_MWAIT;
        !           341:                        sleep((caddr_t)mp, PVFS);
        !           342:                        goto mntloop;
        !           343:                }
        !           344:                error = VFS_ROOT(dp->v_mountedhere, &tdp);
        !           345:                if (error)
        !           346:                        goto bad2;
        !           347:                vput(dp);
        !           348:                ndp->ni_vp = dp = tdp;
        !           349:        }
        !           350: 
        !           351: nextname:
        !           352:        /*
        !           353:         * Not a symbolic link.  If more pathname,
        !           354:         * continue at next component, else return.
        !           355:         */
        !           356:        ndp->ni_ptr = ndp->ni_next;
        !           357:        if (*ndp->ni_ptr == '/') {
        !           358:                while (*ndp->ni_ptr == '/') {
        !           359:                        ndp->ni_ptr++;
        !           360:                        ndp->ni_pathlen--;
        !           361:                }
        !           362:                vrele(ndp->ni_dvp);
        !           363:                goto dirloop;
        !           364:        }
        !           365:        /*
        !           366:         * Check for read-only file systems.
        !           367:         */
        !           368:        if (flag == DELETE || flag == RENAME) {
        !           369:                /*
        !           370:                 * Disallow directory write attempts on read-only
        !           371:                 * file systems.
        !           372:                 */
        !           373:                if ((dp->v_mount->mnt_flag & rdonly) ||
        !           374:                    (wantparent && (ndp->ni_dvp->v_mount->mnt_flag & rdonly))) {
        !           375:                        error = EROFS;
        !           376:                        goto bad2;
        !           377:                }
        !           378:        }
        !           379:        if (!wantparent)
        !           380:                vrele(ndp->ni_dvp);
        !           381:        if ((ndp->ni_nameiop & LOCKLEAF) == 0)
        !           382:                VOP_UNLOCK(dp);
        !           383:        if (getbuf)
        !           384:                FREE(ndp->ni_pnbuf, M_NAMEI);
        !           385:        return (0);
        !           386: 
        !           387: bad2:
        !           388:        if (lockparent && *ndp->ni_next == '\0')
        !           389:                VOP_UNLOCK(ndp->ni_dvp);
        !           390:        vrele(ndp->ni_dvp);
        !           391: bad:
        !           392:        vput(dp);
        !           393:        ndp->ni_vp = NULL;
        !           394:        if (getbuf)
        !           395:                FREE(ndp->ni_pnbuf, M_NAMEI);
        !           396:        return (error);
        !           397: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.