[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

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