[BACK]Return to ext2fs_lookup.c CVS log [TXT][DIR] Up to [local] / sys / ufs / ext2fs

Annotation of sys/ufs/ext2fs/ext2fs_lookup.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ext2fs_lookup.c,v 1.23 2007/06/17 20:15:25 jasper Exp $       */
        !             2: /*     $NetBSD: ext2fs_lookup.c,v 1.16 2000/08/03 20:29:26 thorpej Exp $       */
        !             3:
        !             4: /*
        !             5:  * Modified for NetBSD 1.2E
        !             6:  * May 1997, Manuel Bouyer
        !             7:  * Laboratoire d'informatique de Paris VI
        !             8:  */
        !             9: /*
        !            10:  *  modified for Lites 1.1
        !            11:  *
        !            12:  *  Aug 1995, Godmar Back (gback@cs.utah.edu)
        !            13:  *  University of Utah, Department of Computer Science
        !            14:  */
        !            15: /*
        !            16:  * Copyright (c) 1989, 1993
        !            17:  *     The Regents of the University of California.  All rights reserved.
        !            18:  * (c) UNIX System Laboratories, Inc.
        !            19:  * All or some portions of this file are derived from material licensed
        !            20:  * to the University of California by American Telephone and Telegraph
        !            21:  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
        !            22:  * the permission of UNIX System Laboratories, Inc.
        !            23:  *
        !            24:  * Redistribution and use in source and binary forms, with or without
        !            25:  * modification, are permitted provided that the following conditions
        !            26:  * are met:
        !            27:  * 1. Redistributions of source code must retain the above copyright
        !            28:  *    notice, this list of conditions and the following disclaimer.
        !            29:  * 2. Redistributions in binary form must reproduce the above copyright
        !            30:  *    notice, this list of conditions and the following disclaimer in the
        !            31:  *    documentation and/or other materials provided with the distribution.
        !            32:  * 3. Neither the name of the University nor the names of its contributors
        !            33:  *    may be used to endorse or promote products derived from this software
        !            34:  *    without specific prior written permission.
        !            35:  *
        !            36:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            37:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            38:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            39:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            40:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            41:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            42:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            43:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            44:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            45:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            46:  * SUCH DAMAGE.
        !            47:  *
        !            48:  *     @(#)ufs_lookup.c        8.6 (Berkeley) 4/1/94
        !            49:  */
        !            50:
        !            51: #include <sys/param.h>
        !            52: #include <sys/systm.h>
        !            53: #include <sys/namei.h>
        !            54: #include <sys/buf.h>
        !            55: #include <sys/file.h>
        !            56: #include <sys/mount.h>
        !            57: #include <sys/vnode.h>
        !            58: #include <sys/malloc.h>
        !            59: #include <sys/dirent.h>
        !            60:
        !            61: #include <ufs/ufs/quota.h>
        !            62: #include <ufs/ufs/inode.h>
        !            63: #include <ufs/ufs/ufsmount.h>
        !            64: #include <ufs/ufs/ufs_extern.h>
        !            65:
        !            66: #include <ufs/ext2fs/ext2fs_extern.h>
        !            67: #include <ufs/ext2fs/ext2fs_dir.h>
        !            68: #include <ufs/ext2fs/ext2fs.h>
        !            69:
        !            70: extern int dirchk;
        !            71:
        !            72: static void    ext2fs_dirconv2ffs(struct ext2fs_direct *e2dir,
        !            73:                                          struct dirent *ffsdir);
        !            74: static int     ext2fs_dirbadentry(struct vnode *dp,
        !            75:                                          struct ext2fs_direct *de,
        !            76:                                          int entryoffsetinblock);
        !            77:
        !            78: /*
        !            79:  * the problem that is tackled below is the fact that FFS
        !            80:  * includes the terminating zero on disk while EXT2FS doesn't
        !            81:  * this implies that we need to introduce some padding.
        !            82:  * For instance, a filename "sbin" has normally a reclen 12
        !            83:  * in EXT2, but 16 in FFS.
        !            84:  * This reminds me of that Pepsi commercial: 'Kid saved a lousy nine cents...'
        !            85:  * If it wasn't for that, the complete ufs code for directories would
        !            86:  * have worked w/o changes (except for the difference in DIRBLKSIZ)
        !            87:  */
        !            88: static void
        !            89: ext2fs_dirconv2ffs(struct ext2fs_direct        *e2dir, struct dirent *ffsdir)
        !            90: {
        !            91:        memset(ffsdir, 0, sizeof(struct dirent));
        !            92:        ffsdir->d_fileno = fs2h32(e2dir->e2d_ino);
        !            93:        ffsdir->d_namlen = e2dir->e2d_namlen;
        !            94:
        !            95:        ffsdir->d_type = DT_UNKNOWN;            /* don't know more here */
        !            96: #ifdef DIAGNOSTIC
        !            97:        /*
        !            98:         * XXX Rigth now this can't happen, but if one day
        !            99:         * MAXNAMLEN != E2FS_MAXNAMLEN we should handle this more gracefully !
        !           100:         */
        !           101:        /* XXX: e2d_namlen is to small for such comparison
        !           102:        if (e2dir->e2d_namlen > MAXNAMLEN)
        !           103:                panic("ext2fs: e2dir->e2d_namlen");
        !           104:        */
        !           105: #endif
        !           106:        strncpy(ffsdir->d_name, e2dir->e2d_name, ffsdir->d_namlen);
        !           107:
        !           108:        /* Godmar thinks: since e2dir->e2d_reclen can be big and means
        !           109:           nothing anyway, we compute our own reclen according to what
        !           110:           we think is right
        !           111:         */
        !           112:        ffsdir->d_reclen = DIRENT_SIZE(ffsdir);
        !           113: }
        !           114:
        !           115: /*
        !           116:  * Vnode op for reading directories.
        !           117:  *
        !           118:  * Convert the on-disk entries to <sys/dirent.h> entries.
        !           119:  * the problem is that the conversion will blow up some entries by four bytes,
        !           120:  * so it can't be done in place. This is too bad. Right now the conversion is
        !           121:  * done entry by entry, the converted entry is sent via uiomove.
        !           122:  *
        !           123:  * XXX allocate a buffer, convert as many entries as possible, then send
        !           124:  * the whole buffer to uiomove
        !           125:  */
        !           126: int
        !           127: ext2fs_readdir(void *v)
        !           128: {
        !           129:        struct vop_readdir_args *ap = v;
        !           130:        struct uio *uio = ap->a_uio;
        !           131:        int error;
        !           132:        size_t e2fs_count, readcnt, entries;
        !           133:        struct vnode *vp = ap->a_vp;
        !           134:        struct m_ext2fs *fs = VTOI(vp)->i_e2fs;
        !           135:
        !           136:        struct ext2fs_direct *dp;
        !           137:        struct dirent dstd;
        !           138:        struct uio auio;
        !           139:        struct iovec aiov;
        !           140:        caddr_t dirbuf;
        !           141:        off_t off = uio->uio_offset;
        !           142:        u_long *cookies = NULL;
        !           143:        int nc = 0, ncookies = 0;
        !           144:        int e2d_reclen;
        !           145:
        !           146:        if (vp->v_type != VDIR)
        !           147:                return (ENOTDIR);
        !           148:
        !           149:        e2fs_count = uio->uio_resid;
        !           150:        entries = (uio->uio_offset + e2fs_count) & (fs->e2fs_bsize - 1);
        !           151:
        !           152:        /* Make sure we don't return partial entries. */
        !           153:        if (e2fs_count <= entries)
        !           154:                return (EINVAL);
        !           155:
        !           156:        e2fs_count -= entries;
        !           157:        auio = *uio;
        !           158:        auio.uio_iov = &aiov;
        !           159:        auio.uio_iovcnt = 1;
        !           160:        auio.uio_segflg = UIO_SYSSPACE;
        !           161:        aiov.iov_len = e2fs_count;
        !           162:        auio.uio_resid = e2fs_count;
        !           163:        MALLOC(dirbuf, caddr_t, e2fs_count, M_TEMP, M_WAITOK);
        !           164:        if (ap->a_ncookies) {
        !           165:                nc = ncookies = e2fs_count / 16;
        !           166:                cookies = malloc(sizeof (off_t) * ncookies, M_TEMP, M_WAITOK);
        !           167:                *ap->a_cookies = cookies;
        !           168:        }
        !           169:        memset(dirbuf, 0, e2fs_count);
        !           170:        aiov.iov_base = dirbuf;
        !           171:
        !           172:        error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
        !           173:        if (error == 0) {
        !           174:                readcnt = e2fs_count - auio.uio_resid;
        !           175:                for (dp = (struct ext2fs_direct *)dirbuf;
        !           176:                        (char *)dp < (char *)dirbuf + readcnt; ) {
        !           177:                        e2d_reclen = fs2h16(dp->e2d_reclen);
        !           178:                        if (e2d_reclen == 0) {
        !           179:                                error = EIO;
        !           180:                                break;
        !           181:                        }
        !           182:                        ext2fs_dirconv2ffs(dp, &dstd);
        !           183:                        if(dstd.d_reclen > uio->uio_resid) {
        !           184:                                break;
        !           185:                        }
        !           186:                        if ((error = uiomove((caddr_t)&dstd, dstd.d_reclen, uio)) != 0) {
        !           187:                                break;
        !           188:                        }
        !           189:                        off = off + e2d_reclen;
        !           190:                        if (cookies != NULL) {
        !           191:                                *cookies++ = off;
        !           192:                                if (--ncookies <= 0){
        !           193:                                        break;  /* out of cookies */
        !           194:                                }
        !           195:                        }
        !           196:                        /* advance dp */
        !           197:                        dp = (struct ext2fs_direct *) ((char *)dp + e2d_reclen);
        !           198:                }
        !           199:                /* we need to correct uio_offset */
        !           200:                uio->uio_offset = off;
        !           201:        }
        !           202:        FREE(dirbuf, M_TEMP);
        !           203:        *ap->a_eofflag = ext2fs_size(VTOI(ap->a_vp)) <= uio->uio_offset;
        !           204:        if (ap->a_ncookies) {
        !           205:                if (error) {
        !           206:                        free(*ap->a_cookies, M_TEMP);
        !           207:                        *ap->a_ncookies = 0;
        !           208:                        *ap->a_cookies = NULL;
        !           209:                } else
        !           210:                        *ap->a_ncookies = nc - ncookies;
        !           211:        }
        !           212:        return (error);
        !           213: }
        !           214:
        !           215: /*
        !           216:  * Convert a component of a pathname into a pointer to a locked inode.
        !           217:  * This is a very central and rather complicated routine.
        !           218:  * If the file system is not maintained in a strict tree hierarchy,
        !           219:  * this can result in a deadlock situation (see comments in code below).
        !           220:  *
        !           221:  * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending
        !           222:  * on whether the name is to be looked up, created, renamed, or deleted.
        !           223:  * When CREATE, RENAME, or DELETE is specified, information usable in
        !           224:  * creating, renaming, or deleting a directory entry may be calculated.
        !           225:  * If flag has LOCKPARENT or'ed into it and the target of the pathname
        !           226:  * exists, lookup returns both the target and its parent directory locked.
        !           227:  * When creating or renaming and LOCKPARENT is specified, the target may
        !           228:  * not be ".".  When deleting and LOCKPARENT is specified, the target may
        !           229:  * be "."., but the caller must check to ensure it does an vrele and vput
        !           230:  * instead of two vputs.
        !           231:  *
        !           232:  * Overall outline of ext2fs_lookup:
        !           233:  *
        !           234:  *     check accessibility of directory
        !           235:  *     look for name in cache, if found, then if at end of path
        !           236:  *       and deleting or creating, drop it, else return name
        !           237:  *     search for name in directory, to found or notfound
        !           238:  * notfound:
        !           239:  *     if creating, return locked directory, leaving info on available slots
        !           240:  *     else return error
        !           241:  * found:
        !           242:  *     if at end of path and deleting, return information to allow delete
        !           243:  *     if at end of path and rewriting (RENAME and LOCKPARENT), lock target
        !           244:  *       inode and return info to allow rewrite
        !           245:  *     if not at end, add name to cache; if at end and neither creating
        !           246:  *       nor deleting, add name to cache
        !           247:  */
        !           248: int
        !           249: ext2fs_lookup(void *v)
        !           250: {
        !           251:        struct vop_lookup_args *ap = v;
        !           252:        struct vnode *vdp;      /* vnode for directory being searched */
        !           253:        struct inode *dp;       /* inode for directory being searched */
        !           254:        struct buf *bp;                 /* a buffer of directory entries */
        !           255:        struct ext2fs_direct *ep; /* the current directory entry */
        !           256:        int entryoffsetinblock;         /* offset of ep in bp's buffer */
        !           257:        enum {NONE, COMPACT, FOUND} slotstatus;
        !           258:        doff_t slotoffset;              /* offset of area with free space */
        !           259:        int slotsize;                   /* size of area at slotoffset */
        !           260:        int slotfreespace;              /* amount of space free in slot */
        !           261:        int slotneeded;                 /* size of the entry we're seeking */
        !           262:        int numdirpasses;               /* strategy for directory search */
        !           263:        doff_t endsearch;               /* offset to end directory search */
        !           264:        doff_t prevoff;                 /* prev entry dp->i_offset */
        !           265:        struct vnode *pdp;              /* saved dp during symlink work */
        !           266:        struct vnode *tdp;              /* returned by VFS_VGET */
        !           267:        doff_t enduseful;               /* pointer past last used dir slot */
        !           268:        u_long bmask;                   /* block offset mask */
        !           269:        int lockparent;                 /* 1 => lockparent flag is set */
        !           270:        int wantparent;                 /* 1 => wantparent or lockparent flag */
        !           271:        int namlen, error;
        !           272:        struct vnode **vpp = ap->a_vpp;
        !           273:        struct componentname *cnp = ap->a_cnp;
        !           274:        struct ucred *cred = cnp->cn_cred;
        !           275:        int flags = cnp->cn_flags;
        !           276:        int nameiop = cnp->cn_nameiop;
        !           277:        struct proc *p = cnp->cn_proc;
        !           278:        int     dirblksize = VTOI(ap->a_dvp)->i_e2fs->e2fs_bsize;
        !           279:
        !           280:        bp = NULL;
        !           281:        slotoffset = -1;
        !           282:        *vpp = NULL;
        !           283:        vdp = ap->a_dvp;
        !           284:        dp = VTOI(vdp);
        !           285:        lockparent = flags & LOCKPARENT;
        !           286:        wantparent = flags & (LOCKPARENT|WANTPARENT);
        !           287:        /*
        !           288:         * Check accessiblity of directory.
        !           289:         */
        !           290:        if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0)
        !           291:                return (error);
        !           292:
        !           293:        if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
        !           294:            (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
        !           295:                return (EROFS);
        !           296:
        !           297:        /*
        !           298:         * We now have a segment name to search for, and a directory to search.
        !           299:         *
        !           300:         * Before tediously performing a linear scan of the directory,
        !           301:         * check the name cache to see if the directory/name pair
        !           302:         * we are looking for is known already.
        !           303:         */
        !           304:        if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
        !           305:                return (error);
        !           306:
        !           307:        /*
        !           308:         * Suppress search for slots unless creating
        !           309:         * file and at end of pathname, in which case
        !           310:         * we watch for a place to put the new file in
        !           311:         * case it doesn't already exist.
        !           312:         */
        !           313:        slotstatus = FOUND;
        !           314:        slotfreespace = slotsize = slotneeded = 0;
        !           315:        if ((nameiop == CREATE || nameiop == RENAME) &&
        !           316:                (flags & ISLASTCN)) {
        !           317:                slotstatus = NONE;
        !           318:                slotneeded = EXT2FS_DIRSIZ(cnp->cn_namelen);
        !           319:        }
        !           320:
        !           321:        /*
        !           322:         * If there is cached information on a previous search of
        !           323:         * this directory, pick up where we last left off.
        !           324:         * We cache only lookups as these are the most common
        !           325:         * and have the greatest payoff. Caching CREATE has little
        !           326:         * benefit as it usually must search the entire directory
        !           327:         * to determine that the entry does not exist. Caching the
        !           328:         * location of the last DELETE or RENAME has not reduced
        !           329:         * profiling time and hence has been removed in the interest
        !           330:         * of simplicity.
        !           331:         */
        !           332:        bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
        !           333:        if (nameiop != LOOKUP || dp->i_diroff == 0 ||
        !           334:                dp->i_diroff >ext2fs_size(dp)) {
        !           335:                entryoffsetinblock = 0;
        !           336:                dp->i_offset = 0;
        !           337:                numdirpasses = 1;
        !           338:        } else {
        !           339:                dp->i_offset = dp->i_diroff;
        !           340:                if ((entryoffsetinblock = dp->i_offset & bmask) &&
        !           341:                        (error = ext2fs_bufatoff(dp, (off_t)dp->i_offset,
        !           342:                            NULL, &bp)))
        !           343:                        return (error);
        !           344:                numdirpasses = 2;
        !           345:        }
        !           346:        prevoff = dp->i_offset;
        !           347:        endsearch = roundup(ext2fs_size(dp), dirblksize);
        !           348:        enduseful = 0;
        !           349:
        !           350: searchloop:
        !           351:        while (dp->i_offset < endsearch) {
        !           352:                /*
        !           353:                 * If necessary, get the next directory block.
        !           354:                 */
        !           355:                if ((dp->i_offset & bmask) == 0) {
        !           356:                        if (bp != NULL)
        !           357:                                brelse(bp);
        !           358:                        error = ext2fs_bufatoff(dp, (off_t)dp->i_offset,
        !           359:                            NULL, &bp);
        !           360:                        if (error != 0)
        !           361:                                return (error);
        !           362:                        entryoffsetinblock = 0;
        !           363:                }
        !           364:                /*
        !           365:                 * If still looking for a slot, and at a dirblksize
        !           366:                 * boundary, have to start looking for free space again.
        !           367:                 */
        !           368:                if (slotstatus == NONE &&
        !           369:                        (entryoffsetinblock & (dirblksize - 1)) == 0) {
        !           370:                        slotoffset = -1;
        !           371:                        slotfreespace = 0;
        !           372:                }
        !           373:                /*
        !           374:                 * Get pointer to next entry.
        !           375:                 * Full validation checks are slow, so we only check
        !           376:                 * enough to insure forward progress through the
        !           377:                 * directory. Complete checks can be run by patching
        !           378:                 * "dirchk" to be true.
        !           379:                 */
        !           380:                ep = (struct ext2fs_direct *)
        !           381:                        ((char *)bp->b_data + entryoffsetinblock);
        !           382:                if (ep->e2d_reclen == 0 ||
        !           383:                    (dirchk &&
        !           384:                    ext2fs_dirbadentry(vdp, ep, entryoffsetinblock))) {
        !           385:                        int i;
        !           386:                        ufs_dirbad(dp, dp->i_offset, "mangled entry");
        !           387:                        i = dirblksize -
        !           388:                            (entryoffsetinblock & (dirblksize - 1));
        !           389:                        dp->i_offset += i;
        !           390:                        entryoffsetinblock += i;
        !           391:                        continue;
        !           392:                }
        !           393:
        !           394:                /*
        !           395:                 * If an appropriate sized slot has not yet been found,
        !           396:                 * check to see if one is available. Also accumulate space
        !           397:                 * in the current block so that we can determine if
        !           398:                 * compaction is viable.
        !           399:                 */
        !           400:                if (slotstatus != FOUND) {
        !           401:                        int size = fs2h16(ep->e2d_reclen);
        !           402:
        !           403:                        if (ep->e2d_ino != 0)
        !           404:                                size -= EXT2FS_DIRSIZ(ep->e2d_namlen);
        !           405:                        if (size > 0) {
        !           406:                                if (size >= slotneeded) {
        !           407:                                        slotstatus = FOUND;
        !           408:                                        slotoffset = dp->i_offset;
        !           409:                                        slotsize = fs2h16(ep->e2d_reclen);
        !           410:                                } else if (slotstatus == NONE) {
        !           411:                                        slotfreespace += size;
        !           412:                                        if (slotoffset == -1)
        !           413:                                                slotoffset = dp->i_offset;
        !           414:                                        if (slotfreespace >= slotneeded) {
        !           415:                                                slotstatus = COMPACT;
        !           416:                                                slotsize = dp->i_offset +
        !           417:                                                          fs2h16(ep->e2d_reclen) - slotoffset;
        !           418:                                        }
        !           419:                                }
        !           420:                        }
        !           421:                }
        !           422:
        !           423:                /*
        !           424:                 * Check for a name match.
        !           425:                 */
        !           426:                if (ep->e2d_ino) {
        !           427:                        namlen = ep->e2d_namlen;
        !           428:                        if (namlen == cnp->cn_namelen &&
        !           429:                                !memcmp(cnp->cn_nameptr, ep->e2d_name,
        !           430:                                (unsigned)namlen)) {
        !           431:                                /*
        !           432:                                 * Save directory entry's inode number and
        !           433:                                 * reclen in ndp->ni_ufs area, and release
        !           434:                                 * directory buffer.
        !           435:                                 */
        !           436:                                dp->i_ino = fs2h32(ep->e2d_ino);
        !           437:                                dp->i_reclen = fs2h16(ep->e2d_reclen);
        !           438:                                brelse(bp);
        !           439:                                goto found;
        !           440:                        }
        !           441:                }
        !           442:                prevoff = dp->i_offset;
        !           443:                dp->i_offset += fs2h16(ep->e2d_reclen);
        !           444:                entryoffsetinblock += fs2h16(ep->e2d_reclen);
        !           445:                if (ep->e2d_ino)
        !           446:                        enduseful = dp->i_offset;
        !           447:        }
        !           448: /* notfound: */
        !           449:        /*
        !           450:         * If we started in the middle of the directory and failed
        !           451:         * to find our target, we must check the beginning as well.
        !           452:         */
        !           453:        if (numdirpasses == 2) {
        !           454:                numdirpasses--;
        !           455:                dp->i_offset = 0;
        !           456:                endsearch = dp->i_diroff;
        !           457:                goto searchloop;
        !           458:        }
        !           459:        if (bp != NULL)
        !           460:                brelse(bp);
        !           461:        /*
        !           462:         * If creating, and at end of pathname and current
        !           463:         * directory has not been removed, then can consider
        !           464:         * allowing file to be created.
        !           465:         */
        !           466:        if ((nameiop == CREATE || nameiop == RENAME) &&
        !           467:                (flags & ISLASTCN) && dp->i_e2fs_nlink != 0) {
        !           468:                /*
        !           469:                 * Creation of files on a read-only mounted file system
        !           470:                 * is pointless, so don't proceed any further.
        !           471:                 */
        !           472:                if (vdp->v_mount->mnt_flag & MNT_RDONLY)
        !           473:                                        return (EROFS);
        !           474:                /*
        !           475:                 * Access for write is interpreted as allowing
        !           476:                 * creation of files in the directory.
        !           477:                 */
        !           478:                if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
        !           479:                        return (error);
        !           480:                /*
        !           481:                 * Return an indication of where the new directory
        !           482:                 * entry should be put.  If we didn't find a slot,
        !           483:                 * then set dp->i_count to 0 indicating
        !           484:                 * that the new slot belongs at the end of the
        !           485:                 * directory. If we found a slot, then the new entry
        !           486:                 * can be put in the range from dp->i_offset to
        !           487:                 * dp->i_offset + dp->i_count.
        !           488:                 */
        !           489:                if (slotstatus == NONE) {
        !           490:                        dp->i_offset = roundup(ext2fs_size(dp), dirblksize);
        !           491:                        dp->i_count = 0;
        !           492:                        enduseful = dp->i_offset;
        !           493:                } else {
        !           494:                        dp->i_offset = slotoffset;
        !           495:                        dp->i_count = slotsize;
        !           496:                        if (enduseful < slotoffset + slotsize)
        !           497:                                enduseful = slotoffset + slotsize;
        !           498:                }
        !           499:                dp->i_endoff = roundup(enduseful, dirblksize);
        !           500:                dp->i_flag |= IN_CHANGE | IN_UPDATE;
        !           501:                /*
        !           502:                 * We return with the directory locked, so that
        !           503:                 * the parameters we set up above will still be
        !           504:                 * valid if we actually decide to do a direnter().
        !           505:                 * We return ni_vp == NULL to indicate that the entry
        !           506:                 * does not currently exist; we leave a pointer to
        !           507:                 * the (locked) directory inode in ndp->ni_dvp.
        !           508:                 * The pathname buffer is saved so that the name
        !           509:                 * can be obtained later.
        !           510:                 *
        !           511:                 * NB - if the directory is unlocked, then this
        !           512:                 * information cannot be used.
        !           513:                 */
        !           514:                cnp->cn_flags |= SAVENAME;
        !           515:                if (!lockparent) {
        !           516:                        VOP_UNLOCK(vdp, 0, p);
        !           517:                        cnp->cn_flags |= PDIRUNLOCK;
        !           518:                }
        !           519:                return (EJUSTRETURN);
        !           520:        }
        !           521:        /*
        !           522:         * Insert name into cache (as non-existent) if appropriate.
        !           523:         */
        !           524:        if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
        !           525:                cache_enter(vdp, *vpp, cnp);
        !           526:        return (ENOENT);
        !           527:
        !           528: found:
        !           529:        /*
        !           530:         * Check that directory length properly reflects presence
        !           531:         * of this entry.
        !           532:         */
        !           533:        if (entryoffsetinblock + EXT2FS_DIRSIZ(ep->e2d_namlen)
        !           534:            > ext2fs_size(dp)) {
        !           535:                ufs_dirbad(dp, dp->i_offset, "i_size too small");
        !           536:                error = ext2fs_setsize(dp,
        !           537:                        entryoffsetinblock + EXT2FS_DIRSIZ(ep->e2d_namlen));
        !           538:                if (error) {
        !           539:                        brelse(bp);
        !           540:                        return(error);
        !           541:                }
        !           542:                dp->i_flag |= IN_CHANGE | IN_UPDATE;
        !           543:        }
        !           544:
        !           545:        /*
        !           546:         * Found component in pathname.
        !           547:         * If the final component of path name, save information
        !           548:         * in the cache as to where the entry was found.
        !           549:         */
        !           550:        if ((flags & ISLASTCN) && nameiop == LOOKUP)
        !           551:                dp->i_diroff = dp->i_offset &~ (dirblksize - 1);
        !           552:
        !           553:        /*
        !           554:         * If deleting, and at end of pathname, return
        !           555:         * parameters which can be used to remove file.
        !           556:         * If the wantparent flag isn't set, we return only
        !           557:         * the directory (in ndp->ni_dvp), otherwise we go
        !           558:         * on and lock the inode, being careful with ".".
        !           559:         */
        !           560:        if (nameiop == DELETE && (flags & ISLASTCN)) {
        !           561:                /*
        !           562:                 * Write access to directory required to delete files.
        !           563:                 */
        !           564:                if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
        !           565:                        return (error);
        !           566:                /*
        !           567:                 * Return pointer to current entry in dp->i_offset,
        !           568:                 * and distance past previous entry (if there
        !           569:                 * is a previous entry in this block) in dp->i_count.
        !           570:                 * Save directory inode pointer in ndp->ni_dvp for dirremove().
        !           571:                 */
        !           572:                if ((dp->i_offset & (dirblksize - 1)) == 0)
        !           573:                        dp->i_count = 0;
        !           574:                else
        !           575:                        dp->i_count = dp->i_offset - prevoff;
        !           576:                if (dp->i_number == dp->i_ino) {
        !           577:                        VREF(vdp);
        !           578:                        *vpp = vdp;
        !           579:                        return (0);
        !           580:                }
        !           581:                if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
        !           582:                        return (error);
        !           583:                /*
        !           584:                 * If directory is "sticky", then user must own
        !           585:                 * the directory, or the file in it, else she
        !           586:                 * may not delete it (unless she's root). This
        !           587:                 * implements append-only directories.
        !           588:                 */
        !           589:                if ((dp->i_e2fs_mode & ISVTX) &&
        !           590:                        cred->cr_uid != 0 &&
        !           591:                        cred->cr_uid != dp->i_e2fs_uid &&
        !           592:                        VTOI(tdp)->i_e2fs_uid != cred->cr_uid) {
        !           593:                        vput(tdp);
        !           594:                        return (EPERM);
        !           595:                }
        !           596:                *vpp = tdp;
        !           597:                if (!lockparent) {
        !           598:                        VOP_UNLOCK(vdp, 0, p);
        !           599:                        cnp->cn_flags |= PDIRUNLOCK;
        !           600:                }
        !           601:                return (0);
        !           602:        }
        !           603:
        !           604:        /*
        !           605:         * If rewriting (RENAME), return the inode and the
        !           606:         * information required to rewrite the present directory
        !           607:         * Must get inode of directory entry to verify it's a
        !           608:         * regular file, or empty directory.
        !           609:         */
        !           610:        if (nameiop == RENAME && wantparent &&
        !           611:                (flags & ISLASTCN)) {
        !           612:                if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
        !           613:                        return (error);
        !           614:                /*
        !           615:                 * Careful about locking second inode.
        !           616:                 * This can only occur if the target is ".".
        !           617:                 */
        !           618:                if (dp->i_number == dp->i_ino)
        !           619:                        return (EISDIR);
        !           620:                if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
        !           621:                        return (error);
        !           622:                *vpp = tdp;
        !           623:                cnp->cn_flags |= SAVENAME;
        !           624:                if (!lockparent) {
        !           625:                        VOP_UNLOCK(vdp, 0, p);
        !           626:                        cnp->cn_flags |= PDIRUNLOCK;
        !           627:                }
        !           628:                return (0);
        !           629:        }
        !           630:
        !           631:        /*
        !           632:         * Step through the translation in the name.  We do not `vput' the
        !           633:         * directory because we may need it again if a symbolic link
        !           634:         * is relative to the current directory.  Instead we save it
        !           635:         * unlocked as "pdp".  We must get the target inode before unlocking
        !           636:         * the directory to insure that the inode will not be removed
        !           637:         * before we get it.  We prevent deadlock by always fetching
        !           638:         * inodes from the root, moving down the directory tree. Thus
        !           639:         * when following backward pointers ".." we must unlock the
        !           640:         * parent directory before getting the requested directory.
        !           641:         * There is a potential race condition here if both the current
        !           642:         * and parent directories are removed before the VFS_VGET for the
        !           643:         * inode associated with ".." returns.  We hope that this occurs
        !           644:         * infrequently since we cannot avoid this race condition without
        !           645:         * implementing a sophisticated deadlock detection algorithm.
        !           646:         * Note also that this simple deadlock detection scheme will not
        !           647:         * work if the file system has any hard links other than ".."
        !           648:         * that point backwards in the directory structure.
        !           649:         */
        !           650:        pdp = vdp;
        !           651:        if (flags & ISDOTDOT) {
        !           652:                VOP_UNLOCK(pdp, 0, p);  /* race to get the inode */
        !           653:                cnp->cn_flags |= PDIRUNLOCK;
        !           654:                if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) {
        !           655:                        if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
        !           656:                                cnp->cn_flags &= ~PDIRUNLOCK;
        !           657:                        return (error);
        !           658:                }
        !           659:                if (lockparent && (flags & ISLASTCN)) {
        !           660:                        if ((error = vn_lock(pdp, LK_EXCLUSIVE, p)) != 0) {
        !           661:                                vput(tdp);
        !           662:                                return (error);
        !           663:                        }
        !           664:                        cnp->cn_flags &= ~PDIRUNLOCK;
        !           665:                }
        !           666:                *vpp = tdp;
        !           667:        } else if (dp->i_number == dp->i_ino) {
        !           668:                VREF(vdp);      /* we want ourself, ie "." */
        !           669:                *vpp = vdp;
        !           670:        } else {
        !           671:                if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0)
        !           672:                        return (error);
        !           673:                if (!lockparent || !(flags & ISLASTCN)) {
        !           674:                        VOP_UNLOCK(pdp, 0, p);
        !           675:                        cnp->cn_flags |= PDIRUNLOCK;
        !           676:                }
        !           677:                *vpp = tdp;
        !           678:        }
        !           679:
        !           680:        /*
        !           681:         * Insert name into cache if appropriate.
        !           682:         */
        !           683:        if (cnp->cn_flags & MAKEENTRY)
        !           684:                cache_enter(vdp, *vpp, cnp);
        !           685:        return (0);
        !           686: }
        !           687:
        !           688: /*
        !           689:  * Do consistency checking on a directory entry:
        !           690:  *     record length must be multiple of 4
        !           691:  *     entry must fit in rest of its dirblksize block
        !           692:  *     record must be large enough to contain entry
        !           693:  *     name is not longer than MAXNAMLEN
        !           694:  *     name must be as long as advertised, and null terminated
        !           695:  */
        !           696: /*
        !           697:  *     changed so that it confirms to ext2fs_check_dir_entry
        !           698:  */
        !           699: static int
        !           700: ext2fs_dirbadentry(struct vnode *dp, struct ext2fs_direct *de,
        !           701:     int entryoffsetinblock)
        !           702: {
        !           703:        int     dirblksize = VTOI(dp)->i_e2fs->e2fs_bsize;
        !           704:
        !           705:                char * error_msg = NULL;
        !           706:                int reclen = fs2h16(de->e2d_reclen);
        !           707:                int namlen = de->e2d_namlen;
        !           708:
        !           709:                if (reclen < EXT2FS_DIRSIZ(1)) /* e2d_namlen = 1 */
        !           710:                                error_msg = "rec_len is smaller than minimal";
        !           711:                else if (reclen % 4 != 0)
        !           712:                                error_msg = "rec_len % 4 != 0";
        !           713:                else if (reclen < EXT2FS_DIRSIZ(namlen))
        !           714:                                error_msg = "reclen is too small for name_len";
        !           715:                else if (entryoffsetinblock + reclen > dirblksize)
        !           716:                                error_msg = "directory entry across blocks";
        !           717:                else if (fs2h32(de->e2d_ino) >
        !           718:                    VTOI(dp)->i_e2fs->e2fs.e2fs_icount)
        !           719:                                error_msg = "inode out of bounds";
        !           720:
        !           721:                if (error_msg != NULL) {
        !           722:                        printf( "bad directory entry: %s\n"
        !           723:                            "offset=%d, inode=%lu, rec_len=%d, name_len=%d \n",
        !           724:                            error_msg, entryoffsetinblock,
        !           725:                            (unsigned long) fs2h32(de->e2d_ino),
        !           726:                            reclen, namlen);
        !           727:                        panic("ext2fs_dirbadentry");
        !           728:                }
        !           729:                return error_msg == NULL ? 0 : 1;
        !           730: }
        !           731:
        !           732: /*
        !           733:  * Write a directory entry after a call to namei, using the parameters
        !           734:  * that it left in nameidata.  The argument ip is the inode which the new
        !           735:  * directory entry will refer to.  Dvp is a pointer to the directory to
        !           736:  * be written, which was left locked by namei. Remaining parameters
        !           737:  * (dp->i_offset, dp->i_count) indicate how the space for the new
        !           738:  * entry is to be obtained.
        !           739:  */
        !           740: int
        !           741: ext2fs_direnter(struct inode *ip, struct vnode *dvp,
        !           742:     struct componentname *cnp)
        !           743: {
        !           744:        struct ext2fs_direct *ep, *nep;
        !           745:        struct inode *dp;
        !           746:        struct buf *bp;
        !           747:        struct ext2fs_direct newdir;
        !           748:        struct iovec aiov;
        !           749:        struct uio auio;
        !           750:        u_int dsize;
        !           751:        int error, loc, newentrysize, spacefree;
        !           752:        char *dirbuf;
        !           753:        int dirblksize = ip->i_e2fs->e2fs_bsize;
        !           754:
        !           755:
        !           756: #ifdef DIAGNOSTIC
        !           757:        if ((cnp->cn_flags & SAVENAME) == 0)
        !           758:                panic("direnter: missing name");
        !           759: #endif
        !           760:        dp = VTOI(dvp);
        !           761:        newdir.e2d_ino = h2fs32(ip->i_number);
        !           762:        newdir.e2d_namlen = cnp->cn_namelen;
        !           763:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
        !           764:            (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
        !           765:                newdir.e2d_type = inot2ext2dt(IFTODT(ip->i_e2fs_mode));
        !           766:        } else {
        !           767:                newdir.e2d_type = 0;
        !           768:        };
        !           769:        memcpy(newdir.e2d_name, cnp->cn_nameptr, (unsigned)cnp->cn_namelen + 1);
        !           770:        newentrysize = EXT2FS_DIRSIZ(cnp->cn_namelen);
        !           771:        if (dp->i_count == 0) {
        !           772:                /*
        !           773:                 * If dp->i_count is 0, then namei could find no
        !           774:                 * space in the directory. Here, dp->i_offset will
        !           775:                 * be on a directory block boundary and we will write the
        !           776:                 * new entry into a fresh block.
        !           777:                 */
        !           778:                if (dp->i_offset & (dirblksize - 1))
        !           779:                        panic("ext2fs_direnter: newblk");
        !           780:                auio.uio_offset = dp->i_offset;
        !           781:                newdir.e2d_reclen = h2fs16(dirblksize);
        !           782:                auio.uio_resid = newentrysize;
        !           783:                aiov.iov_len = newentrysize;
        !           784:                aiov.iov_base = (caddr_t)&newdir;
        !           785:                auio.uio_iov = &aiov;
        !           786:                auio.uio_iovcnt = 1;
        !           787:                auio.uio_rw = UIO_WRITE;
        !           788:                auio.uio_segflg = UIO_SYSSPACE;
        !           789:                auio.uio_procp = (struct proc *)0;
        !           790:                error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred);
        !           791:                if (dirblksize >
        !           792:                        VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
        !           793:                        /* XXX should grow with balloc() */
        !           794:                        panic("ext2fs_direnter: frag size");
        !           795:                else if (!error) {
        !           796:                        error = ext2fs_setsize(dp,
        !           797:                                roundup(ext2fs_size(dp), dirblksize));
        !           798:                        if (error)
        !           799:                                return (error);
        !           800:                        dp->i_flag |= IN_CHANGE;
        !           801:                }
        !           802:                return (error);
        !           803:        }
        !           804:
        !           805:        /*
        !           806:         * If dp->i_count is non-zero, then namei found space
        !           807:         * for the new entry in the range dp->i_offset to
        !           808:         * dp->i_offset + dp->i_count in the directory.
        !           809:         * To use this space, we may have to compact the entries located
        !           810:         * there, by copying them together towards the beginning of the
        !           811:         * block, leaving the free space in one usable chunk at the end.
        !           812:         */
        !           813:
        !           814:        /*
        !           815:         * Get the block containing the space for the new directory entry.
        !           816:         */
        !           817:        if ((error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, &dirbuf, &bp))
        !           818:            != 0)
        !           819:                return (error);
        !           820:        /*
        !           821:         * Find space for the new entry. In the simple case, the entry at
        !           822:         * offset base will have the space. If it does not, then namei
        !           823:         * arranged that compacting the region dp->i_offset to
        !           824:         * dp->i_offset + dp->i_count would yield the
        !           825:         * space.
        !           826:         */
        !           827:        ep = (struct ext2fs_direct *)dirbuf;
        !           828:        dsize = EXT2FS_DIRSIZ(ep->e2d_namlen);
        !           829:        spacefree = fs2h16(ep->e2d_reclen) - dsize;
        !           830:        for (loc = fs2h16(ep->e2d_reclen); loc < dp->i_count; ) {
        !           831:                nep = (struct ext2fs_direct *)(dirbuf + loc);
        !           832:                if (ep->e2d_ino) {
        !           833:                        /* trim the existing slot */
        !           834:                        ep->e2d_reclen = h2fs16(dsize);
        !           835:                        ep = (struct ext2fs_direct *)((char *)ep + dsize);
        !           836:                } else {
        !           837:                        /* overwrite; nothing there; header is ours */
        !           838:                        spacefree += dsize;
        !           839:                }
        !           840:                dsize = EXT2FS_DIRSIZ(nep->e2d_namlen);
        !           841:                spacefree += fs2h16(nep->e2d_reclen) - dsize;
        !           842:                loc += fs2h16(nep->e2d_reclen);
        !           843:                memcpy((caddr_t)ep, (caddr_t)nep, dsize);
        !           844:        }
        !           845:        /*
        !           846:         * Update the pointer fields in the previous entry (if any),
        !           847:         * copy in the new entry, and write out the block.
        !           848:         */
        !           849:        if (ep->e2d_ino == 0) {
        !           850: #ifdef DIAGNOSTIC
        !           851:                if (spacefree + dsize < newentrysize)
        !           852:                        panic("ext2fs_direnter: compact1");
        !           853: #endif
        !           854:                newdir.e2d_reclen = h2fs16(spacefree + dsize);
        !           855:        } else {
        !           856: #ifdef DIAGNOSTIC
        !           857:                if (spacefree < newentrysize) {
        !           858:                        printf("ext2fs_direnter: compact2 %u %u",
        !           859:                            (u_int)spacefree, (u_int)newentrysize);
        !           860:                        panic("ext2fs_direnter: compact2");
        !           861:                }
        !           862: #endif
        !           863:                newdir.e2d_reclen = h2fs16(spacefree);
        !           864:                ep->e2d_reclen = h2fs16(dsize);
        !           865:                ep = (struct ext2fs_direct *)((char *)ep + dsize);
        !           866:        }
        !           867:        memcpy((caddr_t)ep, (caddr_t)&newdir, (u_int)newentrysize);
        !           868:        error = VOP_BWRITE(bp);
        !           869:        dp->i_flag |= IN_CHANGE | IN_UPDATE;
        !           870:        if (!error && dp->i_endoff && dp->i_endoff < ext2fs_size(dp))
        !           871:                error = ext2fs_truncate(dp, (off_t)dp->i_endoff, IO_SYNC,
        !           872:                    cnp->cn_cred);
        !           873:        return (error);
        !           874: }
        !           875:
        !           876: /*
        !           877:  * Remove a directory entry after a call to namei, using
        !           878:  * the parameters which it left in nameidata. The entry
        !           879:  * dp->i_offset contains the offset into the directory of the
        !           880:  * entry to be eliminated.  The dp->i_count field contains the
        !           881:  * size of the previous record in the directory.  If this
        !           882:  * is 0, the first entry is being deleted, so we need only
        !           883:  * zero the inode number to mark the entry as free.  If the
        !           884:  * entry is not the first in the directory, we must reclaim
        !           885:  * the space of the now empty record by adding the record size
        !           886:  * to the size of the previous entry.
        !           887:  */
        !           888: int
        !           889: ext2fs_dirremove(struct vnode *dvp, struct componentname *cnp)
        !           890: {
        !           891:        struct inode *dp;
        !           892:        struct ext2fs_direct *ep;
        !           893:        struct buf *bp;
        !           894:        int error;
        !           895:
        !           896:        dp = VTOI(dvp);
        !           897:        if (dp->i_count == 0) {
        !           898:                /*
        !           899:                 * First entry in block: set d_ino to zero.
        !           900:                 */
        !           901:                error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, (char **)&ep,
        !           902:                    &bp);
        !           903:                if (error != 0)
        !           904:                        return (error);
        !           905:                ep->e2d_ino = 0;
        !           906:                error = VOP_BWRITE(bp);
        !           907:                dp->i_flag |= IN_CHANGE | IN_UPDATE;
        !           908:                return (error);
        !           909:        }
        !           910:        /*
        !           911:         * Collapse new free space into previous entry.
        !           912:         */
        !           913:        error = ext2fs_bufatoff(dp, (off_t)(dp->i_offset - dp->i_count),
        !           914:            (char **)&ep, &bp);
        !           915:        if (error != 0)
        !           916:                return (error);
        !           917:        ep->e2d_reclen = h2fs16(fs2h16(ep->e2d_reclen) + dp->i_reclen);
        !           918:        error = VOP_BWRITE(bp);
        !           919:        dp->i_flag |= IN_CHANGE | IN_UPDATE;
        !           920:        return (error);
        !           921: }
        !           922:
        !           923: /*
        !           924:  * Rewrite an existing directory entry to point at the inode
        !           925:  * supplied.  The parameters describing the directory entry are
        !           926:  * set up by a call to namei.
        !           927:  */
        !           928: int
        !           929: ext2fs_dirrewrite(struct inode *dp, struct inode *ip,
        !           930:     struct componentname *cnp)
        !           931: {
        !           932:        struct buf *bp;
        !           933:        struct ext2fs_direct *ep;
        !           934:        int error;
        !           935:
        !           936:        error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, (char **)&ep, &bp);
        !           937:        if (error != 0)
        !           938:                return (error);
        !           939:        ep->e2d_ino = h2fs32(ip->i_number);
        !           940:        if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
        !           941:            (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
        !           942:                ep->e2d_type = inot2ext2dt(IFTODT(ip->i_e2fs_mode));
        !           943:        } else {
        !           944:                ep->e2d_type = 0;
        !           945:        }
        !           946:        error = VOP_BWRITE(bp);
        !           947:        dp->i_flag |= IN_CHANGE | IN_UPDATE;
        !           948:        return (error);
        !           949: }
        !           950:
        !           951: /*
        !           952:  * Check if a directory is empty or not.
        !           953:  * Inode supplied must be locked.
        !           954:  *
        !           955:  * Using a struct dirtemplate here is not precisely
        !           956:  * what we want, but better than using a struct ext2fs_direct.
        !           957:  *
        !           958:  * NB: does not handle corrupted directories.
        !           959:  */
        !           960: int
        !           961: ext2fs_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred)
        !           962: {
        !           963:        off_t off;
        !           964:        struct ext2fs_dirtemplate dbuf;
        !           965:        struct ext2fs_direct *dp = (struct ext2fs_direct *)&dbuf;
        !           966:        int error, namlen;
        !           967:        size_t count;
        !           968:
        !           969: #define        MINDIRSIZ (sizeof (struct ext2fs_dirtemplate) / 2)
        !           970:
        !           971:        for (off = 0; off < ext2fs_size(ip); off += fs2h16(dp->e2d_reclen)) {
        !           972:                error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off,
        !           973:                   UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0);
        !           974:                /*
        !           975:                 * Since we read MINDIRSIZ, residual must
        !           976:                 * be 0 unless we're at end of file.
        !           977:                 */
        !           978:                if (error || count != 0)
        !           979:                        return (0);
        !           980:                /* avoid infinite loops */
        !           981:                if (dp->e2d_reclen == 0)
        !           982:                        return (0);
        !           983:                /* skip empty entries */
        !           984:                if (dp->e2d_ino == 0)
        !           985:                        continue;
        !           986:                /* accept only "." and ".." */
        !           987:                namlen = dp->e2d_namlen;
        !           988:                if (namlen > 2)
        !           989:                        return (0);
        !           990:                if (dp->e2d_name[0] != '.')
        !           991:                        return (0);
        !           992:                /*
        !           993:                 * At this point namlen must be 1 or 2.
        !           994:                 * 1 implies ".", 2 implies ".." if second
        !           995:                 * char is also "."
        !           996:                 */
        !           997:                if (namlen == 1)
        !           998:                        continue;
        !           999:                if (dp->e2d_name[1] == '.' && fs2h32(dp->e2d_ino) == parentino)
        !          1000:                        continue;
        !          1001:                return (0);
        !          1002:        }
        !          1003:        return (1);
        !          1004: }
        !          1005:
        !          1006: /*
        !          1007:  * Check if source directory is in the path of the target directory.
        !          1008:  * Target is supplied locked, source is unlocked.
        !          1009:  * The target is always vput before returning.
        !          1010:  */
        !          1011: int
        !          1012: ext2fs_checkpath(struct inode *source, struct inode *target,
        !          1013:    struct ucred *cred)
        !          1014: {
        !          1015:        struct vnode *vp;
        !          1016:        int error, rootino, namlen;
        !          1017:        struct ext2fs_dirtemplate dirbuf;
        !          1018:        u_int32_t ino;
        !          1019:
        !          1020:        vp = ITOV(target);
        !          1021:        if (target->i_number == source->i_number) {
        !          1022:                error = EEXIST;
        !          1023:                goto out;
        !          1024:        }
        !          1025:        rootino = ROOTINO;
        !          1026:        error = 0;
        !          1027:        if (target->i_number == rootino)
        !          1028:                goto out;
        !          1029:
        !          1030:        for (;;) {
        !          1031:                if (vp->v_type != VDIR) {
        !          1032:                        error = ENOTDIR;
        !          1033:                        break;
        !          1034:                }
        !          1035:                error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
        !          1036:                        sizeof (struct ext2fs_dirtemplate), (off_t)0,
        !          1037:                        UIO_SYSSPACE, IO_NODELOCKED, cred, (size_t *)0,
        !          1038:                        (struct proc *)0);
        !          1039:                if (error != 0)
        !          1040:                        break;
        !          1041:                namlen = dirbuf.dotdot_namlen;
        !          1042:                if (namlen != 2 ||
        !          1043:                        dirbuf.dotdot_name[0] != '.' ||
        !          1044:                        dirbuf.dotdot_name[1] != '.') {
        !          1045:                        error = ENOTDIR;
        !          1046:                        break;
        !          1047:                }
        !          1048:                ino = fs2h32(dirbuf.dotdot_ino);
        !          1049:                if (ino == source->i_number) {
        !          1050:                        error = EINVAL;
        !          1051:                        break;
        !          1052:                }
        !          1053:                if (ino == rootino)
        !          1054:                        break;
        !          1055:                vput(vp);
        !          1056:                error = VFS_VGET(vp->v_mount, ino, &vp);
        !          1057:                if (error != 0) {
        !          1058:                        vp = NULL;
        !          1059:                        break;
        !          1060:                }
        !          1061:        }
        !          1062:
        !          1063: out:
        !          1064:        if (error == ENOTDIR) {
        !          1065:                printf("checkpath: .. not a directory\n");
        !          1066:                panic("checkpath");
        !          1067:        }
        !          1068:        if (vp != NULL)
        !          1069:                vput(vp);
        !          1070:        return (error);
        !          1071: }

CVSweb